Compare commits

...

46 commits

Author SHA1 Message Date
a45ad29642 chore(deps): update dependency just to v1.25.0
All checks were successful
build and publish / release-pypackage (pull_request) Successful in 26s
build and publish / update-changelog (pull_request) Successful in 5s
check code / check-code (pull_request) Successful in 33s
2024-03-08 08:19:26 +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
f38a1036b7 update test cases
All checks were successful
check code / check-code (push) Successful in 34s
2024-02-29 19:45:24 +01:00
6e624a79a7 fix semicolon escaping 2024-02-29 19:37:27 +01:00
a8ecfab930 add new tests
All checks were successful
check code / check-code (push) Successful in 30s
2024-02-29 16:23:00 +01:00
afe182628a fix typo in method call and add function for semicolons 2024-02-29 16:22:52 +01:00
6b06cada38 update ci files for github
All checks were successful
check code / check-code (push) Successful in 29s
2024-02-29 13:06:59 +01:00
7912997add [bot] update changelog
All checks were successful
check code / check-code (push) Successful in 38s
2024-02-29 11:54:48 +00:00
558b861c24 Bump version 0.3.3 → 0.3.4
Some checks failed
check code / check-code (push) Successful in 29s
build and publish / update-changelog (push) Successful in 9s
build and publish / build-pypackage (push) Failing after 47s
2024-02-29 12:53:37 +01:00
c62453b0ac
Merge pull request #3 from olofvndrhr/dev
All checks were successful
check code / check-code (push) Successful in 28s
merge dev into main
2024-02-29 12:52:28 +01:00
0fb38b9ae5 add tests and move multiple replaces to regex replace
All checks were successful
check code / check-code (push) Successful in 33s
2024-02-29 12:48:50 +01:00
6953643876 Update dependency octodns to v1.5.0
All checks were successful
check code / check-code (push) Successful in 33s
2024-02-29 09:22:49 +01:00
537cd2061b Update lscr.io/linuxserver/netbox Docker tag to v3.7.3 2024-02-29 09:22:49 +01:00
21bc3f638a Merge pull request 'Update dependency octodns to v1.5.0' (#13) from renovate/octodns-1.x into main
All checks were successful
check code / check-code (push) Successful in 31s
Reviewed-on: #13
2024-02-29 09:19:45 +01:00
6c9f77c5f4 Update dependency octodns to v1.5.0
All checks were successful
build and publish / update-changelog (pull_request) Successful in 6s
build and publish / build-pypackage (pull_request) Successful in 38s
check code / check-code (pull_request) Successful in 32s
2024-02-29 08:18:33 +01:00
6326903bb3 add typehint for __init__
All checks were successful
check code / check-code (push) Successful in 29s
Signed-off-by: Ivan Schaller <ivan@schaller.sh>
2024-02-28 16:20:46 +01:00
408cf3fdd2 rename class and add new tests
All checks were successful
check code / check-code (push) Successful in 32s
2024-02-28 16:07:32 +01:00
29cf05c888 fix definition
All checks were successful
check code / check-code (push) Successful in 32s
2024-02-28 14:38:08 +01:00
59a9b01fef rename some variables
Some checks failed
check code / check-code (push) Failing after 21s
2024-02-28 14:33:53 +01:00
6612daeee7 fix some errors in record filtering 2024-02-28 14:28:42 +01:00
792b9d5429 simplify some code 2024-02-28 14:07:30 +01:00
886fc871fa Merge pull request 'Update lscr.io/linuxserver/netbox Docker tag to v3.7.3' (#11) from renovate/lscr.io-linuxserver-netbox-3.x into main
All checks were successful
check code / check-code (push) Successful in 27s
Reviewed-on: #11
2024-02-22 08:26:56 +01:00
93be71faba Update lscr.io/linuxserver/netbox Docker tag to v3.7.3
All checks were successful
build and publish / update-changelog (pull_request) Successful in 7s
build and publish / build-pypackage (pull_request) Successful in 30s
check code / check-code (pull_request) Successful in 28s
2024-02-22 08:16:41 +01:00
e27f8938a5 add dev branch to tests
All checks were successful
check code / check-code (push) Successful in 37s
2024-02-21 16:23:21 +01:00
284f001236 first tests with provider support 2024-02-21 16:21:25 +01:00
09898b7a22 revert the test changes
All checks were successful
check code / check-code (push) Successful in 31s
2024-02-21 16:19:29 +01:00
ba9d301dac update dev setup
All checks were successful
check code / check-code (push) Successful in 31s
2024-02-21 16:14:05 +01:00
c5f3fa9e00 fix workflow name
All checks were successful
check code / check-code (push) Successful in 33s
2024-02-21 15:01:43 +01:00
3728594b4e add first test
All checks were successful
check code / check-code (push) Successful in 33s
2024-02-21 14:59:19 +01:00
880a210b9b add dev setup 2024-02-21 14:48:11 +01:00
c81f3241d9 fix github release action
All checks were successful
check code / check-code (push) Successful in 27s
2024-02-20 10:10:03 +01:00
daef5bf30a [bot] update changelog 2024-02-20 09:04:03 +00:00
a97428e81c Bump version 0.3.2 → 0.3.3
Some checks failed
build and publish / update-changelog (push) Successful in 11s
check code / check-code (push) Successful in 23s
build and publish / build-pypackage (push) Failing after 1m3s
2024-02-20 10:03:40 +01:00
e0e769409d fix changelog generation
All checks were successful
check code / check-code (push) Successful in 25s
2024-02-20 09:35:59 +01:00
e047aa3d30 Bump version 0.3.1 → 0.3.2
Some checks failed
build and publish / update-changelog (push) Failing after 7s
check code / check-code (push) Successful in 19s
build and publish / build-pypackage (push) Failing after 1m4s
2024-02-20 09:24:44 +01:00
74c447b282 add CONTRIBUTING.md
All checks were successful
check code / check-code (push) Successful in 19s
2024-02-20 09:13:23 +01:00
86789a1c4b update ci files for future releases 2024-02-20 08:59:05 +01:00
6aeda2c48b add issue templates, ci linting and update pre-commit 2024-02-20 08:34:56 +01:00
30 changed files with 1378 additions and 121 deletions

View file

@ -1,16 +0,0 @@
name: build and publish
on:
push:
tags:
- "v*.*.*"
pull_request:
branches: [main, master]
jobs:
build-pypackage:
uses: actions/workflows/.gitea/workflows/build_pypackage.yml@master
secrets:
username: __token__
token: ${{ secrets.PACKAGE_TOKEN }}

View file

@ -0,0 +1,24 @@
name: build and publish
on:
push:
tags:
- "v*.*.*"
pull_request:
branches: [main, master]
jobs:
release-pypackage:
uses: actions/workflows/.gitea/workflows/release_pypackage.yml@master
with:
repository: main
secrets:
username: __token__
token: ${{ secrets.PACKAGE_TOKEN }}
gh-token: ${{ secrets.GH_TOKEN }}
update-changelog:
uses: actions/workflows/.gitea/workflows/update_changelog.yml@master
with:
branch: main

View file

@ -1,10 +0,0 @@
name: update changelog
on:
push:
tags:
- "v*.*.*"
jobs:
update-changelog:
uses: actions/workflows/.gitea/workflows/update_changelog.yml@master

View file

@ -2,13 +2,13 @@ name: check code
on: on:
push: push:
branches: [main, master] branches: [main, master, dev]
pull_request: pull_request:
branches: [main, master] branches: [main, master, dev]
jobs: jobs:
check-code: check-code:
uses: actions/workflows/.gitea/workflows/check_python_hatch.yml@master uses: actions/workflows/.gitea/workflows/check_python_hatch.yml@master
with: with:
run-tests: false run-tests: true

35
.github/issue_template/bug_report.md vendored Normal file
View file

@ -0,0 +1,35 @@
---
name: Bug report
about: Create a report to help improve the tool
title: "[BUG] <short summary>"
labels: bug
assignees: olofvndrhr
---
**System info (please complete the following information):**
- Host: [e.g. Linux/Debian or Docker]
- `octodns-netbox-dns` version [e.g. v2.1.5]
- `netbox-dns` version [e.g. v2.1.5]
- Netbox version [e.g. v2.1.5]
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.

View file

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[FEATURE] <short summary>"
labels: feature-request
assignees: olofvndrhr
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

54
.github/workflows/build_release.yml vendored Normal file
View file

@ -0,0 +1,54 @@
name: build and release
on:
push:
tags:
- "v*.*.*"
pull_request:
branches: [main, master]
jobs:
release-github:
runs-on: ubuntu-latest
env:
HATCH_INDEX_REPO: main
HATCH_INDEX_USER: __token__
HATCH_INDEX_AUTH: ${{ secrets.PACKAGE_TOKEN }}
steps:
- name: checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: install auto-changelog
run: npm install -g auto-changelog
- name: generate changelog
run: >-
auto-changelog -t keepachangelog
--commit-limit 50 --backfill-limit 50
--ignore-commit-pattern '[Bb]ump version|[Uu]pdate changelog|[Mm]erge pull request'
- name: get release notes
id: release-notes
uses: olofvndrhr/releasenote-gen@v1
- name: install hatch
run: pip install -U hatch hatchling
- name: build package
run: hatch build --clean
- name: create github release
uses: ncipollo/release-action@v1
if: github.event_name != 'pull_request'
with:
name: ${{ github.ref_name }}
body: ${{ steps.release-notes.outputs.releasenotes }}
artifacts: |-
dist/**

31
.github/workflows/check_code.yml vendored Normal file
View file

@ -0,0 +1,31 @@
name: check code
on:
push:
branches: [main, master, dev]
pull_request:
branches: [main, master, dev]
jobs:
check-code:
runs-on: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v3
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: install hatch
run: pip install -U hatch
- name: test codestyle
run: hatch run lint:style
- name: test typing
run: hatch run lint:typing
- name: run tests
run: hatch run default:test

7
.gitignore vendored
View file

@ -9,7 +9,12 @@ venv
.ruff_cache/ .ruff_cache/
__pycache__/ __pycache__/
.pytest_cache/ .pytest_cache/
.pytest_cache&
# dev
dev/db-data
dev/redis-data
dev/netbox-data
dev/output
### Python template ### Python template
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files

View file

@ -1,5 +0,0 @@
#!/bin/env bash
set -euxo pipefail
just format

View file

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

View file

@ -0,0 +1,120 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
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
### Commits
- add dev setup [`880a210`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/880a210b9bacf9158f3f8f90142c34d4e1719f45)
- update dev setup [`ba9d301`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/ba9d301dacf532a4fd217f6b08b4d3b407f315c6)
- simplify some code [`792b9d5`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/792b9d5429c43bbf67b99b35c7852b5d1e048980)
- first tests with provider support [`284f001`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/284f001236bda738693cea213cd3c1b6c5d9d16b)
- revert the test changes [`09898b7`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/09898b7a228454a26bcf1e83b6cac7b556ec9aa3)
- rename class and add new tests [`408cf3f`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/408cf3fdd279d5911eefb21f3789410c287c6611)
- add tests and move multiple replaces to regex replace [`0fb38b9`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/0fb38b9ae54efb1d593f3daa1a2af601a7e52d60)
- fix some errors in record filtering [`6612dae`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/6612daeee79a8759d4af3c0caa86129fce27f0b6)
- rename some variables [`59a9b01`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/59a9b01fef8feadfc448716eec30e9f1157d34ae)
- add first test [`3728594`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/3728594b4e022e77846468d7f8e3260ed3b13029)
- fix definition [`29cf05c`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/29cf05c888fb96dab1710d86168250563b4b0bf6)
- add dev branch to tests [`e27f893`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/e27f8938a51449718de638651550ea54a187589d)
- Update dependency octodns to v1.5.0 [`6953643`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/69536438767c8c7483c330967278a19b02d99f7f)
- Update lscr.io/linuxserver/netbox Docker tag to v3.7.3 [`537cd20`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/537cd2061b859e1f4bff4e009154c1ac2ff31e5f)
- Update dependency octodns to v1.5.0 [`6c9f77c`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/6c9f77c5f420bfc06d28dbbbf5ef512fb8f32d1f)
- add typehint for __init__ [`6326903`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/6326903bb3990ed57045f91bae53b377677862b9)
- Update lscr.io/linuxserver/netbox Docker tag to v3.7.3 [`93be71f`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/93be71fabad25f1285f827e347da82a97212a425)
- fix workflow name [`c5f3fa9`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/c5f3fa9e00ad63231ecbd6654853510ca338883f)
- fix github release action [`c81f324`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/c81f3241d9841798582cbfdf75e11c5d59ea6eee)
## [v0.3.3](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/compare/v0.3.2...v0.3.3) - 2024-02-20
### Commits
- fix changelog generation [`e0e7694`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/e0e769409d7c5c369e7f0c0c1cbd74da1f2ddcde)
## [v0.3.2](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/compare/v0.3.1...v0.3.2) - 2024-02-20
### Commits
- add issue templates, ci linting and update pre-commit [`6aeda2c`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/6aeda2c48bf50c5081a2f5cf8dfed096440a6e5f)
- update ci files for future releases [`86789a1`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/86789a1c4bc3ab45d34e1dfcdcc765d7890138d5)
- add CONTRIBUTING.md [`74c447b`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/74c447b282949184be41f05bd975f442ac6f7b92)
- add changelog [`35c069e`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/35c069efe94442c6307e3ac87185a84ad49a1282)
## [v0.3.1](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/compare/v0.3.0...v0.3.1) - 2024-01-25
### Commits
- fix for single value rcd [`256d1a8`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/256d1a8f0ecc5de6a8d8d3e3ff10752785b3d2d2)
- fix type errors [`f20e190`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/f20e190ef6d4bf130550616fac7d83af721b4ff2)
- fix type hint for rdata [`95c6815`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/95c6815dad6ea0b2c2eca42e83f79da08487e409)
## [v0.3.0](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/compare/v0.2.1...v0.3.0) - 2024-01-25
### Commits
- make populate function smaller [`c95f95f`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/c95f95fb8b8a2ae79b8f4db05675e98386a723b6)
- add docstrings and refactor make absolute function [`f7f54f8`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/f7f54f8eb71fef26c6759509a589d9afc7a91bdc)
- add new workflows [`ff3dd03`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/ff3dd03ce53002e457e172b8718af1e65ac7f78d)
- fix mypy issues [`988502a`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/988502a499d86339fc7f2f4c623c442590b1f59d)
- fix deps [`de1e67c`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/de1e67c6be5063c6dbed6483f232baf9420dcfa7)
## v0.2.1 - 2024-01-09
### Fixed
- remove wayward debug pprint [`#10`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/issues/10)
- Record type as parameter value passed to get_nb_zone [`#7`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/issues/7)
### Commits
- first commit [`cab1692`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/cab1692ea57fedc54a2633330c442d2acebba1e8)
- update query for views and use hatch as a build tool [`cdd0b00`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/cdd0b00cd155ac5af9d6a457fa1ecfb71081b3a9)
- update to python template for future pypi releases [`4a2ba28`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/4a2ba28aaa3c05fdc163a3b703c7226a74e349e6)
- use fork of pynetbox until pkg_resources runtime dependency is removed [`daa03aa`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/daa03aae2df979c2469696011ce42c694192a02c)
- move from provider base class to source [`5714ce5`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/5714ce5af9d738999ddb68e7b92eb60c5776cd02)
- update readme and make absolute optional [`61b1b47`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/61b1b47a96bb81ab6eb216a4a0988f7682a7fa9f)
- update dependencies [`4cf1c62`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/4cf1c627742593a8590f26d49bd375e3b51b31bc)
- _get_nb_zone() is now aware of same zones declared under different view [`c2f27f7`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/c2f27f7c43f78040d79d6fdc2c84d250f6f64403)
- add @ support and make cname records absolute [`9d79906`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/9d79906f960bb61aacfb464979899805bce34dbf)
- implement replace duplicate option [`790a2de`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/790a2de3458e3fd9cefd0fdf35b82dfa156820bf)
- fix 'Abstract base class, log property missing' [`f8251ad`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/f8251ad8ffcf6f92dfcf1dfdcffe954ac55eee4c)
- update view query [`3cb883a`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/3cb883abd67a275e4e64a79c6a28f46d706b9679)
- zone can also be configured without assigned view [`4828bbf`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/4828bbf00bb8f4946f07134a39cddc04a2ed306b)
- make some records absolute [`c77cef6`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/c77cef64ee5d0470ab8fa1f5fc2781e1f24a75a2)
- update requirements [`66d9551`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/66d95519b1070489859d665671d50e50f94f5a8e)
- Fix issue where octodns was failing on missing TTL value for NS records in PTR zones [`d3c1d0f`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/d3c1d0f65390dd595441ac3dca1cf52db790ddad)
- fix parameter call to better reflect function type hint. [`e4db78a`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/e4db78a281a27765271f1afda07dee08602ed2d0)
- Use upstream pynetbox library as their pull req #426 is merged. [`423207e`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/423207e5dd1673f306fb392cc5d37f63a4545fe5)
- fix attribute error in case view is null [`693ea86`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/693ea866296132b1cd94e2dda61ae94e94a77557)
- fix log merge [`f0b502a`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/f0b502a74f3ea72cfd78d9837bbbcc0934e0b826)
- fix literal type [`bec8384`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/bec83845577417d0ede5bd57a7772946bd997142)
- update debug log [`3537917`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/353791797ded363c9610b5f40e4bd857b93fd328)
- escape ; character in txt records [`ac395e8`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/ac395e84e24b1b271ff76721137e2d82f548553c)
- fix request parameter [`d4c0955`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/d4c095540f0b925dcca249d2896ca890731af256)
- add log message for total records found [`14a98fe`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/14a98fe132b3e6789ca3ad410bc101bac00b4f78)
- view argument type hints must also accept None value [`c5ae5bf`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/c5ae5bf4057756030f0447681e9e6c2dccb59ec1)
- update lock [`d4a4032`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/d4a403261fb2e80a4335071cc17dbff00fa9366c)
- Fix invalid query to Netbox, search only with zone ID. [`e752d3d`](https://git.44net.ch/olofvndrhr/octodns-netbox-dns/commit/e752d3db221f9b79e3df5dc30ca40f597a655873)

42
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,42 @@
# getting started
## with asdf
### tools needed
- python 3.11
- [hatch](https://hatch.pypa.io/)
- [asdf](https://asdf-vm.com/guide/getting-started.html)
### setup
1. install [asdf](https://asdf-vm.com/guide/getting-started.html)
2. run `asdf install` in this directory to install all needed tools
3. run `just setup` to install the pre-commit hooks etc.
### pre-commit
1. run `just check` to lint the files and auto-format them.
you can optionally run `just format` and `just lint` as a single action.
2. fix the issues which ruff reports
3. run `just build` to check if it builds correctly
4. commit changes
## manual
### tools needed
- python 3.11
- [hatch](https://hatch.pypa.io/)
### setup
1. install [just](https://github.com/casey/just)
2. run `just setup` to install the pre-commit hooks etc.
### pre-commit
1. run `hatch run lint:fmt` to lint the files and auto-format them.
2. fix the issues which ruff reports
3. run `hatch build --clean` to check if it builds correctly
4. commit changes

View file

@ -1,4 +1,4 @@
# netbox-plugin-dns source for octodns # netbox-plugin-dns provider for octodns
> works with https://github.com/peteeckel/netbox-plugin-dns > works with https://github.com/peteeckel/netbox-plugin-dns
@ -7,7 +7,7 @@
```yml ```yml
providers: providers:
config: config:
class: octodns_netbox_dns.NetBoxDNSSource class: octodns_netbox_dns.NetBoxDNSProvider
# Netbox url # Netbox url
# [mandatory, default=null] # [mandatory, default=null]
url: "https://some-url" url: "https://some-url"
@ -27,8 +27,19 @@ providers:
# Make CNAME, MX and SRV records absolute if they are missing the trailing "." # Make CNAME, MX and SRV records absolute if they are missing the trailing "."
# [optional, default=false] # [optional, default=false]
make_absolute: false make_absolute: false
# Disable automatic PTR record creating in the NetboxDNS plugin.
# [optional, default=true]
disable_ptr: true
``` ```
## compatibility
> actively tested on the newest netbox-plugin-dns and netbox versions
| provider | [netbox-plugin-dns](https://github.com/peteeckel/netbox-plugin-dns) | [netbox](https://github.com/netbox-community/netbox) |
|-------------|---------------------------------------------------------------------|------------------------------------------------------|
| `>= v0.3.3` | `>=0.21.0` | `>=3.6.0` |
## install ## install
### via pip ### via pip

6
dev/Dockerfile Normal file
View file

@ -0,0 +1,6 @@
FROM lscr.io/linuxserver/netbox:3.7.3
RUN pip install -U \
wheel \
setuptools \
netbox-plugin-dns

66
dev/compose.yml Normal file
View file

@ -0,0 +1,66 @@
services:
app:
image: netbox-dev:build
container_name: netbox-dev-app
restart: unless-stopped
security_opt: ["no-new-privileges:true"]
build:
dockerfile: Dockerfile
depends_on:
- db
- redis
networks:
- appnet
ports:
- "8000:8000"
volumes:
- ./netbox-data/:/config/:rw
- ./configuration.py:/config/configuration.py:ro
environment:
- TZ=Europe/Zurich
- PUID=${UID}
- PGID=${GID}
- DB_HOST=netbox-dev-db
- DB_NAME=netbox
- DB_USER=netbox
- DB_PASSWORD=netbox-dev
- REDIS_HOST=netbox-dev-redis
- SUPERUSER_EMAIL=admin@example.com
- SUPERUSER_PASSWORD=netbox-dev
db:
image: bitnami/postgresql:14.9.0
container_name: netbox-dev-db
restart: unless-stopped
user: ${UID}
security_opt: ["no-new-privileges:true"]
networks:
- appnet
volumes:
- /etc/localtime:/etc/localtime:ro
- ./db-data/:/bitnami/postgresql/:rw
environment:
- TZ=Europe/Zurich
- POSTGRESQL_POSTGRES_PASSWORD=netbox-dev
- POSTGRES_DB=netbox
- POSTGRES_USER=netbox
- POSTGRES_PASSWORD=netbox-dev
redis:
image: bitnami/redis:7.2
container_name: netbox-dev-redis
restart: unless-stopped
user: ${UID}
security_opt: ["no-new-privileges:true"]
networks:
- appnet
volumes:
- ./redis-data/:/bitnami/redis/data/:rw
environment:
- TZ=Europe/Zurich
- ALLOW_EMPTY_PASSWORD=yes
networks:
appnet:
name: netbox-dev
driver: bridge

304
dev/configuration.py Normal file
View file

@ -0,0 +1,304 @@
#########################
# #
# Required settings #
# #
#########################
PLUGINS = ["netbox_dns"]
PLUGINS_CONFIG = {
"netbox_dns": {
"zone_default_ttl": 3600,
"zone_soa_serial_auto": True,
"zone_soa_minimum": 3600,
"zone_nameservers": ["ns1.example.com", "ns2.example.com"],
"zone_soa_mname": "ns1.example.com",
"zone_soa_rname": "admin.example.com",
"tolerate_underscores_in_hostnames": False,
"tolerate_leading_underscore_types": [
"TXT",
"SRV",
],
"enable_root_zones": False,
"enforce_unique_records": False,
"feature_ipam_coupling": False,
"feature_ipam_dns_info": True,
},
}
# This is a list of valid fully-qualified domain names (FQDNs) for the NetBox server. NetBox will not permit write
# access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name.
#
# Example: ALLOWED_HOSTS = ['netbox.example.com', 'netbox.internal.local']
ALLOWED_HOSTS = ["localhost"]
# PostgreSQL database configuration. See the Django documentation for a complete list of available parameters:
# https://docs.djangoproject.com/en/stable/ref/settings/#databases
DATABASE = {
"NAME": "netbox", # Database name
"USER": "netbox", # PostgreSQL username
"PASSWORD": "netbox-dev", # PostgreSQL password
"HOST": "netbox-dev-db", # Database server
"PORT": "", # Database port (leave blank for default)
"CONN_MAX_AGE": 300, # Max database connection age
}
# Redis database settings. Redis is used for caching and for queuing background tasks such as webhook events. A separate
# configuration exists for each. Full connection details are required in both sections, and it is strongly recommended
# to use two separate database IDs.
REDIS = {
"tasks": {
"HOST": "netbox-dev-redis",
"PORT": 6379,
# Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel
# 'SENTINELS': [('mysentinel.redis.example.com', 6379)],
# 'SENTINEL_SERVICE': 'netbox',
"PASSWORD": "",
"DATABASE": 0,
"SSL": False,
# Set this to True to skip TLS certificate verification
# This can expose the connection to attacks, be careful
# 'INSECURE_SKIP_TLS_VERIFY': False,
},
"caching": {
"HOST": "netbox-dev-redis",
"PORT": 6379,
# Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel
# 'SENTINELS': [('mysentinel.redis.example.com', 6379)],
# 'SENTINEL_SERVICE': 'netbox',
"PASSWORD": "",
"DATABASE": 1,
"SSL": False,
# Set this to True to skip TLS certificate verification
# This can expose the connection to attacks, be careful
# 'INSECURE_SKIP_TLS_VERIFY': False,
},
}
# This key is used for secure generation of random numbers and strings. It must never be exposed outside of this file.
# For optimal security, SECRET_KEY should be at least 50 characters in length and contain a mix of letters, numbers, and
# symbols. NetBox will not run without this defined. For more information, see
# https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-SECRET_KEY
SECRET_KEY = "ZFK2dO-pD@Vnjxf7gM@gh#jHwXm_wih%V6v@Byld7yX6c^Vsb!"
#########################
# #
# Optional settings #
# #
#########################
# Specify one or more name and email address tuples representing NetBox administrators. These people will be notified of
# application errors (assuming correct email settings are provided).
ADMINS = [
# ('John Doe', 'jdoe@example.com'),
]
# URL schemes that are allowed within links in NetBox
ALLOWED_URL_SCHEMES = (
"file",
"ftp",
"ftps",
"http",
"https",
"irc",
"mailto",
"sftp",
"ssh",
"tel",
"telnet",
"tftp",
"vnc",
"xmpp",
)
# Optionally display a persistent banner at the top and/or bottom of every page. HTML is allowed. To display the same
# content in both banners, define BANNER_TOP and set BANNER_BOTTOM = BANNER_TOP.
BANNER_TOP = ""
BANNER_BOTTOM = ""
# Text to include on the login page above the login form. HTML is allowed.
BANNER_LOGIN = ""
# Base URL path if accessing NetBox within a directory. For example, if installed at https://example.com/netbox/, set:
# BASE_PATH = 'netbox/'
BASE_PATH = ""
# Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90)
CHANGELOG_RETENTION = 90
# API Cross-Origin Resource Sharing (CORS) settings. If CORS_ORIGIN_ALLOW_ALL is set to True, all origins will be
# allowed. Otherwise, define a list of allowed origins using either CORS_ORIGIN_WHITELIST or
# CORS_ORIGIN_REGEX_WHITELIST. For more information, see https://github.com/ottoyiu/django-cors-headers
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = [
# 'https://hostname.example.com',
]
CORS_ORIGIN_REGEX_WHITELIST = [
# r'^(https?://)?(\w+\.)?example\.com$',
]
# Specify any custom validators here, as a mapping of model to a list of validators classes. Validators should be
# instances of or inherit from CustomValidator.
# from extras.validators import CustomValidator
CUSTOM_VALIDATORS = {
# 'dcim.site': [
# CustomValidator({
# 'name': {
# 'min_length': 10,
# 'regex': r'\d{3}$',
# }
# })
# ],
}
# Set to True to enable server debugging. WARNING: Debugging introduces a substantial performance penalty and may reveal
# sensitive information about your installation. Only enable debugging while performing testing. Never enable debugging
# on a production system.
DEBUG = False
# Email settings
EMAIL = {
"SERVER": "localhost",
"PORT": 25,
"USERNAME": "",
"PASSWORD": "",
"USE_SSL": False,
"USE_TLS": False,
"TIMEOUT": 10, # seconds
"FROM_EMAIL": "",
}
# Enforcement of unique IP space can be toggled on a per-VRF basis. To enforce unique IP space within the global table
# (all prefixes and IP addresses not assigned to a VRF), set ENFORCE_GLOBAL_UNIQUE to True.
ENFORCE_GLOBAL_UNIQUE = False
# Exempt certain models from the enforcement of view permissions. Models listed here will be viewable by all users and
# by anonymous users. List models in the form `<app>.<model>`. Add '*' to this list to exempt all models.
EXEMPT_VIEW_PERMISSIONS = [
# 'dcim.site',
# 'dcim.region',
# 'ipam.prefix',
]
# Enable the GraphQL API
GRAPHQL_ENABLED = True
# HTTP proxies NetBox should use when sending outbound HTTP requests (e.g. for webhooks).
# HTTP_PROXIES = {
# 'http': 'http://10.10.1.10:3128',
# 'https': 'http://10.10.1.10:1080',
# }
# IP addresses recognized as internal to the system. The debugging toolbar will be available only to clients accessing
# NetBox from an internal IP.
INTERNAL_IPS = ("127.0.0.1", "::1")
# Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs:
# https://docs.djangoproject.com/en/stable/topics/logging/
LOGGING = {}
# Automatically reset the lifetime of a valid session upon each authenticated request. Enables users to remain
# authenticated to NetBox indefinitely.
LOGIN_PERSISTENCE = False
# Setting this to True will permit only authenticated users to access any part of NetBox. By default, anonymous users
# are permitted to access most data in NetBox but not make any changes.
LOGIN_REQUIRED = False
# The length of time (in seconds) for which a user will remain logged into the web UI before being prompted to
# re-authenticate. (Default: 1209600 [14 days])
LOGIN_TIMEOUT = None
# Setting this to True will display a "maintenance mode" banner at the top of every page.
MAINTENANCE_MODE = False
# The URL to use when mapping physical addresses or GPS coordinates
MAPS_URL = "https://maps.google.com/?q="
# An API consumer can request an arbitrary number of objects =by appending the "limit" parameter to the URL (e.g.
# "?limit=1000"). This setting defines the maximum limit. Setting it to 0 or None will allow an API consumer to request
# all objects by specifying "?limit=0".
MAX_PAGE_SIZE = 1000
# The file path where uploaded media such as image attachments are stored. A trailing slash is not needed. Note that
# the default value of this setting is derived from the installed location.
# MEDIA_ROOT = '/opt/netbox/netbox/media'
# By default uploaded media is stored on the local filesystem. Using Django-storages is also supported. Provide the
# class path of the storage driver in STORAGE_BACKEND and any configuration options in STORAGE_CONFIG. For example:
# STORAGE_BACKEND = 'storages.backends.s3boto3.S3Boto3Storage'
# STORAGE_CONFIG = {
# 'AWS_ACCESS_KEY_ID': 'Key ID',
# 'AWS_SECRET_ACCESS_KEY': 'Secret',
# 'AWS_STORAGE_BUCKET_NAME': 'netbox',
# 'AWS_S3_REGION_NAME': 'eu-west-1',
# }
# Expose Prometheus monitoring metrics at the HTTP endpoint '/metrics'
METRICS_ENABLED = False
# Credentials that NetBox will uses to authenticate to devices when connecting via NAPALM.
NAPALM_USERNAME = ""
NAPALM_PASSWORD = ""
# NAPALM timeout (in seconds). (Default: 30)
NAPALM_TIMEOUT = 30
# NAPALM optional arguments (see https://napalm.readthedocs.io/en/latest/support/#optional-arguments). Arguments must
# be provided as a dictionary.
NAPALM_ARGS = {}
# Determine how many objects to display per page within a list. (Default: 50)
PAGINATE_COUNT = 50
# When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to
# prefer IPv4 instead.
PREFER_IPV4 = False
# Rack elevation size defaults, in pixels. For best results, the ratio of width to height should be roughly 10:1.
RACK_ELEVATION_DEFAULT_UNIT_HEIGHT = 22
RACK_ELEVATION_DEFAULT_UNIT_WIDTH = 220
# Remote authentication support
REMOTE_AUTH_ENABLED = False
REMOTE_AUTH_BACKEND = "netbox.authentication.RemoteUserBackend"
REMOTE_AUTH_HEADER = "HTTP_REMOTE_USER"
REMOTE_AUTH_AUTO_CREATE_USER = False
REMOTE_AUTH_DEFAULT_GROUPS = []
REMOTE_AUTH_DEFAULT_PERMISSIONS = {}
# This repository is used to check whether there is a new release of NetBox available. Set to None to disable the
# version check or use the URL below to check for release in the official NetBox repository.
RELEASE_CHECK_URL = None
# RELEASE_CHECK_URL = 'https://api.github.com/repos/netbox-community/netbox/releases'
# The file path where custom reports will be stored. A trailing slash is not needed. Note that the default value of
# this setting is derived from the installed location.
# REPORTS_ROOT = '/opt/netbox/netbox/reports'
# Maximum execution time for background tasks, in seconds.
RQ_DEFAULT_TIMEOUT = 300
# The file path where custom scripts will be stored. A trailing slash is not needed. Note that the default value of
# this setting is derived from the installed location.
SCRIPTS_ROOT = "/config/scripts"
# The name to use for the session cookie.
SESSION_COOKIE_NAME = "sessionid"
# By default, NetBox will store session data in the database. Alternatively, a file path can be specified here to use
# local file storage instead. (This can be useful for enabling authentication on a standby instance with read-only
# database access.) Note that the user as which NetBox runs must have read and write permissions to this path.
SESSION_FILE_PATH = None
# Time zone (default: UTC)
TIME_ZONE = "UTC"
# Date/time formatting. See the following link for supported formats:
# https://docs.djangoproject.com/en/stable/ref/templates/builtins/#date
DATE_FORMAT = "N j, Y"
SHORT_DATE_FORMAT = "Y-m-d"
TIME_FORMAT = "g:i a"
SHORT_TIME_FORMAT = "H:i:s"
DATETIME_FORMAT = "N j, Y g:i a"
SHORT_DATETIME_FORMAT = "Y-m-d H:i"

57
dev/sync.yml Normal file
View file

@ -0,0 +1,57 @@
manager:
max_workers: 1
plan_outputs:
html:
class: octodns.provider.plan.PlanMarkdown
processors:
spf:
class: octodns_spf.SpfDnsLookupProcessor
no-root-ns:
class: octodns.processor.filter.IgnoreRootNsFilter
min-max-ttl:
class: octodns.processor.restrict.TtlRestrictionFilter
allowed_ttls:
- 60
- 300
- 600
- 900
- 1800
- 3600
- 7200
- 10800
providers:
config:
class: octodns.provider.yaml.YamlProvider
directory: ./zones
default_ttl: 3600
enforce_order: true
populate_should_replace: false
netbox:
class: octodns_netbox_dns.NetBoxDNSProvider
url: http://localhost:8000
token: 1ca8f8de1d651b0859052dc5e6a0858fd1e43e3d # change token for netbox
view: false
replace_duplicates: false
make_absolute: true
zones:
example.com.:
sources:
- config
processors:
- spf
targets:
- netbox
test.example.com.:
sources:
- config
processors:
- spf
targets:
- netbox
view.example.com.:
sources:
- config
processors:
- spf
targets:
- netbox

View file

@ -0,0 +1,37 @@
---
? ''
: - ttl: 172800
type: NS
values:
- ns1.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:
type: A
value: 192.168.1.1
ns2:
type: A
value: 192.168.1.2
record1:
type: CNAME
value: record11.example.com.
record11:
type: A
value: 192.168.1.11
record12:
type: A
value: 192.168.1.12
x._domainkey:
type: TXT
value: v=DKIM1\; k=rsa\; p=MIIBIjANBgkasdasdasIIBCgKCAQEAq7OOAhfjaOKMSiJR8xkG+sadasdasd+OiWdZEZ7T4blBQxuWTNGoaG1CKOFeJSf72JAlqxF++z2CB4ypdUOoRNn96KlcpI2LBmoW1c7ZzFzqPvgCs+EzaOnt5S2FH2njHb15+atdE8cuZ7+MGmHf5HSD/asdasdasdasdasdadadasd+2Chr68t4wc+qPrUIGM3JnOhzKyiK6FfQXVwoDTxwmKTE2EzhPAQjlCHrRLaynDqiGjXjZcqoF9UEB5cBGw+asdasdasdasdas/dwIDAQAB

View file

@ -0,0 +1,19 @@
---
? ''
: ttl: 172800
type: NS
values:
- ns1.example.com.
- ns2.example.com.
_smtp._tls:
type: TXT
value: v=TLSRPTv1\; rua=mailto:tlsrpt@example.com
record1:
type: CNAME
value: record11.test.example.com.
record11:
type: A
value: 192.168.1.11
record12:
type: A
value: 192.168.1.12

View file

@ -0,0 +1,16 @@
---
? ''
: ttl: 172800
type: NS
values:
- ns1.example.com.
- ns2.example.com.
record1:
type: CNAME
value: record11.view.example.com.
record11:
type: A
value: 192.168.1.11
record12:
type: A
value: 192.168.1.13

View file

@ -6,7 +6,7 @@ set shell := ["bash", "-uc"]
set dotenv-load set dotenv-load
show_receipts: show_receipts:
@just --list just --list
show_system_info: show_system_info:
@echo "==================================" @echo "=================================="
@ -18,34 +18,64 @@ show_system_info:
@echo "==================================" @echo "=================================="
setup: setup:
@asdf install asdf install
@lefthook install lefthook install
create_venv: create_venv:
@echo "creating venv" @echo "creating venv"
@python3 -m pip install --upgrade pip setuptools wheel python3 -m pip install --upgrade pip setuptools wheel
@python3 -m venv venv python3 -m venv venv
install_deps: install_deps:
@echo "installing dependencies" @echo "installing dependencies"
@python3 -m hatch dep show requirements --project-only > /tmp/requirements.txt python3 -m hatch dep show requirements --project-only > /tmp/requirements.txt
@pip3 install -r /tmp/requirements.txt pip3 install -r /tmp/requirements.txt
install_deps_dev: install_deps_dev:
@echo "installing dev dependencies" @echo "installing dev dependencies"
@python3 -m hatch dep show requirements --project-only > /tmp/requirements.txt python3 -m hatch dep show requirements --project-only > /tmp/requirements.txt
@python3 -m hatch dep show requirements --env-only >> /tmp/requirements.txt python3 -m hatch dep show requirements --env-only >> /tmp/requirements.txt
@pip3 install -r /tmp/requirements.txt pip3 install -r /tmp/requirements.txt
create_reqs: create_reqs:
@echo "creating requirements" @echo "creating requirements"
@pipreqs --force --savepath requirements.txt src/octodns_netbox_dns pipreqs --force --savepath requirements.txt src/octodns_netbox_dns
lint: lint:
just show_system_info just show_system_info
@hatch run lint:style hatch run lint:style
@hatch run lint:typing hatch run lint:typing
format: format *args:
just show_system_info just show_system_info
@hatch run lint:fmt hatch run lint:fmt {{ args }}
check:
just lint
just format
build:
hatch build --clean
test:
hatch run default:test
up:
docker compose -f dev/compose.yml up
down:
docker compose -f dev/compose.yml down
clean:
rm -rf dev/db-data/*
rm -rf dev/redis-data/*
rm -rf dev/netbox-data/*
sync *args:
hatch -v run default:sync {{ args }}
dump *args:
hatch -v run default:dump {{ args }}
validate *args:
hatch -v run default:validate {{ args }}

View file

@ -2,7 +2,13 @@ colors: true
no_tty: false no_tty: false
pre-commit: pre-commit:
scripts: commands:
"format.sh": 01_ruff_check:
stage_fixed: true stage_fixed: true
runner: bash glob: "*.py"
run: ruff check --fix-only --exit-zero --silent {all_files}
02_ruff_format:
stage_fixed: true
glob: "*.py"
run: ruff format {all_files}

View file

@ -35,22 +35,23 @@ source = "regex_commit"
path = "src/octodns_netbox_dns/__about__.py" path = "src/octodns_netbox_dns/__about__.py"
tag_sign = false tag_sign = false
[tool.hatch.build]
ignore-vcs = true
[tool.hatch.build.targets.sdist] [tool.hatch.build.targets.sdist]
packages = ["src/octodns_netbox_dns"] packages = ["src/octodns_netbox_dns"]
[tool.hatch.build.targets.wheel] [tool.hatch.build.targets.wheel]
packages = ["src/octodns_netbox_dns"] packages = ["src/octodns_netbox_dns"]
###
### envs ### envs
###
[tool.hatch.envs.default] [tool.hatch.envs.default]
python = "3.11" python = "3.11"
dependencies = [ dependencies = [
"pytest==7.4.3", "pytest==7.4.4",
"coverage==7.3.2", "coverage==7.4.2",
"octodns==1.5.0",
"octodns-spf==0.0.2",
] ]
[tool.hatch.envs.default.scripts] [tool.hatch.envs.default.scripts]
@ -59,21 +60,34 @@ test-cov = ["coverage erase", "coverage run -m pytest {args:tests}"]
cov-report = ["- coverage combine", "coverage report", "coverage xml"] cov-report = ["- coverage combine", "coverage report", "coverage xml"]
cov = ["test-cov", "cov-report"] cov = ["test-cov", "cov-report"]
sync = ["cd dev && octodns-sync --debug --config-file sync.yml --force {args}"]
dump = ["cd dev && octodns-dump --debug --config-file sync.yml --output-dir output {args} '*' netbox"]
validate = ["cd dev && octodns-validate --debug --config-file sync.yml {args}"]
[tool.hatch.envs.lint] [tool.hatch.envs.lint]
python = "3.11" python = "3.11"
detached = true detached = true
dependencies = [ dependencies = [
"mypy==1.7.1", "mypy==1.8.0",
"ruff==0.1.7", "ruff==0.2.2",
] ]
[tool.hatch.envs.lint.scripts] [tool.hatch.envs.lint.scripts]
typing = "mypy --non-interactive --install-types {args:src/octodns_netbox_dns}" typing = "mypy --non-interactive --install-types {args:src/octodns_netbox_dns}"
style = ["ruff check --diff {args:.}", "ruff format --check --diff {args:.}"] style = [
fmt = ["ruff format {args:.}", "ruff check --fix {args:.}", "style"] "ruff check --diff {args:.}",
"ruff format --check --diff {args:.}"
]
fmt = [
"ruff check --fix {args:.}",
"ruff format {args:.}",
"style"
]
all = ["style", "typing"] all = ["style", "typing"]
###
### ruff ### ruff
###
[tool.ruff] [tool.ruff]
target-version = "py311" target-version = "py311"
@ -81,7 +95,6 @@ line-length = 100
indent-width = 4 indent-width = 4
fix = true fix = true
show-fixes = true show-fixes = true
ignore-init-module-imports = true
respect-gitignore = true respect-gitignore = true
src = ["src", "tests"] src = ["src", "tests"]
exclude = [ exclude = [
@ -99,6 +112,7 @@ exclude = [
"dist", "dist",
"node_modules", "node_modules",
"venv", "venv",
"dev"
] ]
[tool.ruff.lint] [tool.ruff.lint]
@ -129,6 +143,7 @@ select = [
"W", "W",
"YTT", "YTT",
] ]
ignore-init-module-imports = true
ignore = ["E501", "D103", "D100", "D102", "PLR2004", "D403", "ISC001", "FBT001", "FBT002", "FBT003"] ignore = ["E501", "D103", "D100", "D102", "PLR2004", "D403", "ISC001", "FBT001", "FBT002", "FBT003"]
unfixable = ["F401"] unfixable = ["F401"]
@ -137,39 +152,42 @@ quote-style = "double"
indent-style = "space" indent-style = "space"
skip-magic-trailing-comma = false skip-magic-trailing-comma = false
line-ending = "lf" line-ending = "lf"
docstring-code-format = true
[tool.ruff.per-file-ignores] [tool.ruff.lint.per-file-ignores]
"__init__.py" = ["D104"] "__init__.py" = ["D104"]
"__about__.py" = ["D104", "F841"] "__about__.py" = ["D104", "F841"]
"tests/**/*" = ["PLR2004", "S101", "TID252"] "tests/**/*" = ["PLR2004", "S101", "TID252"]
[tool.ruff.pyupgrade] [tool.ruff.lint.pyupgrade]
keep-runtime-typing = true keep-runtime-typing = true
[tool.ruff.isort] [tool.ruff.lint.isort]
lines-after-imports = 2 lines-after-imports = 2
known-first-party = ["octodns_netbox_dns"] known-first-party = ["octodns_netbox_dns"]
[tool.ruff.flake8-tidy-imports] [tool.ruff.lint.flake8-tidy-imports]
ban-relative-imports = "all" ban-relative-imports = "all"
[tool.ruff.pylint] [tool.ruff.lint.pylint]
max-branches = 24 max-branches = 24
max-returns = 12 max-returns = 12
max-statements = 100 max-statements = 100
max-args = 15 max-args = 15
allow-magic-value-types = ["str", "bytes", "complex", "float", "int"] allow-magic-value-types = ["str", "bytes", "complex", "float", "int"]
[tool.ruff.mccabe] [tool.ruff.lint.mccabe]
max-complexity = 15 max-complexity = 15
[tool.ruff.pydocstyle] [tool.ruff.lint.pydocstyle]
convention = "google" convention = "google"
[tool.ruff.pycodestyle] [tool.ruff.lint.pycodestyle]
max-doc-length = 100 max-doc-length = 100
###
### mypy ### mypy
###
[tool.mypy] [tool.mypy]
#plugins = ["pydantic.mypy"] #plugins = ["pydantic.mypy"]
@ -191,16 +209,20 @@ show_error_context = true
#init_typed = true #init_typed = true
#warn_required_dynamic_aliases = true #warn_required_dynamic_aliases = true
###
### pytest ### pytest
###
[tool.pytest.ini_options] [tool.pytest.ini_options]
pythonpath = ["src"] pythonpath = ["src"]
addopts = "--color=yes --exitfirst --verbose -ra" addopts = "--color=yes --exitfirst --verbose -ra"
#addopts = "--color=yes --exitfirst --verbose -ra --capture=tee-sys"
filterwarnings = [ filterwarnings = [
'ignore:Jupyter is migrating its paths to use standard platformdirs:DeprecationWarning', 'ignore:Jupyter is migrating its paths to use standard platformdirs:DeprecationWarning',
] ]
###
### coverage ### coverage
###
[tool.coverage.run] [tool.coverage.run]
source_pkgs = ["octodns_netbox_dns", "tests"] source_pkgs = ["octodns_netbox_dns", "tests"]
@ -209,8 +231,8 @@ parallel = true
omit = ["src/octodns_netbox_dns/__about__.py"] omit = ["src/octodns_netbox_dns/__about__.py"]
[tool.coverage.paths] [tool.coverage.paths]
testproj = ["src/octodns_netbox_dns", "*/octodns_netbox_dns/src/octodns_netbox_dns"] octodns_netbox_dns = ["src/octodns_netbox_dns", "*/octodns-netbox-dns/src/octodns_netbox_dns"]
tests = ["tests", "*/octodns_netbox_dns/tests"] tests = ["tests", "*/octodns-netbox-dns/tests"]
[tool.coverage.report] [tool.coverage.report]
# Regexes for lines to exclude from consideration # Regexes for lines to exclude from consideration

View file

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

View file

@ -2,20 +2,21 @@ import logging
from typing import Any, Literal from typing import Any, Literal
import dns.rdata import dns.rdata
import octodns.provider.base
import octodns.provider.plan
import octodns.record import octodns.record
import octodns.source.base
import octodns.zone import octodns.zone
import pynetbox.core.api import pynetbox.core.api
import pynetbox.core.response import pynetbox.core.response
class NetBoxDNSSource(octodns.source.base.BaseSource): class NetBoxDNSProvider(octodns.provider.base.BaseProvider):
""" """OctoDNS provider for NetboxDNS"""
OctoDNS provider for NetboxDNS
"""
SUPPORTS_GEO = False SUPPORTS_GEO = False
SUPPORTS_DYNAMIC = False SUPPORTS_DYNAMIC = False
SUPPORTS_ROOT_NS = True
SUPPORTS_MULTIVALUE_PTR = True
SUPPORTS: set[str] = { # noqa SUPPORTS: set[str] = { # noqa
"A", "A",
"AAAA", "AAAA",
@ -56,23 +57,26 @@ class NetBoxDNSSource(octodns.source.base.BaseSource):
ttl=3600, ttl=3600,
replace_duplicates=False, replace_duplicates=False,
make_absolute=False, make_absolute=False,
): disable_ptr=True,
""" *args,
Initialize the NetboxDNSSource **kwargs,
""" ) -> None:
self.log = logging.getLogger(f"NetboxDNSSource[{id}]") """initialize the NetBoxDNSProvider"""
self.log.debug(f"__init__: {id=}, {url=}, {view=}, {replace_duplicates=}, {make_absolute=}") self.log = logging.getLogger(f"NetBoxDNSProvider[{id}]")
super().__init__(id) self.log.debug(
f"__init__: {id=}, {url=}, {view=}, {replace_duplicates=}, {make_absolute=}, {disable_ptr=}, {args=}, {kwargs=}"
)
super().__init__(id, *args, **kwargs)
self.api = pynetbox.core.api.Api(url, token) self.api = pynetbox.core.api.Api(url, token)
self.nb_view = self._get_nb_view(view) self.nb_view = self._get_nb_view(view)
self.ttl = ttl self.ttl = ttl
self.replace_duplicates = replace_duplicates self.replace_duplicates = replace_duplicates
self.make_absolute = make_absolute self.make_absolute = make_absolute
self.disable_ptr = disable_ptr
def _make_absolute(self, value: str) -> str: def _make_absolute(self, value: str) -> str:
""" """return dns name with trailing dot to make it absolute
Return dns name with trailing dot to make it absolute
@param value: dns record value @param value: dns record value
@ -86,9 +90,18 @@ class NetBoxDNSSource(octodns.source.base.BaseSource):
return absolute_value return absolute_value
def _escape_semicolon(self, value: str) -> str:
fixed = value.replace(";", r"\;")
self.log.debug(rf"in='{value}', escaped='{fixed}'")
return fixed
def _unescape_semicolon(self, value: str) -> str:
fixed = value.replace(r"\\", "\\").replace(r"\;", ";")
self.log.debug(rf"in='{value}', unescaped='{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]:
""" """get the correct netbox view when requested
Get the correct netbox view when requested
@param view: `False` for no view, `None` for zones without a view, else the view name @param view: `False` for no view, `None` for zones without a view, else the view name
@ -110,8 +123,7 @@ class NetBoxDNSSource(octodns.source.base.BaseSource):
return {"view_id": nb_view.id} return {"view_id": nb_view.id}
def _get_nb_zone(self, name: str, view: dict[str, str | int]) -> pynetbox.core.response.Record: def _get_nb_zone(self, name: str, view: dict[str, str | int]) -> pynetbox.core.response.Record:
""" """given a zone name and a view name, look it up in NetBox.
Given a zone name and a view name, look it up in NetBox.
@param name: name of the dns zone @param name: name of the dns zone
@param view: the netbox view id in the api query format @param view: the netbox view id in the api query format
@ -127,15 +139,15 @@ class NetBoxDNSSource(octodns.source.base.BaseSource):
return nb_zone return nb_zone
def _format_rdata(self, rdata: dns.rdata.Rdata, raw_value: str) -> str | dict[str, Any]: def _format_rdata(self, rcd_type: str, rcd_value: str) -> str | dict[str, Any]:
""" """format netbox record values to correct octodns record values
Format netbox record values to correct octodns record values
@param rdata: rrdata record value @param rcd_type: record type
@param raw_value: raw record value @param rcd_value: record value
@return: formatted rrdata value @return: formatted rrdata value
""" """
rdata = dns.rdata.from_text("IN", rcd_type, rcd_value)
match rdata.rdtype.name: match rdata.rdtype.name:
case "A" | "AAAA": case "A" | "AAAA":
value = rdata.address value = rdata.address
@ -193,7 +205,7 @@ class NetBoxDNSSource(octodns.source.base.BaseSource):
} }
case "SPF" | "TXT": case "SPF" | "TXT":
value = raw_value.replace(";", r"\;") value = self._escape_semicolon(rcd_value)
case "SRV": case "SRV":
value = { value = {
@ -211,13 +223,12 @@ class NetBoxDNSSource(octodns.source.base.BaseSource):
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
def _format_nb_records(self, zone: octodns.zone.Zone) -> list[dict[str, Any]]: def _format_nb_records(self, zone: octodns.zone.Zone) -> list[dict[str, Any]]:
""" """format netbox dns records to the octodns format
Format netbox dns records to the octodns format
@param zone: octodns zone @param zone: octodns zone
@ -231,11 +242,11 @@ class NetBoxDNSSource(octodns.source.base.BaseSource):
raise LookupError raise LookupError
nb_records: pynetbox.core.response.RecordSet = self.api.plugins.netbox_dns.records.filter( nb_records: pynetbox.core.response.RecordSet = self.api.plugins.netbox_dns.records.filter(
zone_id=nb_zone.id zone_id=nb_zone.id, status="active"
) )
for nb_record in nb_records: for nb_record in nb_records:
rcd_name: str = nb_record.name if nb_record.name != "@" else "" rcd_name: str = "" if nb_record.name == "@" else nb_record.name
raw_value: str = nb_record.value if nb_record.value != "@" else nb_record.zone.name rcd_value: str = nb_record.zone.name if nb_record.value == "@" else nb_record.value
rcd_type: str = nb_record.type rcd_type: str = nb_record.type
rcd_ttl: int = nb_record.ttl or nb_zone.default_ttl rcd_ttl: int = nb_record.ttl or nb_zone.default_ttl
if nb_record.type == "NS": if nb_record.type == "NS":
@ -247,37 +258,40 @@ class NetBoxDNSSource(octodns.source.base.BaseSource):
"ttl": rcd_ttl, "ttl": rcd_ttl,
"values": [], "values": [],
} }
self.log.debug(rf"working on record={rcd_data}, value={rcd_value}")
self.log.debug(f"record data={rcd_data}")
rdata = dns.rdata.from_text("IN", nb_record.type, raw_value)
try: try:
rcd_value = self._format_rdata(rdata, raw_value) rcd_rdata = self._format_rdata(rcd_type, rcd_value)
except NotImplementedError: except NotImplementedError:
continue continue
except Exception as exc:
raise exc
if (rcd_name, rcd_type) not in records: if (rcd_name, rcd_type) not in records:
records[(rcd_name, rcd_type)] = rcd_data records[(rcd_name, rcd_type)] = rcd_data
records[(rcd_name, rcd_type)]["values"].append(rcd_value) records[(rcd_name, rcd_type)]["values"].append(rcd_rdata)
self.log.debug(rf"record data={records[(rcd_name, rcd_type)]}")
return list(records.values()) return list(records.values())
def populate( def populate(
self, zone: octodns.zone.Zone, target: bool = False, lenient: bool = False self, zone: octodns.zone.Zone, target: bool = False, lenient: bool = False
) -> None: ) -> bool:
""" """get all the records of a zone from NetBox and add them to the OctoDNS zone
Get all the records of a zone from NetBox and add them to the OctoDNS zone
@param zone: octodns zone @param zone: octodns zone
@param target: when `True`, load the current state of the provider. @param target: when `True`, load the current state of the provider.
@param lenient: when `True`, skip record validation and do a "best effort" load of data. @param lenient: when `True`, skip record validation and do a "best effort" load of data.
"""
self.log.info(f"populate -> '{zone.name}', target={target}, lenient={lenient}")
records = self._format_nb_records(zone) @return: true if the zone exists, else false.
"""
self.log.info(f"--> populate '{zone.name}', target={target}, lenient={lenient}")
try:
records = self._format_nb_records(zone)
except LookupError:
return False
for data in records: for data in records:
if len(data["values"]) == 1: if len(data["values"]) == 1:
data["value"] = data.pop("values")[0] data["value"] = data.pop("values")[0]
@ -291,3 +305,128 @@ class NetBoxDNSSource(octodns.source.base.BaseSource):
zone.add_record(record, lenient=lenient, replace=self.replace_duplicates) zone.add_record(record, lenient=lenient, replace=self.replace_duplicates)
self.log.info(f"populate -> found {len(zone.records)} records for zone '{zone.name}'") self.log.info(f"populate -> found {len(zone.records)} records for zone '{zone.name}'")
return True
def _format_changeset(self, change: Any) -> set[str]:
"""format the changeset
@param change: the raw changes
@return: the formatted/escaped changeset
"""
match change:
case octodns.record.ValueMixin():
changeset = {repr(change.value)[1:-1]}
case octodns.record.ValuesMixin():
changeset = {repr(v)[1:-1] for v in change.values}
case _:
raise ValueError
if change._type not in ["TXT", "SPF"]:
self.log.debug(f"{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:
"""filter out record types which the provider can't create in netbox
@param change: the planned change
@return: false if the change should be discarded, true if it should be kept.
"""
if change.record._type in ["SOA", "PTR", "NS"]:
self.log.debug(rf"record not supported as provider, ignoring: {change.record}")
return False
return True
def _apply(self, plan: octodns.provider.plan.Plan) -> None:
"""apply the changes to the NetBox DNS zone.
@param plan: the planned changes
@return: none
"""
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)
for change in plan.changes:
match change:
case octodns.record.Create():
rcd_name = "@" if change.new.name == "" else change.new.name
new_changeset = self._format_changeset(change.new)
for record in new_changeset:
self.log.debug(rf"ADD {change.new._type} {rcd_name} {record}")
self.api.plugins.netbox_dns.records.create(
zone=nb_zone.id,
name=rcd_name,
type=change.new._type,
ttl=change.new.ttl,
value=record,
disable_ptr=self.disable_ptr,
)
case octodns.record.Delete():
nb_records: pynetbox.core.response.RecordSet = (
self.api.plugins.netbox_dns.records.filter(
zone_id=nb_zone.id,
name=change.existing.name,
type=change.existing._type,
)
)
existing_changeset = self._format_changeset(change.existing)
for nb_record in nb_records:
for record in existing_changeset:
if nb_record.value != record:
continue
self.log.debug(
rf"DELETE {nb_record.type} {nb_record.name} {nb_record.value}"
)
nb_record.delete()
case octodns.record.Update():
rcd_name = "@" if change.existing.name == "" else change.existing.name
nb_records = self.api.plugins.netbox_dns.records.filter(
zone_id=nb_zone.id,
name=rcd_name,
type=change.existing._type,
)
existing_changeset = self._format_changeset(change.existing)
new_changeset = self._format_changeset(change.new)
to_delete = existing_changeset.difference(new_changeset)
to_update = existing_changeset.intersection(new_changeset)
to_create = new_changeset.difference(existing_changeset)
for nb_record in nb_records:
if nb_record.value in to_delete:
self.log.debug(
rf"DELETE {nb_record.type} {nb_record.name} {nb_record.value}"
)
nb_record.delete()
if nb_record.value in to_update:
self.log.debug(
rf"MODIFY (ttl) {nb_record.type} {nb_record.name} {nb_record.value}"
)
nb_record.ttl = change.new.ttl
nb_record.save()
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(
zone=nb_zone.id,
name=rcd_name,
type=change.new._type,
ttl=change.new.ttl,
value=record,
disable_ptr=self.disable_ptr,
)

