#
#
#
[docs]
class ProcessorException(Exception):
'''
Exception raised when a processor encounters an error during processing.
A subclass of this exception can be raised by processors when they
encounter invalid configurations, unsupported operations, or other
processing errors.
'''
pass
[docs]
class BaseProcessor(object):
'''
Base class for all octoDNS processors.
Processors provide hooks into the octoDNS sync process to modify zones and
records at various stages. They can be used to filter, transform, or
validate DNS records before planning and applying changes.
Processors are executed in the order they are configured and can modify:
- **Source zones** (after sources populate, before planning)
- **Target zones** (after target populates, before planning)
- **Source and target zones** (just before computing changes)
- **Plans** (after planning, before applying)
Subclasses should override one or more of the ``process_*`` methods to
implement custom processing logic.
Example usage::
processors:
my-processor:
class: my.custom.processor.MyProcessor
# processor-specific configuration
zones:
example.com.:
sources:
- config
processors:
- my-processor
targets:
- route53
See Also:
- :class:`octodns.processor.filter.TypeAllowlistFilter`
- :class:`octodns.processor.ownership.OwnershipProcessor`
- :class:`octodns.processor.acme.AcmeMangingProcessor`
'''
[docs]
def __init__(self, name, lenient=False):
'''
Initialize the processor.
:param name: Unique identifier for this processor instance. Used in
logging and configuration references.
:type name: str
:param lenient: When True, the processor will operate in lenient mode.
This value is combined with the per-call ``lenient``
parameter in ``process_*`` methods.
:type lenient: bool
.. note::
The ``name`` parameter is deprecated and will be removed in
version 2.0. Use ``id`` instead.
'''
# TODO: name is DEPRECATED, remove in 2.0
self.id = self.name = name
self.lenient = lenient
[docs]
def process_source_zone(self, desired, sources, lenient=False):
'''
Process the desired zone after all sources have populated.
Called after all sources have completed populate. Provides an
opportunity for the processor to modify the desired zone that targets
will receive.
:param desired: The desired zone state after all sources have populated.
This zone will be used as the target state for planning.
:type desired: octodns.zone.Zone
:param sources: List of source providers that populated the zone. May be
empty for aliased zones.
:type sources: list[octodns.provider.base.BaseProvider]
:param lenient: When True, relaxed validation rules should be applied
when modifying zone records.
:type lenient: bool
:return: The modified desired zone, typically the same object passed in.
:rtype: octodns.zone.Zone
.. important::
- Will see ``desired`` after any modifications done by
``Provider._process_desired_zone`` and processors configured to run
before this one.
- May modify ``desired`` directly.
- Must return ``desired`` which will normally be the ``desired`` param.
- Must not modify records directly; ``record.copy`` should be called,
the results of which can be modified, and then ``Zone.add_record``
may be used with ``replace=True``.
- May call ``Zone.remove_record`` to remove records from ``desired``.
- Sources may be empty, as will be the case for aliased zones.
- Implementations should combine ``self.lenient or lenient`` and pass
the result to any record and zone calls that accept ``lenient`` as
a parameter, e.g. ``zone.add_record(..., lenient=lenient)``.
'''
return desired
[docs]
def process_target_zone(self, existing, target, lenient=False):
'''
Process the existing zone after the target has populated.
Called after a target has completed ``populate``, before changes are
computed between ``existing`` and ``desired``. This provides an
opportunity to modify the existing zone state.
:param existing: The current zone state from the target provider.
:type existing: octodns.zone.Zone
:param target: The target provider that populated the existing zone.
:type target: octodns.provider.base.BaseProvider
:param lenient: When True, relaxed validation rules should be applied
when modifying zone records.
:type lenient: bool
:return: The modified existing zone, typically the same object passed in.
:rtype: octodns.zone.Zone
.. important::
- Will see ``existing`` after any modifications done by processors
configured to run before this one.
- May modify ``existing`` directly.
- Must return ``existing`` which will normally be the ``existing`` param.
- Must not modify records directly; ``record.copy`` should be called,
the results of which can be modified, and then ``Zone.add_record``
may be used with ``replace=True``.
- May call ``Zone.remove_record`` to remove records from ``existing``.
- Implementations should combine ``self.lenient or lenient`` and pass
the result to any record and zone calls that accept ``lenient`` as
a parameter, e.g. ``zone.add_record(..., lenient=lenient)``.
'''
return existing
[docs]
def process_source_and_target_zones(
self, desired, existing, target, lenient=False
):
'''
Process both desired and existing zones before computing changes.
Called just prior to computing changes for the target provider between
``desired`` and ``existing``. Provides an opportunity for the processor
to modify either or both zones that will be used to compute the changes
and create the initial plan.
:param desired: The desired zone state after all source processing.
:type desired: octodns.zone.Zone
:param existing: The existing zone state after all target processing.
:type existing: octodns.zone.Zone
:param target: The target provider for which changes will be computed.
:type target: octodns.provider.base.BaseProvider
:param lenient: When True, relaxed validation rules should be applied
when modifying zone records.
:type lenient: bool
:return: A tuple of (desired, existing) zones, typically the same
objects passed in.
:rtype: tuple[octodns.zone.Zone, octodns.zone.Zone]
.. important::
- Will see ``desired`` after any modifications done by
``Provider._process_desired_zone`` and all processors via
``Processor.process_source_zone``.
- Will see ``existing`` after any modifications done by all processors
via ``Processor.process_target_zone``.
- Will see both ``desired`` and ``existing`` after any modifications
done by any processors configured to run before this one via
``Processor.process_source_and_target_zones``.
- May modify ``desired`` directly.
- Must return ``desired`` which will normally be the ``desired`` param.
- May modify ``existing`` directly.
- Must return ``existing`` which will normally be the ``existing``
param.
- Must not modify records directly; ``record.copy`` should be called,
the results of which can be modified, and then ``Zone.add_record``
may be used with ``replace=True``.
- May call ``Zone.remove_record`` to remove records from ``desired``.
- May call ``Zone.remove_record`` to remove records from ``existing``.
- Implementations should combine ``self.lenient or lenient`` and pass
the result to any record and zone calls that accept ``lenient`` as
a parameter, e.g. ``zone.add_record(..., lenient=lenient)``.
'''
return desired, existing
[docs]
def process_plan(self, plan, sources, target, lenient=False):
'''
Process the plan after it has been computed.
Called after the planning phase has completed. Provides an opportunity
for the processor to modify the plan, thus changing the actions that
will be displayed and potentially applied.
:param plan: The computed plan containing the changes to be applied.
May be None if no changes were detected.
:type plan: octodns.provider.plan.Plan or None
:param sources: List of source providers for this zone. May be empty
for aliased zones.
:type sources: list[octodns.provider.base.BaseProvider]
:param target: The target provider for which the plan was created.
:type target: octodns.provider.base.BaseProvider
:param lenient: When True, relaxed validation rules should be applied
when modifying zone records.
:type lenient: bool
:return: The modified plan, which may be the same object passed in,
a newly created Plan, or None if no changes are needed.
:rtype: octodns.provider.plan.Plan or None
.. important::
- ``plan`` may be None if no changes were detected; if so, a ``Plan``
may still be created and returned.
- May modify ``plan.changes`` directly or create a new ``Plan``.
- Does not have to modify ``plan.desired`` and/or ``plan.existing`` to
line up with any modifications made to ``plan.changes``.
- Should copy over ``plan.exists``, ``plan.update_pcent_threshold``,
and ``plan.delete_pcent_threshold`` when creating a new ``Plan``.
- Must return a ``Plan`` which may be ``plan`` or can be a newly
created one with ``plan.desired`` and ``plan.existing`` copied over
as-is or modified.
- Sources may be empty, as will be the case for aliased zones.
- Implementations should combine ``self.lenient or lenient`` and pass
the result to any record and zone calls that accept ``lenient`` as
a parameter, e.g. ``zone.add_record(..., lenient=lenient)``.
'''
# plan may be None if no changes were detected up until now, the
# process may still create a plan.
# sources may be empty, as will be the case for aliased zones
return plan