Usage#
This module is designed to be used as a dxaws primitive: you provide a
DnsRecordDesired and the DnsManager converges Route 53 to match.
The most common call pattern is:
- Construct a
DnsManager - Provide a
DnsRecordDesired - Call
mgr.execute(desired)
Basic Example: Create / Update / Delete#
from dxaws_dns.manager import DnsManager
from dxaws_dns.models import DnsRecordDesired
# AWS Route53 is the default provider
mgr = DnsManager()
# Create or update a TXT record
present = DnsRecordDesired(
zone_name="dev.dxaws.com",
record_name="_demo",
record_type="TXT",
ttl=60,
values=["hello from dxaws"],
state="present",
)
result = mgr.execute(present)
print(result.outcome) # "applied" or "noop"
# Delete the record
absent = DnsRecordDesired(
zone_name="dev.dxaws.com",
record_name="_demo",
record_type="TXT",
state="absent",
)
result2 = mgr.execute(absent)
print(result2.outcome) # "applied" or "noop"Notes:
zone_nameis the human-facing identifier and is always required.zone_idis optional; the manager can resolve it via the provider.- TXT values may be provided unquoted. The provider/manager normalize quoting to match Route 53 behavior.
Overriding the Provider#
Most callers should use DnsManager() directly and treat providers as an
internal implementation detail. The manager defaults to the AWS Route53
provider.
Providers exist primarily for dependency injection (testing, alternate backends, recording providers, etc.). If you need to override the provider explicitly you can:
from dxaws_core import AwsSession
from dxaws_dns.manager import DnsManager
from dxaws_dns.providers.aws import Route53Provider
aws = AwsSession(region_name="ca-central-1")
provider = Route53Provider(aws=aws)
mgr = DnsManager(provider=provider)Application and composition code should normally interact only with the manager surface. If functionality from a provider is needed, it should be exposed through the manager interface rather than accessed directly.
Idempotency#
Declarative convergence means you can run the same desired state repeatedly:
result1 = mgr.execute(present)
result2 = mgr.execute(present)
assert result2.outcome == "noop"If AWS drifts (or you change inputs like TTL), the next run will return
"applied" and re-stabilize.
Record Types#
The acceptance harness currently validates these record types:
TXTACNAME
Example A record:
present_a = DnsRecordDesired(
zone_name="dev.dxaws.com",
record_name="_demo-a",
record_type="A",
ttl=60,
values=["203.0.113.10"],
state="present",
)
mgr.execute(present_a)Example CNAME record:
present_cname = DnsRecordDesired(
zone_name="dev.dxaws.com",
record_name="_demo-cname",
record_type="CNAME",
ttl=60,
values=["example.com."],
state="present",
)
mgr.execute(present_cname)Running Acceptance Tests Safely#
Acceptance tests mutate real AWS resources and are treated as contract tests.
They are guarded by:
- Opt-in:
DXAWS_AWS_TESTS=1 - Explicit confirmation:
DXAWS_ACCEPTANCE_CONFIRMmust equal the zone name - AWS identity printed before mutation
Make target#
make accept-dns ZONE=dev.dxaws.comThis target sets:
DXAWS_AWS_TESTS=1DXAWS_ACCEPTANCE_ZONE_NAME=$(ZONE)DXAWS_ACCEPTANCE_CONFIRM=$(ZONE)
The test creates and deletes temporary TXT/A/CNAME records and verifies:
- Create/read/delete lifecycle
- Idempotency (
noopon second apply) - TTL drift detection + correction
Troubleshooting#
“Value should be enclosed in quotation marks”#
Route 53 expects TXT values to be quoted. This module normalizes TXT values,
so you should be able to pass unquoted strings in values=[...].
If you see this error, verify you are using Route53Provider from this module
and that your running code includes the TXT normalization changes.
“Refusing to run acceptance test…”#
Set:
DXAWS_ACCEPTANCE_ZONE_NAME=<zone>DXAWS_ACCEPTANCE_CONFIRM=<zone>
…and run again.