View file

@ -0,0 +1,75 @@
from octodns_netbox_dns import NetBoxDNSProvider
DEFAULT_CONFIG = {
"id": 1,
"url": "https://localhost:8000",
"token": "",
"view": False,
"replace_duplicates": False,
"make_absolute": True,
}
def test_escape1():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"v=TLSRPTv1; rua=mailto:tlsrpt@example.com"
value = nbdns._escape_semicolon(rcd_value)
assert value == r"v=TLSRPTv1\; rua=mailto:tlsrpt@example.com"
def test_escape2():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"v=TLSRPTv1\; rua=mailto:tlsrpt@example.com"
value = nbdns._escape_semicolon(rcd_value)
assert value == r"v=TLSRPTv1\\; rua=mailto:tlsrpt@example.com"
def test_escape3():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"t=y\;o=~\;"
value = nbdns._escape_semicolon(rcd_value)
assert value == r"t=y\\;o=~\\;"
def test_escape4():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"t=y;o=~;"
value = nbdns._escape_semicolon(rcd_value)
assert value == r"t=y\;o=~\;"
def test_unescape1():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"v=TLSRPTv1\; rua=mailto:tlsrpt@example.com"
value = nbdns._unescape_semicolon(rcd_value)
assert value == r"v=TLSRPTv1; rua=mailto:tlsrpt@example.com"
def test_unescape2():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"v=TLSRPTv1\\; rua=mailto:tlsrpt@example.com"
value = nbdns._unescape_semicolon(rcd_value)
assert value == r"v=TLSRPTv1; rua=mailto:tlsrpt@example.com"
def test_unescape3():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"t=y\\;o=~\;"
value = nbdns._unescape_semicolon(rcd_value)
assert value == r"t=y;o=~;"
def test_unescape4():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_value = r"t=y;o=~;"
value = nbdns._unescape_semicolon(rcd_value)
assert value == r"t=y;o=~;"

