Attach generic references to normalized objects
This commit is contained in:
@@ -110,11 +110,35 @@ class ObjectReference:
|
|||||||
object.__setattr__(self, "logical_key", logical_key)
|
object.__setattr__(self, "logical_key", logical_key)
|
||||||
|
|
||||||
|
|
||||||
|
def _normalized_references(
|
||||||
|
references,
|
||||||
|
) -> tuple[ObjectReference, ...]:
|
||||||
|
normalized = tuple(references)
|
||||||
|
if any(
|
||||||
|
not isinstance(reference, ObjectReference)
|
||||||
|
for reference in normalized
|
||||||
|
):
|
||||||
|
raise ValueError(
|
||||||
|
"Object references must be ObjectReference instances"
|
||||||
|
)
|
||||||
|
if len(set(normalized)) != len(normalized):
|
||||||
|
raise ValueError("Object references cannot contain duplicates")
|
||||||
|
return normalized
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class DiscoveredObject:
|
class DiscoveredObject:
|
||||||
object_type: str
|
object_type: str
|
||||||
local_key: str
|
local_key: str
|
||||||
payload: Mapping[str, Any]
|
payload: Mapping[str, Any]
|
||||||
|
references: tuple[ObjectReference, ...] = ()
|
||||||
|
|
||||||
|
def __post_init__(self) -> None:
|
||||||
|
object.__setattr__(
|
||||||
|
self,
|
||||||
|
"references",
|
||||||
|
_normalized_references(self.references),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@@ -123,6 +147,14 @@ class NormalizedObject:
|
|||||||
logical_key: str
|
logical_key: str
|
||||||
payload: Mapping[str, Any]
|
payload: Mapping[str, Any]
|
||||||
local_key: str | None = None
|
local_key: str | None = None
|
||||||
|
references: tuple[ObjectReference, ...] = ()
|
||||||
|
|
||||||
|
def __post_init__(self) -> None:
|
||||||
|
object.__setattr__(
|
||||||
|
self,
|
||||||
|
"references",
|
||||||
|
_normalized_references(self.references),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ def _normalize_dns_record(
|
|||||||
logical_key=hostname,
|
logical_key=hostname,
|
||||||
local_key=discovered.local_key,
|
local_key=discovered.local_key,
|
||||||
payload=normalized_payload,
|
payload=normalized_payload,
|
||||||
|
references=discovered.references,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -146,6 +147,7 @@ def _normalize_proxy_host(
|
|||||||
logical_key=",".join(domains),
|
logical_key=",".join(domains),
|
||||||
local_key=discovered.local_key,
|
local_key=discovered.local_key,
|
||||||
payload=normalized_payload,
|
payload=normalized_payload,
|
||||||
|
references=discovered.references,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -175,6 +177,7 @@ def _normalize_certificate(
|
|||||||
logical_key=identity.key,
|
logical_key=identity.key,
|
||||||
local_key=discovered.local_key,
|
local_key=discovered.local_key,
|
||||||
payload=normalized_payload,
|
payload=normalized_payload,
|
||||||
|
references=discovered.references,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
from dns_sync.adapters import (
|
||||||
|
CERTIFICATES,
|
||||||
|
PROXY_HOSTS,
|
||||||
|
DiscoveredObject,
|
||||||
|
ObjectReference,
|
||||||
|
)
|
||||||
|
from dns_sync.object_normalizer import normalize_discovered_object
|
||||||
|
|
||||||
|
|
||||||
|
class ReferenceNormalizationTests(unittest.TestCase):
|
||||||
|
def test_adapter_reference_survives_central_normalization(self):
|
||||||
|
certificate = ObjectReference(
|
||||||
|
relation="certificate",
|
||||||
|
object_type=CERTIFICATES,
|
||||||
|
local_key="67",
|
||||||
|
)
|
||||||
|
discovered = DiscoveredObject(
|
||||||
|
object_type=PROXY_HOSTS,
|
||||||
|
local_key="12",
|
||||||
|
payload={
|
||||||
|
"domain_names": ["app.example.com"],
|
||||||
|
"forward_scheme": "http",
|
||||||
|
"forward_host": "192.168.1.20",
|
||||||
|
"forward_port": 8080,
|
||||||
|
"enabled": True,
|
||||||
|
},
|
||||||
|
references=[certificate],
|
||||||
|
)
|
||||||
|
|
||||||
|
normalized = normalize_discovered_object(discovered)
|
||||||
|
|
||||||
|
self.assertIsInstance(discovered.references, tuple)
|
||||||
|
self.assertEqual(normalized.references, (certificate,))
|
||||||
|
self.assertEqual(
|
||||||
|
normalized.references[0].local_key,
|
||||||
|
"67",
|
||||||
|
)
|
||||||
|
self.assertIsNone(
|
||||||
|
normalized.references[0].logical_key,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_duplicate_references_are_rejected(self):
|
||||||
|
certificate = ObjectReference(
|
||||||
|
relation="certificate",
|
||||||
|
object_type=CERTIFICATES,
|
||||||
|
local_key="67",
|
||||||
|
)
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
ValueError,
|
||||||
|
"cannot contain duplicates",
|
||||||
|
):
|
||||||
|
DiscoveredObject(
|
||||||
|
object_type=PROXY_HOSTS,
|
||||||
|
local_key="12",
|
||||||
|
payload={},
|
||||||
|
references=(certificate, certificate),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_non_reference_values_are_rejected(self):
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
ValueError,
|
||||||
|
"ObjectReference instances",
|
||||||
|
):
|
||||||
|
DiscoveredObject(
|
||||||
|
object_type=PROXY_HOSTS,
|
||||||
|
local_key="12",
|
||||||
|
payload={},
|
||||||
|
references=("certificate:67",),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user