Resolve endpoint-local object dependencies

This commit is contained in:
Lyncoln
2026-09-19 21:34:23 -04:00
parent dc6505d165
commit 8caac79a1e
8 changed files with 1174 additions and 42 deletions
+116
View File
@@ -5,10 +5,12 @@ from datetime import datetime, timezone
from dns_sync.adapters import (
CERTIFICATES,
DNS_RECORDS,
PROXY_HOSTS,
Capability,
CapabilityOperation,
Endpoint,
NormalizedObject,
ObjectReference,
Observation,
PlanOperation,
)
@@ -173,6 +175,120 @@ class EndpointPlanningTests(unittest.TestCase):
self.assertNotIn("app.example.com", planned_keys)
self.assertNotIn("unmanaged.example.com", planned_keys)
def test_plan_orders_referenced_object_before_dependent(self):
endpoint = Endpoint("generic", "node.example:443")
generic_adapter = FakeAdapter(
endpoint=endpoint,
capabilities=frozenset(
{
Capability(
CERTIFICATES,
CapabilityOperation.APPLY,
),
Capability(
PROXY_HOSTS,
CapabilityOperation.APPLY,
),
}
),
)
certificate = NormalizedObject(
object_type=CERTIFICATES,
logical_key="app.example.com",
payload={
"domain_names": ["app.example.com"],
},
)
proxy_host = NormalizedObject(
object_type=PROXY_HOSTS,
logical_key="app.example.com",
payload={
"domain_names": ["app.example.com"],
"forward_scheme": "http",
"forward_host": "192.168.1.50",
"forward_port": 8080,
"enabled": True,
},
references=(
ObjectReference(
relation="certificate",
object_type=CERTIFICATES,
logical_key="app.example.com",
),
),
)
plans = build_endpoint_plans(
[generic_adapter],
[
proxy_host,
certificate,
],
[],
)
self.assertEqual(len(plans), 1)
self.assertEqual(
tuple(
action.desired.object_type
for action in plans[0].actions
),
(
CERTIFICATES,
PROXY_HOSTS,
),
)
def test_plan_dependency_cycle_fails_before_plan_is_returned(self):
endpoint = Endpoint("generic", "node.example:443")
object_a = "object_a"
object_b = "object_b"
generic_adapter = adapter(
"generic",
"node.example:443",
object_a,
object_b,
)
first = NormalizedObject(
object_type=object_a,
logical_key="a",
payload={},
references=(
ObjectReference(
relation="b",
object_type=object_b,
logical_key="b",
),
),
)
second = NormalizedObject(
object_type=object_b,
logical_key="b",
payload={},
references=(
ObjectReference(
relation="a",
object_type=object_a,
logical_key="a",
),
),
)
with self.assertRaisesRegex(
RuntimeError,
"dependency cycle",
):
build_endpoint_plans(
[generic_adapter],
[first, second],
[],
)
def test_duplicate_endpoint_objects_fail_without_payload_output(self):
desired = [
dns_object("app.example.com", "192.168.1.101")