View file

@ -0,0 +1,39 @@
from octodns_netbox_dns import NetBoxDNSProvider
class Change:
def __init__(self, rtype: str):
self.record = Record(rtype)
class Record:
def __init__(self, rtype: str):
self._type = rtype
DEFAULT_CONFIG = {
"id": 1,
"url": "https://localhost:8000",
"token": "",
"view": False,
"replace_duplicates": False,
"make_absolute": True,
}
def test1():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
for n in ["SOA", "NS", "PTR"]:
change = Change(n)
include_rcd = nbdns._include_change(change)
assert not include_rcd
def test2():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
for n in ["A", "AAA", "CNAME", "TXT", "MX"]:
change = Change(n)
include_rcd = nbdns._include_change(change)
assert include_rcd

103
tests/test_format_rdata.py Normal file
View file

@ -0,0 +1,103 @@
from octodns_netbox_dns import NetBoxDNSProvider
DEFAULT_CONFIG = {
"id": 1,
"url": "https://localhost:8000",
"token": "",
"view": False,
"replace_duplicates": False,
"make_absolute": True,
}
def test_a():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_type = "A"
rcd_value = "127.0.0.1"
value = nbdns._format_rdata(rcd_type, rcd_value)
assert value == "127.0.0.1"
def test_aaaa():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_type = "AAAA"
rcd_value = "fc07::1"
value = nbdns._format_rdata(rcd_type, rcd_value)
assert value == "fc07::1"
def test_mx():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_type = "MX"
rcd_value = "10 mx.example.com"
value = nbdns._format_rdata(rcd_type, rcd_value)
assert value == {
"preference": 10,
"exchange": "mx.example.com.",
}
def test_txt1():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_type = "TXT"
rcd_value = "v=TLSRPTv1; rua=mailto:tlsrpt@example.com"
value = nbdns._format_rdata(rcd_type, rcd_value)
assert value == r"v=TLSRPTv1\; rua=mailto:tlsrpt@example.com"
def test_txt2():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_type = "TXT"
rcd_value = r"v=TLSRPTv1\; rua=mailto:tlsrpt@example.com"
value = nbdns._format_rdata(rcd_type, rcd_value)
assert value == r"v=TLSRPTv1\\; rua=mailto:tlsrpt@example.com"
def test_txt3():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_type = "TXT"
rcd_value = r"v=DKIM1; k=rsa; p=/0f+sikE+k9ZKbn1BJu0/soWht/+Zd/nc/+Gy//mQ1B5sCKYKgAmYTSWkxRjFzkc6KAQhi+/IzaFogEV050wcscdC8Rc8lAQzDUFrMs2ZZK1vFtkwIDAQAB"
value = nbdns._format_rdata(rcd_type, rcd_value)
assert (
value
== r"v=DKIM1\; k=rsa\; p=/0f+sikE+k9ZKbn1BJu0/soWht/+Zd/nc/+Gy//mQ1B5sCKYKgAmYTSWkxRjFzkc6KAQhi+/IzaFogEV050wcscdC8Rc8lAQzDUFrMs2ZZK1vFtkwIDAQAB"
)
def test_txt4():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_type = "TXT"
rcd_value = r"t=y\;o=~\;"
value = nbdns._format_rdata(rcd_type, rcd_value)
assert value == r"t=y\\;o=~\\;"
def test_txt5():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_type = "TXT"
rcd_value = r"t=y;o=~;"
value = nbdns._format_rdata(rcd_type, rcd_value)
assert value == r"t=y\;o=~\;"
def test_srv():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd_type = "SRV"
rcd_value = r"0 5 25565 mc.example.com"
value = nbdns._format_rdata(rcd_type, rcd_value)
assert value == {
"priority": 0,
"weight": 5,
"port": 25565,
"target": "mc.example.com.",
}

View file

@ -0,0 +1,27 @@
from octodns_netbox_dns import NetBoxDNSProvider
DEFAULT_CONFIG = {
"id": 1,
"url": "https://localhost:8000",
"token": "",
"view": False,
"replace_duplicates": False,
"make_absolute": True,
}
def test1():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd = "example.com"
absolute = nbdns._make_absolute(rcd)
assert absolute == "example.com."
def test2():
nbdns = NetBoxDNSProvider(**DEFAULT_CONFIG)
rcd = "example.com."
absolute = nbdns._make_absolute(rcd)
assert absolute == "example.com."