Compare commits

..

14 commits

Author SHA1 Message Date
1cbd26d4cb chore(deps): update dependency coverage to v7.4.3
All checks were successful
build and publish / update-changelog (pull_request) Successful in 5s
build and publish / release-pypackage (pull_request) Successful in 25s
check code / check-code (pull_request) Successful in 32s
2024-03-12 20:14:22 +01:00
10e842385c Merge pull request 'chore(deps): update dependency just to v1.25.2' (#3) from renovate/just-1.x into main
All checks were successful
check code / check-code (push) Successful in 29s
Reviewed-on: #3
2024-03-12 10:16:25 +01:00
4304729ba0 Merge pull request 'chore(deps): update dependency octodns to v1.6.0' (#15) from renovate/octodns-1.x into main
Some checks failed
check code / check-code (push) Has been cancelled
Reviewed-on: #15
2024-03-12 10:16:10 +01:00
b19a598c38 chore(deps): update dependency octodns to v1.6.0
All checks were successful
build and publish / update-changelog (pull_request) Successful in 7s
build and publish / release-pypackage (pull_request) Successful in 25s
check code / check-code (pull_request) Successful in 25s
2024-03-12 08:16:41 +01:00
dff84f48ab chore(deps): update dependency just to v1.25.2
All checks were successful
build and publish / release-pypackage (pull_request) Successful in 29s
build and publish / update-changelog (pull_request) Successful in 5s
check code / check-code (pull_request) Successful in 31s
2024-03-11 08:16:17 +01:00
ff955d8479 [bot] update changelog 2024-03-04 16:09:15 +00:00
ec27c03260 Bump version 0.3.4 → 0.3.5
All checks were successful
build and publish / update-changelog (push) Successful in 9s
check code / check-code (push) Successful in 28s
build and publish / release-pypackage (push) Successful in 48s
2024-03-04 17:08:41 +01:00
2e468c8569 fix tests
All checks were successful
check code / check-code (push) Successful in 34s
Signed-off-by: Ivan Schaller <ivan@schaller.sh>
2024-03-01 22:51:48 +01:00
8d29b5e639 revert: change from repr to string in changeset
Some checks failed
check code / check-code (push) Failing after 27s
Signed-off-by: Ivan Schaller <ivan@schaller.sh>
2024-03-01 22:49:17 +01:00
696d2a2532 change from repr to string in changeset
All checks were successful
check code / check-code (push) Successful in 30s
Signed-off-by: Ivan Schaller <ivan@schaller.sh>
2024-03-01 19:37:16 +01:00
4fe8be6291 unescape the changeset before comparison to live records to have an accurate changeset. fixes changes for txt records
All checks were successful
check code / check-code (push) Successful in 29s
2024-03-01 10:30:58 +01:00
78448d2bde only unescape txt and spf records
All checks were successful
check code / check-code (push) Successful in 30s
2024-02-29 22:17:45 +01:00
ff1a47cf8c update logging 2024-02-29 22:14:00 +01:00
91ba03af7f rollback changes to semicolon escaping
All checks were successful
check code / check-code (push) Successful in 27s
2024-02-29 21:45:03 +01:00
7 changed files with 86 additions and 61 deletions

View file

@ -1,2 +1,2 @@
just 1.16.0 just 1.25.2
lefthook 1.4.6 lefthook 1.4.6

View file

@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
## [v0.3.5](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/compare/v0.3.4...v0.3.5) - 2024-03-04
### Commits
- add new tests [`a8ecfab`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/a8ecfab93096cd3201efcb06a65bc86a2444611a)
- fix typo in method call and add function for semicolons [`afe1826`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/afe182628a7b2fc784dc48bebaf9978c85d682d2)
- update ci files for github [`6b06cad`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/6b06cada38751648b9365fd27b850aa2b6d250a8)
- unescape the changeset before comparison to live records to have an accurate changeset. fixes changes for txt records [`4fe8be6`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/4fe8be62918b5bea821f4f88a151918899b61e91)
- rollback changes to semicolon escaping [`91ba03a`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/91ba03af7f5f53a7f3b5218f0f4a905eebcdb914)
- revert: change from repr to string in changeset [`8d29b5e`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/8d29b5e639b25bb57b43e9e85bbe78e51d70b493)
- update logging [`ff1a47c`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/ff1a47cf8cda21695fb4e30910dd92d0f9cb8b63)
- update test cases [`f38a103`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/f38a1036b79b9779a8480c2d1f79132370b83bb4)
- change from repr to string in changeset [`696d2a2`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/696d2a2532eef05fee95cddff627c9b09736ae52)
- only unescape txt and spf records [`78448d2`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/78448d2bde85fda1718c64e6cd8983b4fcb20fe0)
- fix semicolon escaping [`6e624a7`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/6e624a79a75051295d1863f9af7e907d44a9b307)
- fix tests [`2e468c8`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/2e468c85699808ed9ba2edb35a6cc39591869346)
## [v0.3.4](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/compare/v0.3.3...v0.3.4) - 2024-02-29 ## [v0.3.4](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/compare/v0.3.3...v0.3.4) - 2024-02-29
### Commits ### Commits

View file

@ -1,10 +1,22 @@
--- ---
? '' ? ''
: ttl: 172800 : - ttl: 172800
type: NS type: NS
values: values:
- ns1.example.com. - ns1.example.com.
- ns3.example.com. - ns2.example.com.
- type: TXT
value: v=spf1 include:example.com -all
_ts3._udp:
type: SRV
value:
port: 9987
priority: 0
target: example.com.
weight: 5
abc:
type: CNAME
value: def.example.com.
ns1: ns1:
type: A type: A
value: 192.168.1.1 value: 192.168.1.1

View file

@ -50,7 +50,7 @@ python = "3.11"
dependencies = [ dependencies = [
"pytest==7.4.4", "pytest==7.4.4",
"coverage==7.4.3", "coverage==7.4.3",
"octodns==1.5.0", "octodns==1.6.0",
"octodns-spf==0.0.2", "octodns-spf==0.0.2",
] ]

View file

@ -1 +1 @@
__version__ = "0.3.4" __version__ = "0.3.5"

View file

@ -61,8 +61,8 @@ class NetBoxDNSProvider(octodns.provider.base.BaseProvider):
*args, *args,
**kwargs, **kwargs,
) -> None: ) -> None:
"""initialize the NetboxDNSSource""" """initialize the NetBoxDNSProvider"""
self.log = logging.getLogger(f"NetboxDNSSource[{id}]") self.log = logging.getLogger(f"NetBoxDNSProvider[{id}]")
self.log.debug( self.log.debug(
f"__init__: {id=}, {url=}, {view=}, {replace_duplicates=}, {make_absolute=}, {disable_ptr=}, {args=}, {kwargs=}" f"__init__: {id=}, {url=}, {view=}, {replace_duplicates=}, {make_absolute=}, {disable_ptr=}, {args=}, {kwargs=}"
) )
@ -90,21 +90,14 @@ class NetBoxDNSProvider(octodns.provider.base.BaseProvider):
return absolute_value return absolute_value
@staticmethod def _escape_semicolon(self, value: str) -> str:
def _fix_semicolon(value: str, escape: bool) -> str: fixed = value.replace(";", r"\;")
"""escape and un-escape semicolons in record values for netbox/octodns self.log.debug(rf"in='{value}', escaped='{fixed}'")
return fixed
@param value: the record value
@param escape: if set to true, all semicolons get escaped with a backslash.
if false it un-escapes all semicolons.
@return: the modified record value
"""
if escape:
fixed = value.replace(";", "\\;")
else:
fixed = value.replace("\\;", ";")
def _unescape_semicolon(self, value: str) -> str:
fixed = value.replace(r"\\", "\\").replace(r"\;", ";")
self.log.debug(rf"in='{value}', unescaped='{fixed}'")
return fixed return fixed
def _get_nb_view(self, view: str | None | Literal[False]) -> dict[str, int | str]: def _get_nb_view(self, view: str | None | Literal[False]) -> dict[str, int | str]:
@ -212,7 +205,7 @@ class NetBoxDNSProvider(octodns.provider.base.BaseProvider):
} }
case "SPF" | "TXT": case "SPF" | "TXT":
value = self._fix_semicolon(rcd_value, escape=True) value = self._escape_semicolon(rcd_value)
case "SRV": case "SRV":
value = { value = {
@ -230,7 +223,7 @@ class NetBoxDNSProvider(octodns.provider.base.BaseProvider):
self.log.error("invalid record type") self.log.error("invalid record type")
raise ValueError raise ValueError
self.log.debug(f"formatted record value={value}") self.log.debug(rf"formatted record value={value}")
return value # type:ignore return value # type:ignore
@ -265,7 +258,7 @@ class NetBoxDNSProvider(octodns.provider.base.BaseProvider):
"ttl": rcd_ttl, "ttl": rcd_ttl,
"values": [], "values": [],
} }
self.log.debug(f"working on record={rcd_data} -> {rcd_value}") self.log.debug(rf"working on record={rcd_data}, value={rcd_value}")
try: try:
rcd_rdata = self._format_rdata(rcd_type, rcd_value) rcd_rdata = self._format_rdata(rcd_type, rcd_value)
@ -277,7 +270,7 @@ class NetBoxDNSProvider(octodns.provider.base.BaseProvider):
records[(rcd_name, rcd_type)]["values"].append(rcd_rdata) records[(rcd_name, rcd_type)]["values"].append(rcd_rdata)
self.log.debug(f"record data={records[(rcd_name, rcd_type)]}") self.log.debug(rf"record data={records[(rcd_name, rcd_type)]}")
return list(records.values()) return list(records.values())
@ -292,7 +285,7 @@ class NetBoxDNSProvider(octodns.provider.base.BaseProvider):
@return: true if the zone exists, else false. @return: true if the zone exists, else false.
""" """
self.log.info(f"populate -> '{zone.name}', target={target}, lenient={lenient}") self.log.info(f"--> populate '{zone.name}', target={target}, lenient={lenient}")
try: try:
records = self._format_nb_records(zone) records = self._format_nb_records(zone)
@ -315,13 +308,12 @@ class NetBoxDNSProvider(octodns.provider.base.BaseProvider):
return True return True
@staticmethod def _format_changeset(self, change: Any) -> set[str]:
def _format_changeset(change: Any) -> set[str]:
"""format the changeset """format the changeset
@param change: the raw changes @param change: the raw changes
@return: the formatted changeset @return: the formatted/escaped changeset
""" """
match change: match change:
case octodns.record.ValueMixin(): case octodns.record.ValueMixin():
@ -331,8 +323,14 @@ class NetBoxDNSProvider(octodns.provider.base.BaseProvider):
case _: case _:
raise ValueError raise ValueError
if change._type not in ["TXT", "SPF"]:
self.log.debug(f"{changeset=}")
return changeset return changeset
unescaped_changeset = {self._unescape_semicolon(n) for n in changeset}
self.log.debug(f"{unescaped_changeset=}")
return unescaped_changeset
def _include_change(self, change: octodns.record.change.Change) -> bool: def _include_change(self, change: octodns.record.change.Change) -> bool:
"""filter out record types which the provider can't create in netbox """filter out record types which the provider can't create in netbox
@ -341,7 +339,7 @@ class NetBoxDNSProvider(octodns.provider.base.BaseProvider):
@return: false if the change should be discarded, true if it should be kept. @return: false if the change should be discarded, true if it should be kept.
""" """
if change.record._type in ["SOA", "PTR", "NS"]: if change.record._type in ["SOA", "PTR", "NS"]:
self.log.debug(f"record not supported as provider, ignoring: {change.record}") self.log.debug(rf"record not supported as provider, ignoring: {change.record}")
return False return False
return True return True
@ -353,7 +351,7 @@ class NetBoxDNSProvider(octodns.provider.base.BaseProvider):
@return: none @return: none
""" """
self.log.debug(f"_apply: zone={plan.desired.name}, changes={len(plan.changes)}") self.log.debug(f"--> _apply zone={plan.desired.name}, changes={len(plan.changes)}")
nb_zone = self._get_nb_zone(plan.desired.name, view=self.nb_view) nb_zone = self._get_nb_zone(plan.desired.name, view=self.nb_view)
@ -364,17 +362,15 @@ class NetBoxDNSProvider(octodns.provider.base.BaseProvider):
new_changeset = self._format_changeset(change.new) new_changeset = self._format_changeset(change.new)
for record in new_changeset: for record in new_changeset:
nb_record: pynetbox.core.response.Record = ( self.log.debug(rf"ADD {change.new._type} {rcd_name} {record}")
self.api.plugins.netbox_dns.records.create( self.api.plugins.netbox_dns.records.create(
zone=nb_zone.id, zone=nb_zone.id,
name=rcd_name, name=rcd_name,
type=change.new._type, type=change.new._type,
ttl=change.new.ttl, ttl=change.new.ttl,
value=self._fix_semicolon(record, escape=False), value=record,
disable_ptr=self.disable_ptr, disable_ptr=self.disable_ptr,
) )
)
self.log.debug(f"ADD {nb_record.type} {nb_record.name} {nb_record.value}")
case octodns.record.Delete(): case octodns.record.Delete():
nb_records: pynetbox.core.response.RecordSet = ( nb_records: pynetbox.core.response.RecordSet = (
@ -391,7 +387,7 @@ class NetBoxDNSProvider(octodns.provider.base.BaseProvider):
if nb_record.value != record: if nb_record.value != record:
continue continue
self.log.debug( self.log.debug(
f"DELETE {nb_record.type} {nb_record.name} {nb_record.value}" rf"DELETE {nb_record.type} {nb_record.name} {nb_record.value}"
) )
nb_record.delete() nb_record.delete()
@ -414,23 +410,23 @@ class NetBoxDNSProvider(octodns.provider.base.BaseProvider):
for nb_record in nb_records: for nb_record in nb_records:
if nb_record.value in to_delete: if nb_record.value in to_delete:
self.log.debug( self.log.debug(
f"DELETE {nb_record.type} {nb_record.name} {nb_record.value}" rf"DELETE {nb_record.type} {nb_record.name} {nb_record.value}"
) )
nb_record.delete() nb_record.delete()
if nb_record.value in to_update: if nb_record.value in to_update:
nb_record.ttl = change.new.ttl
self.log.debug( self.log.debug(
f"MODIFY {nb_record.type} {nb_record.name} {nb_record.value}" rf"MODIFY (ttl) {nb_record.type} {nb_record.name} {nb_record.value}"
) )
nb_record.ttl = change.new.ttl
nb_record.save() nb_record.save()
for record in to_create: for record in to_create:
self.log.debug(rf"ADD {change.new._type} {rcd_name} {record}")
nb_record = self.api.plugins.netbox_dns.records.create( nb_record = self.api.plugins.netbox_dns.records.create(
zone=nb_zone.id, zone=nb_zone.id,
name=rcd_name, name=rcd_name,
type=change.new._type, type=change.new._type,
ttl=change.new.ttl, ttl=change.new.ttl,
value=self._fix_semicolon(record, escape=False), value=record,
disable_ptr=self.disable_ptr, disable_ptr=self.disable_ptr,
) )
self.log.debug(f"ADD {nb_record.type} {nb_record.name} {nb_record.value}")

View file

@ -14,7 +14,7 @@ DEFAULT_CONFIG = {
def test_escape1(): def test_escape1():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG) nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"v=TLSRPTv1; rua=mailto:tlsrpt@example.com" rcd_value = r"v=TLSRPTv1; rua=mailto:tlsrpt@example.com"
value = nbdns._fix_semicolon(rcd_value, escape=True) value = nbdns._escape_semicolon(rcd_value)
assert value == r"v=TLSRPTv1\; rua=mailto:tlsrpt@example.com" assert value == r"v=TLSRPTv1\; rua=mailto:tlsrpt@example.com"
@ -22,7 +22,7 @@ def test_escape1():
def test_escape2(): def test_escape2():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG) nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"v=TLSRPTv1\; rua=mailto:tlsrpt@example.com" rcd_value = r"v=TLSRPTv1\; rua=mailto:tlsrpt@example.com"
value = nbdns._fix_semicolon(rcd_value, escape=True) value = nbdns._escape_semicolon(rcd_value)
assert value == r"v=TLSRPTv1\\; rua=mailto:tlsrpt@example.com" assert value == r"v=TLSRPTv1\\; rua=mailto:tlsrpt@example.com"
@ -30,7 +30,7 @@ def test_escape2():
def test_escape3(): def test_escape3():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG) nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"t=y\;o=~\;" rcd_value = r"t=y\;o=~\;"
value = nbdns._fix_semicolon(rcd_value, escape=True) value = nbdns._escape_semicolon(rcd_value)
assert value == r"t=y\\;o=~\\;" assert value == r"t=y\\;o=~\\;"
@ -38,7 +38,7 @@ def test_escape3():
def test_escape4(): def test_escape4():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG) nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"t=y;o=~;" rcd_value = r"t=y;o=~;"
value = nbdns._fix_semicolon(rcd_value, escape=True) value = nbdns._escape_semicolon(rcd_value)
assert value == r"t=y\;o=~\;" assert value == r"t=y\;o=~\;"
@ -46,7 +46,7 @@ def test_escape4():
def test_unescape1(): def test_unescape1():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG) nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"v=TLSRPTv1\; rua=mailto:tlsrpt@example.com" rcd_value = r"v=TLSRPTv1\; rua=mailto:tlsrpt@example.com"
value = nbdns._fix_semicolon(rcd_value, escape=False) value = nbdns._unescape_semicolon(rcd_value)
assert value == r"v=TLSRPTv1; rua=mailto:tlsrpt@example.com" assert value == r"v=TLSRPTv1; rua=mailto:tlsrpt@example.com"
@ -54,22 +54,22 @@ def test_unescape1():
def test_unescape2(): def test_unescape2():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG) nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"v=TLSRPTv1\\; rua=mailto:tlsrpt@example.com" rcd_value = r"v=TLSRPTv1\\; rua=mailto:tlsrpt@example.com"
value = nbdns._fix_semicolon(rcd_value, escape=False) value = nbdns._unescape_semicolon(rcd_value)
assert value == r"v=TLSRPTv1\; rua=mailto:tlsrpt@example.com" assert value == r"v=TLSRPTv1; rua=mailto:tlsrpt@example.com"
def test_unescape3(): def test_unescape3():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG) nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"t=y\\;o=~\;" rcd_value = r"t=y\\;o=~\;"
value = nbdns._fix_semicolon(rcd_value, escape=False) value = nbdns._unescape_semicolon(rcd_value)
assert value == r"t=y\;o=~;" assert value == r"t=y;o=~;"
def test_unescape4(): def test_unescape4():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG) nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"t=y;o=~;" rcd_value = r"t=y;o=~;"
value = nbdns._fix_semicolon(rcd_value, escape=False) value = nbdns._unescape_semicolon(rcd_value)
assert value == r"t=y;o=~;" assert value == r"t=y;o=~;"