saltext-opnsense 0.1.1.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- saltext_opnsense-0.1.1.dev0/.github/workflows/ci.yml +50 -0
- saltext_opnsense-0.1.1.dev0/.github/workflows/publish.yml +41 -0
- saltext_opnsense-0.1.1.dev0/.gitignore +20 -0
- saltext_opnsense-0.1.1.dev0/.pre-commit-config.yaml +23 -0
- saltext_opnsense-0.1.1.dev0/CHANGELOG.md +9 -0
- saltext_opnsense-0.1.1.dev0/CONTRIBUTING.md +128 -0
- saltext_opnsense-0.1.1.dev0/LICENSE +21 -0
- saltext_opnsense-0.1.1.dev0/MANIFEST.in +10 -0
- saltext_opnsense-0.1.1.dev0/Makefile +92 -0
- saltext_opnsense-0.1.1.dev0/PKG-INFO +137 -0
- saltext_opnsense-0.1.1.dev0/README.md +104 -0
- saltext_opnsense-0.1.1.dev0/changelog/README.md +10 -0
- saltext_opnsense-0.1.1.dev0/docs/ARCHITECTURE.md +239 -0
- saltext_opnsense-0.1.1.dev0/docs/DEVELOPMENT.md +90 -0
- saltext_opnsense-0.1.1.dev0/docs/FIREWALL_SAFETY.md +201 -0
- saltext_opnsense-0.1.1.dev0/docs/MAINTENANCE.md +197 -0
- saltext_opnsense-0.1.1.dev0/docs/Makefile +12 -0
- saltext_opnsense-0.1.1.dev0/docs/USAGE.md +704 -0
- saltext_opnsense-0.1.1.dev0/docs/conf.py +23 -0
- saltext_opnsense-0.1.1.dev0/docs/index.rst +14 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/pillars/file-based-proxy.yaml +57 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/pillars/full_example.sls +358 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/pillars/full_example.sls.example +542 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/pillars/opnsense-router.sls +15 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/pillars/opnsense.sls +112 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/pillars/top.sls.example +35 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/proxy/opnsense-router +8 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/states/acme_certificates.sls +201 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/states/bind_records.sls +42 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/states/delightful_aliases.sls +85 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/states/free_modules_demo.sls +50 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/states/host_overrides.sls +21 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/states/kea_reservations.sls +104 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/states/metrics.sls +73 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/states/unbound_aliases.sls +48 -0
- saltext_opnsense-0.1.1.dev0/docs/tutorials/states/unbound_aliases_batch.sls +57 -0
- saltext_opnsense-0.1.1.dev0/noxfile.py +29 -0
- saltext_opnsense-0.1.1.dev0/pillar.example +97 -0
- saltext_opnsense-0.1.1.dev0/pyproject.toml +101 -0
- saltext_opnsense-0.1.1.dev0/setup.cfg +4 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/__init__.py +6 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/grains/opnsense.py +46 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/modules/acmeclient.py +171 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/modules/bind.py +229 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/modules/dns.py +181 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/modules/firewall.py +105 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/modules/kea.py +206 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/modules/opnsense.py +531 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/modules/unbound.py +308 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/proxy/opnsense.py +164 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/states/bind.py +460 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/states/dns.py +352 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/states/opnsense.py +1986 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/states/unbound.py +539 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/utils/api_spec.py +158 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/utils/common.py +99 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/utils/controllers.json +4982 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/utils/models.json +16010 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/utils/models.py +239 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/utils/opnsense.py +658 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/version/__init__.py +10 -0
- saltext_opnsense-0.1.1.dev0/src/saltext/opnsense/version/_version.py +24 -0
- saltext_opnsense-0.1.1.dev0/src/saltext_opnsense.egg-info/PKG-INFO +137 -0
- saltext_opnsense-0.1.1.dev0/src/saltext_opnsense.egg-info/SOURCES.txt +92 -0
- saltext_opnsense-0.1.1.dev0/src/saltext_opnsense.egg-info/dependency_links.txt +1 -0
- saltext_opnsense-0.1.1.dev0/src/saltext_opnsense.egg-info/entry_points.txt +2 -0
- saltext_opnsense-0.1.1.dev0/src/saltext_opnsense.egg-info/requires.txt +3 -0
- saltext_opnsense-0.1.1.dev0/src/saltext_opnsense.egg-info/scm_file_list.json +88 -0
- saltext_opnsense-0.1.1.dev0/src/saltext_opnsense.egg-info/scm_version.json +8 -0
- saltext_opnsense-0.1.1.dev0/src/saltext_opnsense.egg-info/top_level.txt +1 -0
- saltext_opnsense-0.1.1.dev0/tests/__init__.py +0 -0
- saltext_opnsense-0.1.1.dev0/tests/conftest.py +41 -0
- saltext_opnsense-0.1.1.dev0/tests/integration/README.md +42 -0
- saltext_opnsense-0.1.1.dev0/tests/integration/__init__.py +0 -0
- saltext_opnsense-0.1.1.dev0/tests/integration/test_live_opnsense.py +45 -0
- saltext_opnsense-0.1.1.dev0/tests/unit/modules/test_exec_helpers.py +165 -0
- saltext_opnsense-0.1.1.dev0/tests/unit/modules/test_exec_wrappers_generated.py +75 -0
- saltext_opnsense-0.1.1.dev0/tests/unit/modules/test_modules_opnsense.py +22 -0
- saltext_opnsense-0.1.1.dev0/tests/unit/proxy/test_proxy_opnsense.py +34 -0
- saltext_opnsense-0.1.1.dev0/tests/unit/states/test_state_helpers.py +239 -0
- saltext_opnsense-0.1.1.dev0/tests/unit/states/test_state_reconfigure.py +456 -0
- saltext_opnsense-0.1.1.dev0/tests/unit/states/test_state_wrappers_generated.py +54 -0
- saltext_opnsense-0.1.1.dev0/tests/unit/states/test_states_opnsense.py +279 -0
- saltext_opnsense-0.1.1.dev0/tests/unit/test_client.py +393 -0
- saltext_opnsense-0.1.1.dev0/tests/unit/test_free_modules_import.py +82 -0
- saltext_opnsense-0.1.1.dev0/tools/README.md +40 -0
- saltext_opnsense-0.1.1.dev0/tools/generate_all.py +275 -0
- saltext_opnsense-0.1.1.dev0/tools/generate_models.py +376 -0
- saltext_opnsense-0.1.1.dev0/tools/generate_pillar_example.py +100 -0
- saltext_opnsense-0.1.1.dev0/tools/generate_spec.py +177 -0
- saltext_opnsense-0.1.1.dev0/tools/generate_wrappers.py +963 -0
- saltext_opnsense-0.1.1.dev0/tools/sync_extmods.py +158 -0
- saltext_opnsense-0.1.1.dev0/tools/test_live.py +67 -0
- saltext_opnsense-0.1.1.dev0/tools/verify_import.py +76 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
lint:
|
|
10
|
+
name: Lint & Format Check
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.11"
|
|
17
|
+
- run: pip install ruff
|
|
18
|
+
- run: ruff check src tests tools
|
|
19
|
+
- run: ruff format --check src tests tools
|
|
20
|
+
|
|
21
|
+
unit:
|
|
22
|
+
name: Unit Tests (Python ${{ matrix.python-version }})
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
strategy:
|
|
25
|
+
fail-fast: false
|
|
26
|
+
matrix:
|
|
27
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
- uses: actions/setup-python@v5
|
|
31
|
+
with:
|
|
32
|
+
python-version: ${{ matrix.python-version }}
|
|
33
|
+
- run: pip install -e .[dev] || (pip install -e . && pip install pytest requests salt)
|
|
34
|
+
- run: PYTHONPATH=src pytest tests/unit -v
|
|
35
|
+
|
|
36
|
+
spec-drift:
|
|
37
|
+
name: Spec Integrity Check
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v4
|
|
41
|
+
- uses: actions/setup-python@v5
|
|
42
|
+
with:
|
|
43
|
+
python-version: "3.11"
|
|
44
|
+
- run: pip install requests
|
|
45
|
+
- name: Verify Spec Consistency
|
|
46
|
+
run: |
|
|
47
|
+
CORE_REF=$(python3 -c "import json,pathlib; print(json.loads(pathlib.Path('src/saltext/opnsense/utils/controllers.json').read_text()).get('meta',{}).get('core_ref','25.7'))")
|
|
48
|
+
echo "Verifying spec against upstream tag: ${CORE_REF}"
|
|
49
|
+
python tools/generate_spec.py --core-ref "${CORE_REF}" --plugins-ref "${CORE_REF}" --output /tmp/controllers.json
|
|
50
|
+
diff -u tools/controllers.json /tmp/controllers.json || (echo "controllers.json drift detected — run make bump CORE=${CORE_REF}" && exit 1)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*.*.*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build-and-publish:
|
|
10
|
+
name: Build and publish to PyPI
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
permissions:
|
|
13
|
+
# Required for Trusted Publishing (OIDC) to PyPI
|
|
14
|
+
id-token: write
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout Repository
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0 # Required for setuptools_scm to determine version from git tags
|
|
22
|
+
|
|
23
|
+
- name: Set up Python
|
|
24
|
+
uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.11"
|
|
27
|
+
|
|
28
|
+
- name: Install build tools
|
|
29
|
+
run: python -m pip install --upgrade pip build twine
|
|
30
|
+
|
|
31
|
+
- name: Build sdist and wheel
|
|
32
|
+
run: python -m build
|
|
33
|
+
|
|
34
|
+
- name: Check build artifacts
|
|
35
|
+
run: twine check dist/*
|
|
36
|
+
|
|
37
|
+
- name: Publish to PyPI
|
|
38
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
39
|
+
# If you are using an API token instead of OIDC, uncomment the following:
|
|
40
|
+
# with:
|
|
41
|
+
# password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.pyc
|
|
3
|
+
*.pyo
|
|
4
|
+
*.pyd
|
|
5
|
+
*.egg-info/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
.eggs/
|
|
9
|
+
.pytest_cache/
|
|
10
|
+
.nox/
|
|
11
|
+
venv/
|
|
12
|
+
.venv/
|
|
13
|
+
controllers.json.bak
|
|
14
|
+
/tmp/
|
|
15
|
+
tools/tmp/
|
|
16
|
+
# generated ergonomic wrappers - dynamic injection covers all, keep repo minimal
|
|
17
|
+
src/saltext/opnsense/modules/opnsense_*.py
|
|
18
|
+
src/saltext/opnsense/states/opnsense_*.py
|
|
19
|
+
# but keep generic opnsense.py (excluded above would ignore generic too? pattern is opnsense_*.py, not opnsense.py, so generic safe)
|
|
20
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.14.8
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff
|
|
6
|
+
args: [--fix]
|
|
7
|
+
types: [python]
|
|
8
|
+
- id: ruff-format
|
|
9
|
+
types: [python]
|
|
10
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
11
|
+
rev: v6.0.0
|
|
12
|
+
hooks:
|
|
13
|
+
- id: trailing-whitespace
|
|
14
|
+
- id: end-of-file-fixer
|
|
15
|
+
- id: check-yaml
|
|
16
|
+
- id: check-added-large-files
|
|
17
|
+
args: ['--maxkb=500']
|
|
18
|
+
- id: check-merge-conflict
|
|
19
|
+
|
|
20
|
+
# Setup:
|
|
21
|
+
# pip install pre-commit
|
|
22
|
+
# pre-commit install
|
|
23
|
+
# pre-commit run --all-files
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
This changelog is managed via towncrier.
|
|
4
|
+
|
|
5
|
+
Fragments in `changelog/` (feature, bugfix, doc, removal, misc) are concatenated into this file via `towncrier build`.
|
|
6
|
+
|
|
7
|
+
## 0.1.0 (unreleased)
|
|
8
|
+
|
|
9
|
+
- Initial scaffold: generic templated `opnsense` execution + state modules, proxy minion, utils client, codegen tool for all API endpoints, unit tests Salt way, examples replacing `query.sh` / `sync-bind-zone.sh`
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Contributing — saltext-opnsense
|
|
2
|
+
|
|
3
|
+
## Quick start
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
python3 -m venv .venv
|
|
7
|
+
source .venv/bin/activate
|
|
8
|
+
pip install -e ".[dev]" # dev: pytest, ruff, towncrier, nox
|
|
9
|
+
# or:
|
|
10
|
+
pip install -e . && pip install pytest ruff towncrier requests "salt>=3008"
|
|
11
|
+
|
|
12
|
+
# generate everything (spec + wrappers + verify + sync)
|
|
13
|
+
make gen-all
|
|
14
|
+
# or manually:
|
|
15
|
+
make gen-spec
|
|
16
|
+
make gen-wrappers
|
|
17
|
+
make verify
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Running tests
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# unit (no live OPNsense, mocked)
|
|
24
|
+
PYTHONPATH=src pytest tests/unit -v
|
|
25
|
+
|
|
26
|
+
# import proof: 76 exec + 76 state + 1816 dynamic wrappers
|
|
27
|
+
PYTHONPATH=src python3 tools/verify_import.py
|
|
28
|
+
PYTHONPATH=src python3 tools/verify_import.py
|
|
29
|
+
|
|
30
|
+
# lint
|
|
31
|
+
ruff check src tests tools
|
|
32
|
+
ruff format src tests tools --check
|
|
33
|
+
|
|
34
|
+
# full nox matrix (needs salt installed)
|
|
35
|
+
nox -e tests
|
|
36
|
+
nox -e lint
|
|
37
|
+
|
|
38
|
+
# live smoke (read-only, no Salt) against opnsense-router
|
|
39
|
+
OPNSENSE_HOST=opnsense.example.com OPNSENSE_API_KEY=... OPNSENSE_API_SECRET=... python tools/test_live.py
|
|
40
|
+
# or:
|
|
41
|
+
python tools/test_live.py --host opnsense.example.com --key $KEY --secret $SECRET
|
|
42
|
+
|
|
43
|
+
# integration (gated, live)
|
|
44
|
+
OPNSENSE_LIVE_TEST=1 PYTHONPATH=src pytest tests/integration -v -k live
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Adding a new test
|
|
48
|
+
|
|
49
|
+
Tests live in `tests/unit/`:
|
|
50
|
+
- `utils/test_client.py` — mock `requests.Session.request`, test `OPNsenseClient.search/get/add`
|
|
51
|
+
- `modules/test_modules_opnsense.py` — mock `_get_client`, test execution module proxy/direct branching
|
|
52
|
+
- `states/test_opnsense.py` — mock `__salt__` (search/add/set/del), test `item_present/absent` idempotency
|
|
53
|
+
- `test_free_modules_import.py` — proves all 76 generated wrappers import
|
|
54
|
+
|
|
55
|
+
Example:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from unittest.mock import MagicMock, patch
|
|
59
|
+
from saltext.opnsense.utils.opnsense import OPNsenseClient, OPNsenseClientConfig
|
|
60
|
+
|
|
61
|
+
@patch("saltext.opnsense.utils.opnsense.requests.Session.request")
|
|
62
|
+
def test_my_feature(mock_req):
|
|
63
|
+
mock_resp = MagicMock()
|
|
64
|
+
mock_resp.status_code = 200
|
|
65
|
+
mock_resp.json.return_value = {"rows": [], "total": 0}
|
|
66
|
+
mock_resp.text = '{"rows":[]}'
|
|
67
|
+
mock_req.return_value = mock_resp
|
|
68
|
+
cfg = OPNsenseClientConfig(host="opnsense-router", api_key="a", api_secret="b")
|
|
69
|
+
client = OPNsenseClient(cfg)
|
|
70
|
+
res = client.search("unbound", "settings", "host_alias", search_phrase="www")
|
|
71
|
+
assert "rows" in res
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Run `pytest tests/unit -v --collect-only` to verify discovery.
|
|
75
|
+
|
|
76
|
+
## Regenerating code
|
|
77
|
+
|
|
78
|
+
- Spec: `tools/generate_spec.py --core-ref 25.7 --plugins-ref 25.7 --output src/saltext/opnsense/utils/controllers.json`
|
|
79
|
+
- Wrappers: `tools/generate_wrappers.py` (emits 76 exec + 76 state modules)
|
|
80
|
+
- Verify: `tools/verify_import.py`
|
|
81
|
+
`make gen-all` does all three in order.
|
|
82
|
+
|
|
83
|
+
## Changelog — towncrier
|
|
84
|
+
|
|
85
|
+
We use towncrier. Fragments live in `changelog/`:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
changelog.feature. — new features
|
|
89
|
+
changelog.bugfix. — bug fixes
|
|
90
|
+
changelog.doc. — docs
|
|
91
|
+
changelog.removal. — deprecation/removal
|
|
92
|
+
changelog.misc. — trivial (no changelog entry)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Create fragment:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
towncrier create 123.feature --edit
|
|
99
|
+
# writes changelog/123.feature.md with your text
|
|
100
|
+
# commit it with your PR
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Build on release:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
towncrier build --version 0.2.0
|
|
107
|
+
# appends to CHANGELOG.md, deletes fragments
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
A changelog fragment is optional for small PRs but encouraged.
|
|
111
|
+
|
|
112
|
+
## Submitting PR
|
|
113
|
+
|
|
114
|
+
1. Branch from `main`: `git checkout -b fix/unbound-search`
|
|
115
|
+
2. Make change + regenerate if needed: `make gen-all`
|
|
116
|
+
3. Run `PYTHONPATH=src pytest tests/unit -v` and `tools/verify_import.py`
|
|
117
|
+
4. Run `ruff check src tests tools`
|
|
118
|
+
5. Add towncrier fragment: `towncrier create <pr>.feature --edit`
|
|
119
|
+
6. Push, open PR to `main` at `https://github.com/primechuck/saltext-opnsense`. Mention Renovate / OPNsense version if relevant.
|
|
120
|
+
|
|
121
|
+
See `docs/MAINTENANCE.md` for OPNsense release sprint workflow.
|
|
122
|
+
|
|
123
|
+
## Code style
|
|
124
|
+
|
|
125
|
+
- `ruff` with `line-length=100`, `target-version=py310`
|
|
126
|
+
- Builtins allowed: `__opts__`, `__salt__`, `__proxy__`, `__context__`, `__grains__`, `__utils__` (declared in `pyproject.toml`)
|
|
127
|
+
- No comments unless comstream — rely on docstrings in generated wrappers
|
|
128
|
+
- Prefer `file-based` vs `pip install` note in docs when adding new modules
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 saltext-opnsense Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
include README.md LICENSE CHANGELOG.md
|
|
2
|
+
include src/saltext/opnsense/utils/controllers.json
|
|
3
|
+
include src/saltext/opnsense/utils/models.json
|
|
4
|
+
recursive-include src/saltext/opnsense/utils *.json
|
|
5
|
+
recursive-include tools *.json
|
|
6
|
+
include pyproject.toml
|
|
7
|
+
global-exclude __pycache__
|
|
8
|
+
global-exclude *.py[cod]
|
|
9
|
+
prune .pytest_cache
|
|
10
|
+
prune .nox
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Makefile for saltext-opnsense — maintainable codegen pipeline
|
|
2
|
+
# Single entrypoint: make gen-all (wraps tools/generate_all.py)
|
|
3
|
+
# See docs/MAINTENANCE.md for full sprint checklist
|
|
4
|
+
|
|
5
|
+
PYTHON ?= python3
|
|
6
|
+
CORE_REF ?= 25.7
|
|
7
|
+
PLUGINS_REF ?= 25.7
|
|
8
|
+
CORE ?= $(CORE_REF)
|
|
9
|
+
ARGS ?=
|
|
10
|
+
DRY ?=
|
|
11
|
+
|
|
12
|
+
TOOLS_DIR := tools
|
|
13
|
+
SRC_UTILS := src/saltext/opnsense/utils
|
|
14
|
+
SRC_JSON := $(SRC_UTILS)/controllers.json
|
|
15
|
+
SRC_MODELS_JSON := $(SRC_UTILS)/models.json
|
|
16
|
+
|
|
17
|
+
.PHONY: help gen-spec gen-models gen-wrappers bump sync verify test lint gen-all clean
|
|
18
|
+
|
|
19
|
+
help:
|
|
20
|
+
@echo "saltext-opnsense maintenance"
|
|
21
|
+
@echo ""
|
|
22
|
+
@echo "Targets:"
|
|
23
|
+
@echo " gen-spec - Clone core/plugins @ REF and parse controllers.php -> src/.../utils/controllers.json"
|
|
24
|
+
@echo " gen-models - Parse Model XML -> src/.../utils/models.json"
|
|
25
|
+
@echo " gen-wrappers - Spec -> 76 exec + 76 state wrappers (auto-generated)"
|
|
26
|
+
@echo " bump - Upstream version sprint: make bump CORE=25.7"
|
|
27
|
+
@echo " sync - Copy src -> extmods directories for gitfs file-based install"
|
|
28
|
+
@echo " verify - Prove all 76 modules import (exec+state+dynamic)"
|
|
29
|
+
@echo " test - pytest tests/unit -q"
|
|
30
|
+
@echo " lint - ruff check src tests tools"
|
|
31
|
+
@echo " gen-all - Full pipeline: spec -> wrappers -> sync -> verify -> test (via generate_all.py)"
|
|
32
|
+
@echo " clean - Remove caches, /tmp/opnsense-spec, pycache"
|
|
33
|
+
@echo ""
|
|
34
|
+
@echo "Variables:"
|
|
35
|
+
@echo " CORE_REF, PLUGINS_REF (default 25.7) e.g. make gen-all CORE_REF=25.7 PLUGINS_REF=25.7"
|
|
36
|
+
@echo " CORE (alias for CORE_REF/PLUGINS_REF) e.g. make bump CORE=25.7"
|
|
37
|
+
@echo ""
|
|
38
|
+
@echo "Examples:"
|
|
39
|
+
@echo " make bump CORE=25.7"
|
|
40
|
+
@echo " make gen-all CORE_REF=25.7 PLUGINS_REF=25.7"
|
|
41
|
+
@echo " make gen-wrappers && make verify"
|
|
42
|
+
|
|
43
|
+
gen-spec:
|
|
44
|
+
@mkdir -p $(SRC_UTILS)
|
|
45
|
+
$(PYTHON) $(TOOLS_DIR)/generate_spec.py --core-ref $(CORE_REF) --plugins-ref $(PLUGINS_REF) --output $(SRC_JSON)
|
|
46
|
+
@jq .meta $(SRC_JSON) 2>/dev/null || python3 -c "import json,pathlib; print(json.loads(pathlib.Path('$(SRC_JSON)').read_text()).get('meta'))"
|
|
47
|
+
|
|
48
|
+
gen-models:
|
|
49
|
+
@mkdir -p $(SRC_UTILS)
|
|
50
|
+
@if [ -d /tmp/opnsense-spec/core ] && [ -d /tmp/opnsense-spec/plugins ]; then \
|
|
51
|
+
echo "Using cached clones /tmp/opnsense-spec/core and /tmp/opnsense-spec/plugins"; \
|
|
52
|
+
$(PYTHON) $(TOOLS_DIR)/generate_models.py --core /tmp/opnsense-spec/core --plugins /tmp/opnsense-spec/plugins --output $(SRC_MODELS_JSON); \
|
|
53
|
+
else \
|
|
54
|
+
$(PYTHON) $(TOOLS_DIR)/generate_models.py --core-ref $(CORE_REF) --plugins-ref $(PLUGINS_REF) --output $(SRC_MODELS_JSON); \
|
|
55
|
+
fi
|
|
56
|
+
@echo "Wrote $(SRC_MODELS_JSON)"
|
|
57
|
+
|
|
58
|
+
gen-wrappers:
|
|
59
|
+
$(PYTHON) $(TOOLS_DIR)/generate_wrappers.py
|
|
60
|
+
|
|
61
|
+
bump:
|
|
62
|
+
$(PYTHON) $(TOOLS_DIR)/generate_spec.py --core-ref $(CORE) --plugins-ref $(CORE) --output $(SRC_JSON)
|
|
63
|
+
cp $(SRC_JSON) $(TOOLS_DIR)/controllers.json
|
|
64
|
+
$(PYTHON) $(TOOLS_DIR)/generate_wrappers.py
|
|
65
|
+
PYTHONPATH=src $(PYTHON) $(TOOLS_DIR)/verify_import.py
|
|
66
|
+
|
|
67
|
+
sync:
|
|
68
|
+
$(PYTHON) $(TOOLS_DIR)/sync_extmods.py --copy
|
|
69
|
+
|
|
70
|
+
verify:
|
|
71
|
+
PYTHONPATH=src $(PYTHON) $(TOOLS_DIR)/verify_import.py
|
|
72
|
+
|
|
73
|
+
test:
|
|
74
|
+
PYTHONPATH=src $(PYTHON) -m pytest tests/unit -q
|
|
75
|
+
|
|
76
|
+
lint:
|
|
77
|
+
$(PYTHON) -m ruff check src tests tools || ruff check src tests tools
|
|
78
|
+
|
|
79
|
+
gen-all:
|
|
80
|
+
ifeq ($(DRY),1)
|
|
81
|
+
$(PYTHON) $(TOOLS_DIR)/generate_all.py --core-ref $(CORE_REF) --plugins-ref $(PLUGINS_REF) --dry-run $(ARGS)
|
|
82
|
+
else
|
|
83
|
+
$(PYTHON) $(TOOLS_DIR)/generate_all.py --core-ref $(CORE_REF) --plugins-ref $(PLUGINS_REF) $(ARGS)
|
|
84
|
+
endif
|
|
85
|
+
|
|
86
|
+
clean:
|
|
87
|
+
rm -rf /tmp/opnsense-spec tools/tmp __pycache__ src/__pycache__ .pytest_cache .nox build dist *.egg-info src/*.egg-info
|
|
88
|
+
rm -rf src/saltext/opnsense/__pycache__ src/saltext/opnsense/modules/__pycache__ src/saltext/opnsense/states/__pycache__ src/saltext/opnsense/utils/__pycache__
|
|
89
|
+
rm -rf src/saltext/opnsense/proxy/__pycache__ src/saltext/opnsense/grains/__pycache__ tests/__pycache__ tests/unit/__pycache__
|
|
90
|
+
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
|
|
91
|
+
find . -type f -name "*.pyc" -delete 2>/dev/null || true
|
|
92
|
+
@echo "Cleaned caches. Generated wrappers/json kept."
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: saltext-opnsense
|
|
3
|
+
Version: 0.1.1.dev0
|
|
4
|
+
Summary: Salt extension for managing OPNsense via its API - templated, 3008+ ready, with dynamic wrappers, file-based install, and Vault support
|
|
5
|
+
Author-email: David Bierce <david@bierce.org>
|
|
6
|
+
Maintainer-email: David Bierce <david@bierce.org>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/primechuck/saltext-opnsense
|
|
9
|
+
Project-URL: Repository, https://github.com/primechuck/saltext-opnsense
|
|
10
|
+
Project-URL: Issues, https://github.com/primechuck/saltext-opnsense/issues
|
|
11
|
+
Project-URL: Documentation, https://primechuck.github.io/saltext-opnsense/
|
|
12
|
+
Keywords: salt,salt-extension,saltext,opnsense,firewall,api,unbound,bind,kea,acme
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: System Administrators
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Topic :: System :: Networking :: Firewalls
|
|
17
|
+
Classifier: Topic :: System :: Systems Administration
|
|
18
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: salt>=3008
|
|
30
|
+
Requires-Dist: requests>=2.28
|
|
31
|
+
Requires-Dist: urllib3>=1.26
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# saltext-opnsense
|
|
35
|
+
|
|
36
|
+
SaltStack extension for managing OPNsense firewalls via the REST API.
|
|
37
|
+
|
|
38
|
+
Manage OPNsense services (Unbound DNS, Kea DHCP, BIND, ACME certs, firewall aliases, interfaces) declaratively with Salt states or programmatically via execution modules. API bindings are generated directly from upstream OPNsense schemas.
|
|
39
|
+
|
|
40
|
+
> **Target Release**: Built for **OPNsense 25.7** (76 modules, ~1,816 API endpoints).
|
|
41
|
+
> **Core Design Goal**: Maintainer laziness. Never hand-code API wrappers. When OPNsense ships a new release, all 76 modules and 1,800+ endpoints are regenerated directly from upstream schemas via `make bump CORE=25.7`.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
- **Execution Modules**: Direct API calls to OPNsense controllers and actions.
|
|
47
|
+
- **State Modules**: Declarative states for OPNsense resources (`item_present`, `item_absent`, DNS aliases, DHCP leases, ACME certs).
|
|
48
|
+
- **Proxy Minion Support**: Agentless management of OPNsense hardware and VMs.
|
|
49
|
+
- **Auto-Generated Spec**: Keeps up with upstream OPNsense releases without manual code edits.
|
|
50
|
+
- **Diagnostics (`opnsense.doctor`)**: Quick CLI check for credentials, API connectivity, and firmware status.
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
53
|
+
|
|
54
|
+
### 1. Installation
|
|
55
|
+
|
|
56
|
+
Install on the Salt Master and Proxy Minion:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
salt-pip install saltext-opnsense
|
|
60
|
+
salt '*' saltutil.sync_all
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Or copy directly into Salt's `file_roots` (for environments without `salt-pip`):
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
python3 tools/sync_extmods.py --copy
|
|
67
|
+
salt '*' saltutil.sync_all
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. Configuration
|
|
71
|
+
|
|
72
|
+
Define your OPNsense target in Pillar (e.g. `/srv/pillar/opnsense.sls`). See [pillar.example](file:///Users/dbierce/GitHub/configurations/projects/saltext-opnsense-review/pillar.example) for details.
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
proxy:
|
|
76
|
+
proxytype: opnsense
|
|
77
|
+
host: opnsense.example.com
|
|
78
|
+
proto: https
|
|
79
|
+
api_key: "your_api_key"
|
|
80
|
+
api_secret: "your_api_secret"
|
|
81
|
+
# verify_ssl: false # Optional; defaults to true
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 3. Diagnostics
|
|
85
|
+
|
|
86
|
+
Verify connectivity and credential resolution:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
salt opnsense-router opnsense.doctor
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Usage
|
|
93
|
+
|
|
94
|
+
### Execution Module
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Search Unbound DNS host aliases
|
|
98
|
+
salt opnsense-router opnsense.search unbound settings host_alias
|
|
99
|
+
|
|
100
|
+
# Call endpoint directly
|
|
101
|
+
salt opnsense-router opnsense_unbound.search_host_alias
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### State Module
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
# Ensure an Unbound Host Alias exists
|
|
108
|
+
www_alias:
|
|
109
|
+
opnsense_unbound.host_alias_present:
|
|
110
|
+
- data:
|
|
111
|
+
enabled: "1"
|
|
112
|
+
hostname: www
|
|
113
|
+
domain: example.com
|
|
114
|
+
- reconfigure: unbound/service/reconfigure
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Maintenance & Upgrades
|
|
118
|
+
|
|
119
|
+
API spec bindings are generated from upstream `opnsense/core` and `opnsense/plugins`.
|
|
120
|
+
|
|
121
|
+
When OPNsense ships a new release (e.g. `26.1`), regenerate bindings with:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
make bump CORE=26.1
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
For developer documentation and full maintenance details, see [docs/MAINTENANCE.md](file:///Users/dbierce/GitHub/configurations/projects/saltext-opnsense-review/docs/MAINTENANCE.md).
|
|
128
|
+
|
|
129
|
+
## Testing
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Run unit tests
|
|
133
|
+
PYTHONPATH=src pytest tests/unit -v
|
|
134
|
+
|
|
135
|
+
# Verify module imports
|
|
136
|
+
PYTHONPATH=src python3 tools/verify_import.py
|
|
137
|
+
```
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# saltext-opnsense
|
|
2
|
+
|
|
3
|
+
SaltStack extension for managing OPNsense firewalls via the REST API.
|
|
4
|
+
|
|
5
|
+
Manage OPNsense services (Unbound DNS, Kea DHCP, BIND, ACME certs, firewall aliases, interfaces) declaratively with Salt states or programmatically via execution modules. API bindings are generated directly from upstream OPNsense schemas.
|
|
6
|
+
|
|
7
|
+
> **Target Release**: Built for **OPNsense 25.7** (76 modules, ~1,816 API endpoints).
|
|
8
|
+
> **Core Design Goal**: Maintainer laziness. Never hand-code API wrappers. When OPNsense ships a new release, all 76 modules and 1,800+ endpoints are regenerated directly from upstream schemas via `make bump CORE=25.7`.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Execution Modules**: Direct API calls to OPNsense controllers and actions.
|
|
14
|
+
- **State Modules**: Declarative states for OPNsense resources (`item_present`, `item_absent`, DNS aliases, DHCP leases, ACME certs).
|
|
15
|
+
- **Proxy Minion Support**: Agentless management of OPNsense hardware and VMs.
|
|
16
|
+
- **Auto-Generated Spec**: Keeps up with upstream OPNsense releases without manual code edits.
|
|
17
|
+
- **Diagnostics (`opnsense.doctor`)**: Quick CLI check for credentials, API connectivity, and firmware status.
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
### 1. Installation
|
|
22
|
+
|
|
23
|
+
Install on the Salt Master and Proxy Minion:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
salt-pip install saltext-opnsense
|
|
27
|
+
salt '*' saltutil.sync_all
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Or copy directly into Salt's `file_roots` (for environments without `salt-pip`):
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
python3 tools/sync_extmods.py --copy
|
|
34
|
+
salt '*' saltutil.sync_all
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2. Configuration
|
|
38
|
+
|
|
39
|
+
Define your OPNsense target in Pillar (e.g. `/srv/pillar/opnsense.sls`). See [pillar.example](file:///Users/dbierce/GitHub/configurations/projects/saltext-opnsense-review/pillar.example) for details.
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
proxy:
|
|
43
|
+
proxytype: opnsense
|
|
44
|
+
host: opnsense.example.com
|
|
45
|
+
proto: https
|
|
46
|
+
api_key: "your_api_key"
|
|
47
|
+
api_secret: "your_api_secret"
|
|
48
|
+
# verify_ssl: false # Optional; defaults to true
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 3. Diagnostics
|
|
52
|
+
|
|
53
|
+
Verify connectivity and credential resolution:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
salt opnsense-router opnsense.doctor
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Usage
|
|
60
|
+
|
|
61
|
+
### Execution Module
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Search Unbound DNS host aliases
|
|
65
|
+
salt opnsense-router opnsense.search unbound settings host_alias
|
|
66
|
+
|
|
67
|
+
# Call endpoint directly
|
|
68
|
+
salt opnsense-router opnsense_unbound.search_host_alias
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### State Module
|
|
72
|
+
|
|
73
|
+
```yaml
|
|
74
|
+
# Ensure an Unbound Host Alias exists
|
|
75
|
+
www_alias:
|
|
76
|
+
opnsense_unbound.host_alias_present:
|
|
77
|
+
- data:
|
|
78
|
+
enabled: "1"
|
|
79
|
+
hostname: www
|
|
80
|
+
domain: example.com
|
|
81
|
+
- reconfigure: unbound/service/reconfigure
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Maintenance & Upgrades
|
|
85
|
+
|
|
86
|
+
API spec bindings are generated from upstream `opnsense/core` and `opnsense/plugins`.
|
|
87
|
+
|
|
88
|
+
When OPNsense ships a new release (e.g. `26.1`), regenerate bindings with:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
make bump CORE=26.1
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
For developer documentation and full maintenance details, see [docs/MAINTENANCE.md](file:///Users/dbierce/GitHub/configurations/projects/saltext-opnsense-review/docs/MAINTENANCE.md).
|
|
95
|
+
|
|
96
|
+
## Testing
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Run unit tests
|
|
100
|
+
PYTHONPATH=src pytest tests/unit -v
|
|
101
|
+
|
|
102
|
+
# Verify module imports
|
|
103
|
+
PYTHONPATH=src python3 tools/verify_import.py
|
|
104
|
+
```
|