Zone
- exception octodns.zone.SubzoneRecordException(msg, record)[source]
Bases:
ExceptionException raised when a record belongs in a sub-zone but is added to the parent.
This exception is raised when attempting to add a record to a zone that should actually be managed in a configured sub-zone. Only NS and DS records are allowed at the sub-zone boundary.
- Parameters:
record (octodns.record.base.Record) – The record that caused the exception.
- exception octodns.zone.DuplicateRecordException(msg, existing, new)[source]
Bases:
ExceptionException raised when attempting to add a duplicate record to a zone.
A duplicate is defined as a record with the same name and type as an existing record in the zone. The exception includes references to both the existing and new records for debugging.
- Parameters:
existing (octodns.record.base.Record) – The existing record in the zone.
new (octodns.record.base.Record) – The new record being added.
- exception octodns.zone.InvalidNodeException(msg, record)[source]
Bases:
ExceptionException raised when CNAME records coexist with other records at a node.
Per DNS standards, CNAME records cannot coexist with other record types at the same node. This exception is raised when such an invalid configuration is detected.
- Parameters:
record (octodns.record.base.Record) – The record that caused the exception.
- exception octodns.zone.InvalidNameError[source]
Bases:
ExceptionException raised when a zone name is invalid.
Zone names must: - End with a dot (.) - Not contain double dots (..) - Not contain whitespace
- class octodns.zone.Zone(name, sub_zones, update_pcent_threshold=None, delete_pcent_threshold=None, ignore_subzone_adds=False)[source]
Bases:
objectContainer for DNS records belonging to a single DNS zone.
A Zone represents a DNS zone and manages all the records within it. It provides methods for adding, removing, and querying records, as well as computing changes between zones and applying those changes.
Zones support copy-on-write semantics via the
copy()method, which creates shallow copies that are hydrated on first modification. This allows for efficient processing of zones through multiple stages without unnecessary copying.Key features:
Record management: Add, remove, and query DNS records
Validation: Enforce DNS standards (CNAME restrictions, sub-zone rules)
IDNA support: Handle internationalized domain names
Sub-zone awareness: Respect configured sub-zone boundaries
Change tracking: Compute differences between desired and existing state
Copy-on-write: Efficient shallow copying with lazy hydration
Example usage:
from octodns.zone import Zone from octodns.record import Record zone = Zone('example.com.', []) record = Record.new(zone, 'www', {'type': 'A', 'ttl': 300, 'value': '1.2.3.4'}) zone.add_record(record) # Create a shallow copy copy = zone.copy() # Modifications to copy don't affect the original until hydrated
See also
Zone Lifecycle During Sync for details on zone processing workflow
- log = <Logger Zone (WARNING)>
- REFERENCES = ('https://datatracker.ietf.org/doc/html/rfc1034', 'https://datatracker.ietf.org/doc/html/rfc1035', 'https://datatracker.ietf.org/doc/html/rfc2181', 'https://datatracker.ietf.org/doc/html/rfc4592')
- __init__(name, sub_zones, update_pcent_threshold=None, delete_pcent_threshold=None, ignore_subzone_adds=False)[source]
Initialize a DNS zone.
- Parameters:
name (str) – The zone name (must end with a dot). Internationalized domain names (IDN) are automatically encoded to IDNA format.
sub_zones (list[str]) – List of sub-zone names managed separately. Records belonging to sub-zones will be rejected (except NS/DS at the boundary).
update_pcent_threshold (float or None) – Override for maximum update percentage threshold. If None, uses provider default.
delete_pcent_threshold (float or None) – Override for maximum delete percentage threshold. If None, uses provider default.
ignore_subzone_adds (bool) – If True, silently drop records that belong under a configured sub-zone instead of raising. Useful when a source returns records that overlap a configured sub-zone. Records explicitly marked
lenient=Truekeep their existing warn-and-add behavior.
- Raises:
InvalidNameError – If the zone name is invalid (missing trailing dot, contains double dots, or has whitespace).
Important
Zone names must end with a dot (.)
Zone names are automatically encoded to IDNA format internally
Sub-zones prevent records from being added to the parent zone
- property records
Get all records in this zone.
Returns a set of all DNS records in the zone. If this is a shallow copy (not yet hydrated), returns records from the origin zone.
- Returns:
Set of all records in the zone.
- Return type:
- property root_ns
Get the root NS record for this zone.
The root NS record is the NS record at the zone apex (empty hostname). Returns None if no root NS record exists.
- Returns:
The root NS record, or None if not present.
- Return type:
octodns.record.ns.NsRecord or None
- hostname_from_fqdn(fqdn)[source]
Extract the hostname portion from a fully qualified domain name.
Strips the zone name from the FQDN to get just the hostname portion. Handles both IDNA-encoded and UTF-8 domain names correctly.
- Parameters:
fqdn (str) – Fully qualified domain name.
- Returns:
The hostname portion (without the zone name).
- Return type:
Example:
zone = Zone('example.com.', []) zone.hostname_from_fqdn('www.example.com.') # Returns 'www' zone.hostname_from_fqdn('example.com.') # Returns ''
- owns(_type, fqdn)[source]
Determine if this zone owns a given FQDN for a specific record type.
Checks whether a record with the given FQDN and type should be managed by this zone, taking into account sub-zone boundaries. Records under sub-zones are not owned by the parent (except NS records at the exact sub-zone boundary).
- Parameters:
- Returns:
True if this zone owns the FQDN for this type, False otherwise.
- Return type:
Important
NS records at sub-zone boundaries are owned by the parent zone
All other records under sub-zones are not owned by the parent
FQDNs are automatically normalized (trailing dot added if missing)
- add_record(record, replace=False, lenient=False)[source]
Add a DNS record to this zone.
Adds the provided record to the zone with validation. If this is a shallow copy (has an origin), it will be hydrated before adding.
- Parameters:
record (octodns.record.base.Record) – The DNS record to add to the zone.
replace (bool) – If True, replace any existing record with the same name and type. If False, raise an exception if a duplicate exists.
lenient (bool) – If True, skip some validation checks (sub-zone checks, CNAME coexistence checks). Useful when loading existing data that may not be standards-compliant.
- Raises:
SubzoneRecordException – If the record belongs in a configured sub-zone (unless it’s an NS/DS record at the boundary).
DuplicateRecordException – If a record with the same name and type already exists and
replace=False.InvalidNodeException – If adding the record would create an invalid CNAME coexistence situation.
Important
Automatically hydrates shallow copies on first modification
NS/DS records are allowed at sub-zone boundaries
CNAME records cannot coexist with other records at the same node
Use
replace=Trueto update existing recordsUse
lenient=Truewhen loading potentially non-compliant data
- remove_record(record)[source]
Remove a DNS record from this zone.
Removes the provided record from the zone. If this is a shallow copy (has an origin), it will be hydrated before removing.
- Parameters:
record (octodns.record.base.Record) – The DNS record to remove from the zone.
Important
Automatically hydrates shallow copies on first modification
Clearing the root NS record (empty name) also clears the cached
root_nspropertySilently succeeds if the record doesn’t exist in the zone
- changes(desired, target)[source]
Compute the changes needed to transform this zone into the desired state.
Compares this zone (existing state) with the desired zone and returns a list of changes (Creates, Updates, Deletes) required to make this zone match the desired state. Respects record-level include/exclude filtering and provider support.
- Parameters:
desired (Zone) – The desired zone state to compare against.
target (octodns.provider.base.BaseProvider) – The target provider that will apply these changes. Used to check record support and apply include/exclude rules.
- Returns:
List of changes needed to transform this zone to the desired state.
- Return type:
Important
Skips records marked as
ignoredRespects record-level
includedandexcludedlistsOnly includes changes for record types the target supports
Returns Creates, Updates (via record.changes), and Deletes
- apply(changes)[source]
Apply a list of changes to this zone.
Applies the provided changes by adding new/updated records and removing deleted records. Uses
replace=Trueandlenient=Trueto handle updates and non-standard records gracefully.- Parameters:
changes (list[octodns.record.change.Change]) – List of changes to apply to the zone.
Important
Delete changes remove the existing record
Create and Update changes add the new record with
replace=TrueAll adds use
lenient=Trueto skip validationChanges are applied in the order provided
- hydrate()[source]
Convert a shallow copy into a hydrated copy with its own record references.
Hydration copies all records from the origin zone into this zone, making it independent. The records themselves are still the original objects and should not be modified directly. Use
add_record()withreplace=Trueorremove_record()to make changes.- Returns:
True if hydration occurred, False if already hydrated.
- Return type:
Note
This method is automatically called by
add_record()andremove_record()when needed, so manual calls are rarely necessary.Important
Only hydrates if this is a shallow copy (has an
_origin)Clears the
_originreference after hydrationUses
lenient=Truewhen adding records from originRecords are still shared with the origin (not deep copied)
- copy()[source]
Create a shallow copy of this zone using copy-on-write semantics.
Creates a new zone that shares records with this zone until the copy is modified. When
add_record()orremove_record()is called on the copy, it will be automatically hydrated with its own record references.- Returns:
A shallow copy of this zone.
- Return type:
Important
The copy shares records with the original until hydrated
Hydration happens automatically on first modification
Records in the hydrated copy are still the same objects (not deep copied)
Modifying records directly affects both zones; use
record.copy()andadd_record(..., replace=True)instead
Example:
original = Zone('example.com.', []) # ... add records to original ... copy = original.copy() # Shallow copy, shares records # No copying has occurred yet copy.add_record(new_record) # Triggers hydration, copies record refs # Now copy has its own record references