mreg-api 0.3.0__tar.gz → 0.4.0__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.
- mreg_api-0.4.0/.github/workflows/docs.yml +29 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/.markdownlint.json +5 -1
- {mreg_api-0.3.0 → mreg_api-0.4.0}/CHANGELOG.md +32 -1
- {mreg_api-0.3.0 → mreg_api-0.4.0}/PKG-INFO +23 -2
- mreg_api-0.4.0/README.md +44 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/TESTING.md +27 -11
- {mreg_api-0.3.0 → mreg_api-0.4.0}/ci/docker-compose.yml +1 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/ci/run_tests.sh +31 -4
- mreg_api-0.4.0/docs/guides/authentication.md +62 -0
- mreg_api-0.4.0/docs/guides/caching.md +63 -0
- mreg_api-0.4.0/docs/guides/configuration.md +64 -0
- mreg_api-0.4.0/docs/guides/eventlog.md +52 -0
- mreg_api-0.4.0/docs/guides/requesthistory.md +15 -0
- mreg_api-0.4.0/docs/guides/resources.md +163 -0
- mreg_api-0.4.0/docs/index.md +50 -0
- mreg_api-0.4.0/docs/quick-start.md +122 -0
- mreg_api-0.4.0/docs/reference/cache.md +15 -0
- mreg_api-0.4.0/docs/reference/client.md +14 -0
- mreg_api-0.4.0/docs/reference/events.md +25 -0
- mreg_api-0.4.0/docs/reference/exceptions.md +12 -0
- mreg_api-0.4.0/docs/reference/managers.md +123 -0
- mreg_api-0.4.0/docs/reference/models.md +11 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/_version.py +3 -3
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/client.py +63 -44
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/events.py +38 -5
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/managers.py +407 -231
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/models/models.py +20 -16
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api.egg-info/PKG-INFO +23 -2
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api.egg-info/SOURCES.txt +17 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api.egg-info/scm_file_list.json +18 -1
- mreg_api-0.4.0/mreg_api.egg-info/scm_version.json +8 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/pyproject.toml +2 -1
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/test_atoms.py +26 -40
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/test_cname.py +1 -1
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/test_host_records.py +13 -13
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/test_hosts.py +1 -8
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/test_ip.py +0 -4
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/test_labels.py +10 -17
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/test_meta.py +4 -0
- mreg_api-0.4.0/tests/integration/test_nameservers.py +130 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/test_network_policy.py +0 -15
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/test_networks.py +10 -36
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/test_client.py +1 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/test_events.py +15 -15
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/test_managers.py +42 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/uv.lock +291 -5
- mreg_api-0.4.0/zensical.toml +398 -0
- mreg_api-0.3.0/README.md +0 -23
- mreg_api-0.3.0/mreg_api.egg-info/scm_version.json +0 -8
- {mreg_api-0.3.0 → mreg_api-0.4.0}/.claude/CLAUDE.md +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/.github/workflows/publish.yml +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/.github/workflows/test.yml +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/.gitignore +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/.pre-commit-config.yaml +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/LICENSE +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/NOTES.md +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/ci/Dockerfile +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/__about__.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/__init__.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/cache.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/endpoints.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/exceptions.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/models/__init__.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/models/abstracts.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/models/fields.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/models/history.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/py.typed +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/types.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/utilities/__init__.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/utilities/fs.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api/utilities/shared.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api.egg-info/dependency_links.txt +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api.egg-info/requires.txt +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/mreg_api.egg-info/top_level.txt +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/setup.cfg +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/__init__.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/conftest.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/__init__.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/conftest.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/test_dhcp.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/test_hostgroups.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/test_permissions.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/test_roles.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/integration/test_zones.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/models/__init__.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/models/test_fields.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/models/test_models.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/test_cache.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/test_exceptions.py +0 -0
- {mreg_api-0.3.0 → mreg_api-0.4.0}/tests/test_types.py +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Documentation
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- main
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
pages: write
|
|
9
|
+
id-token: write
|
|
10
|
+
jobs:
|
|
11
|
+
deploy:
|
|
12
|
+
environment:
|
|
13
|
+
name: github-pages
|
|
14
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/configure-pages@v6
|
|
18
|
+
- uses: actions/checkout@v6
|
|
19
|
+
- name: Install uv
|
|
20
|
+
uses: astral-sh/setup-uv@v2
|
|
21
|
+
- name: Set up Python 3.12
|
|
22
|
+
run: uv python install 3.12
|
|
23
|
+
- run: uv sync --only-group docs
|
|
24
|
+
- run: uv run zensical build --clean
|
|
25
|
+
- uses: actions/upload-pages-artifact@v5
|
|
26
|
+
with:
|
|
27
|
+
path: site
|
|
28
|
+
- uses: actions/deploy-pages@v5
|
|
29
|
+
id: deployment
|
|
@@ -7,6 +7,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
<!-- ## Unreleased -->
|
|
9
9
|
|
|
10
|
+
## [0.4.0](https://github.com/unioslo/mreg-api/releases/tag/0.4.0) - 2026-08-24
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `MregClient.community` property to access the `CommunityManager` for managing communities.
|
|
15
|
+
- Still exists via `MregClient.network.community`.
|
|
16
|
+
- `EventLog.get(subject=..., kind=..., level=..., min_level=...)` method to support retrieving events and filtering by a combination of subject, kind, and level. This replaces the existing `get_for`, `get_by_kind`, `get_by_level`, and `get_at_or_above` methods, and allows one to combine all their filters in a single call. Currently, only intersections of filters are supported (i.e. events must match all filters to be returned). Future releases may support unions of filters (i.e. events matching any filter will be returned).
|
|
17
|
+
- `MregClient.policy` property that groups the existing `MregClient.atom`, `MregClient.role`, `MregClient.label` into a common namespace as `MregClient.policy.role`, `MregClient.policy.atom`, and `MregClient.policy.label`.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- `MregClient.*.create()` semantics and return type changes:
|
|
22
|
+
- POST requests now prefer to return the created object found in the response, rather than fetching the object again from the API via the location header. The manager falls back on fetching via location header if the response does not contain the created object.
|
|
23
|
+
- `create()` method return type changed from `T | None` to `T`. Never returns None.
|
|
24
|
+
- `create(fetch_after_create)` parameter removed.
|
|
25
|
+
- `models.LDAPHealth` now defines `status` as a `Literal["OK", "Down", "Unknown"]` type instead of a generic string.
|
|
26
|
+
- `models.UserInfo` now has defaults for all its fields.
|
|
27
|
+
- `MregClient.community.create()` now returns the created `Community` object instead of a boolean indicating success.
|
|
28
|
+
- Default limit of 500 for `list()` calls has been changed to `None` (unrestricted).
|
|
29
|
+
|
|
30
|
+
### Removed
|
|
31
|
+
|
|
32
|
+
- **BREAKING:** `create(fetch_after_create)` parameter. No longer has any meaning as each endpoint returns a valid object representation in the response body after creation.
|
|
33
|
+
|
|
34
|
+
### Deprecated
|
|
35
|
+
|
|
36
|
+
- `EventLog.get_all()` -> `EventLog.get()`
|
|
37
|
+
- `EventLog.get_for()` -> `EventLog.get(subject=...)`
|
|
38
|
+
- `EventLog.get_by_kind()` -> `EventLog.get(kind=...)`
|
|
39
|
+
- `EventLog.get_by_level()` -> `EventLog.get(level=...)`
|
|
40
|
+
- `EventLog.get_at_or_above()` -> `EventLog.get(min_level=...)`
|
|
41
|
+
|
|
10
42
|
## [0.3.0](https://github.com/unioslo/mreg-api/releases/tag/0.3.0) - 2026-08-12
|
|
11
43
|
|
|
12
44
|
### Added
|
|
@@ -19,7 +51,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
19
51
|
- **BREAKING**: `MregClient` is no longer a singleton. Each instance is independent and maintains its own state. The `MregClient.get_instance()` method has been removed. Each instantiation of `MregClient` is now independent and maintains its own state, including history, events and cache.
|
|
20
52
|
- `Network.get_community()` now ignores case when searching for communities by name. It returns the first community with the given name, or None if not found.
|
|
21
53
|
|
|
22
|
-
|
|
23
54
|
### Removed
|
|
24
55
|
|
|
25
56
|
- **BREAKING**: `MregClient.reset_instance` removed because the singleton pattern has been removed.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mreg-api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: MREG API
|
|
5
5
|
Author-email: Terje Kvernes <terjekv@uio.no>
|
|
6
6
|
Maintainer-email: Peder Hovdan Andresen <pederhan@uio.no>
|
|
@@ -701,7 +701,28 @@ Dynamic: license-file
|
|
|
701
701
|
|
|
702
702
|
# MREG API [](https://github.com/unioslo/mreg-api/actions/workflows/test.yml)
|
|
703
703
|
|
|
704
|
-
|
|
704
|
+
`mreg-api` is a Python client library for the [MREG](https://github.com/unioslo/mreg)
|
|
705
|
+
REST API. It gives you a typed, ergonomic interface to every MREG
|
|
706
|
+
resource through a single client
|
|
707
|
+
object with scoped namespaces for each resource type.
|
|
708
|
+
|
|
709
|
+
It provides optional caching of resources, automatic FQDN expansion of hostnames, and a consistent interface for all resource types. The client is compatible with Python 3.11 and later.
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
## Documentation
|
|
713
|
+
|
|
714
|
+
https://unioslo.github.io/mreg-api/
|
|
715
|
+
|
|
716
|
+
## Development
|
|
717
|
+
|
|
718
|
+
Set up a development environment with `uv`:
|
|
719
|
+
|
|
720
|
+
```bash
|
|
721
|
+
git clone git@github.com:unioslo/mreg-api.git
|
|
722
|
+
uv sync
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
### Pre-commit Hooks
|
|
705
726
|
|
|
706
727
|
This project uses `prek` to manage pre-commit hooks for code quality and formatting. To set up the pre-commit hooks, run the following command:
|
|
707
728
|
|
mreg_api-0.4.0/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# MREG API [](https://github.com/unioslo/mreg-api/actions/workflows/test.yml)
|
|
2
|
+
|
|
3
|
+
`mreg-api` is a Python client library for the [MREG](https://github.com/unioslo/mreg)
|
|
4
|
+
REST API. It gives you a typed, ergonomic interface to every MREG
|
|
5
|
+
resource through a single client
|
|
6
|
+
object with scoped namespaces for each resource type.
|
|
7
|
+
|
|
8
|
+
It provides optional caching of resources, automatic FQDN expansion of hostnames, and a consistent interface for all resource types. The client is compatible with Python 3.11 and later.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Documentation
|
|
12
|
+
|
|
13
|
+
https://unioslo.github.io/mreg-api/
|
|
14
|
+
|
|
15
|
+
## Development
|
|
16
|
+
|
|
17
|
+
Set up a development environment with `uv`:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
git clone git@github.com:unioslo/mreg-api.git
|
|
21
|
+
uv sync
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Pre-commit Hooks
|
|
25
|
+
|
|
26
|
+
This project uses `prek` to manage pre-commit hooks for code quality and formatting. To set up the pre-commit hooks, run the following command:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
uv tool install prek
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Then, install the pre-commit hooks with:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
prek install
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Run the pre-commit checks manually with:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
prek run
|
|
42
|
+
# Optionally for all files:
|
|
43
|
+
prek run --all-files
|
|
44
|
+
```
|
|
@@ -45,11 +45,22 @@ Flags:
|
|
|
45
45
|
| `--unit-only` | Skip integration tests (no containers started) |
|
|
46
46
|
| `--integration-only` | Skip unit tests |
|
|
47
47
|
| `--no-cov` | Disable coverage. Used in CI |
|
|
48
|
+
| `-h`, `--help` | Show usage |
|
|
49
|
+
| `-- ARGS...` | Pass everything after `--` to pytest |
|
|
50
|
+
|
|
51
|
+
Unknown flags are an error (exit code 2) — the script never silently ignores them.
|
|
52
|
+
|
|
53
|
+
Container setup (`ci/run_tests.sh` only, not read by pytest):
|
|
54
|
+
|
|
55
|
+
| Env var | Default | Description |
|
|
56
|
+
|---|---|---|
|
|
57
|
+
| `MREG_IMAGE` | `ghcr.io/unioslo/mreg:master` | mreg container image |
|
|
58
|
+
| `MREG_IMAGE_PULL_POLICY` | `missing` | Compose pull policy: `missing`, `always`, `never` |
|
|
59
|
+
| `MREG_PORT` | `8000` | Host port the mreg container is exposed on |
|
|
60
|
+
|
|
61
|
+
`master` is a mutable tag, so a local image can go stale. Use `MREG_IMAGE_PULL_POLICY=always` to pull the current one.
|
|
62
|
+
|
|
48
63
|
|
|
49
|
-
```bash
|
|
50
|
-
# Fast run without coverage
|
|
51
|
-
bash ci/run_tests.sh --no-cov
|
|
52
|
-
```
|
|
53
64
|
|
|
54
65
|
### Running manually against a local server
|
|
55
66
|
|
|
@@ -88,19 +99,24 @@ uv run pytest tests/integration/ \
|
|
|
88
99
|
CLI flags take precedence over env vars.
|
|
89
100
|
|
|
90
101
|
|
|
91
|
-
### Subset
|
|
102
|
+
### Subset and extra arguments
|
|
103
|
+
|
|
92
104
|
|
|
93
105
|
```bash
|
|
94
|
-
#
|
|
95
|
-
|
|
106
|
+
# Fast run without coverage
|
|
107
|
+
bash ci/run_tests.sh --no-cov
|
|
96
108
|
|
|
97
|
-
# Single
|
|
98
|
-
|
|
109
|
+
# Single module
|
|
110
|
+
bash ci/run_tests.sh --integration-only -- tests/integration/test_labels.py
|
|
99
111
|
|
|
100
|
-
#
|
|
101
|
-
|
|
112
|
+
# Stop on first failure, filter by name
|
|
113
|
+
bash ci/run_tests.sh --integration-only -- -x -k labels
|
|
102
114
|
```
|
|
103
115
|
|
|
116
|
+
Each pass selects its tests by marker (`-m integration` / `-m "not integration"`) rather than by
|
|
117
|
+
path, so a path after `--` narrows the run. When both suites run, the arguments go to both pytest
|
|
118
|
+
invocations.
|
|
119
|
+
|
|
104
120
|
## Coverage
|
|
105
121
|
|
|
106
122
|
### Unit tests only
|
|
@@ -8,6 +8,7 @@ RUN_UNIT=true
|
|
|
8
8
|
RUN_INTEGRATION=true
|
|
9
9
|
RUN_COVERAGE=true
|
|
10
10
|
MREG_IMAGE="${MREG_IMAGE:-ghcr.io/unioslo/mreg:master}"
|
|
11
|
+
MREG_IMAGE_PULL_POLICY="${MREG_IMAGE_PULL_POLICY:-missing}"
|
|
11
12
|
# Host port the mreg container is exposed on. Override if 8000 is already in use.
|
|
12
13
|
MREG_PORT="${MREG_PORT:-8000}"
|
|
13
14
|
MREG_URL="${MREG_URL:-http://127.0.0.1:${MREG_PORT}}"
|
|
@@ -15,12 +16,32 @@ MREG_USERNAME="${MREG_USERNAME:-test}"
|
|
|
15
16
|
MREG_PASSWORD="${MREG_PASSWORD:-test}"
|
|
16
17
|
MREG_CACHE="${MREG_CACHE:-0}"
|
|
17
18
|
|
|
19
|
+
usage() {
|
|
20
|
+
cat <<'EOF'
|
|
21
|
+
Usage: bash ci/run_tests.sh [--unit-only|--integration-only] [--no-cov] [-- pytest args...]
|
|
22
|
+
|
|
23
|
+
Everything after -- is passed to pytest:
|
|
24
|
+
|
|
25
|
+
bash ci/run_tests.sh --integration-only -- tests/integration/test_labels.py
|
|
26
|
+
bash ci/run_tests.sh --integration-only -- -x -k labels
|
|
27
|
+
EOF
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Extra arguments passed to pytest (everything after --).
|
|
31
|
+
EXTRA_ARGS=()
|
|
32
|
+
|
|
18
33
|
while [[ $# -gt 0 ]]; do
|
|
19
34
|
case $1 in
|
|
20
35
|
--unit-only) RUN_INTEGRATION=false; shift ;;
|
|
21
36
|
--integration-only) RUN_UNIT=false; shift ;;
|
|
22
37
|
--no-cov) RUN_COVERAGE=false; shift ;;
|
|
23
|
-
|
|
38
|
+
-h|--help) usage; exit 0 ;;
|
|
39
|
+
--) shift; EXTRA_ARGS=("$@"); break ;;
|
|
40
|
+
*)
|
|
41
|
+
echo "ERROR: unknown option: $1" >&2
|
|
42
|
+
usage >&2
|
|
43
|
+
exit 2
|
|
44
|
+
;;
|
|
24
45
|
esac
|
|
25
46
|
done
|
|
26
47
|
|
|
@@ -47,7 +68,9 @@ if [[ "$RUN_INTEGRATION" == "true" ]]; then
|
|
|
47
68
|
cd "$SCRIPT_DIR"
|
|
48
69
|
|
|
49
70
|
echo "Starting mreg and postgres on port ${MREG_PORT}..."
|
|
50
|
-
MREG_IMAGE="$MREG_IMAGE" MREG_PORT="$MREG_PORT"
|
|
71
|
+
MREG_IMAGE="$MREG_IMAGE" MREG_PORT="$MREG_PORT" \
|
|
72
|
+
MREG_IMAGE_PULL_POLICY="$MREG_IMAGE_PULL_POLICY" \
|
|
73
|
+
$DOCKER compose up -d
|
|
51
74
|
|
|
52
75
|
echo "Creating superuser..."
|
|
53
76
|
$DOCKER exec mreg uv run /app/manage.py create_mreg_superuser \
|
|
@@ -65,23 +88,27 @@ INTEGRATION_EXIT=0
|
|
|
65
88
|
|
|
66
89
|
if [[ "$RUN_UNIT" == "true" ]]; then
|
|
67
90
|
echo "Running unit tests..."
|
|
68
|
-
|
|
91
|
+
# No path here: pytest falls back to testpaths (tests/) from pyproject.toml,
|
|
92
|
+
# so a path in EXTRA_ARGS narrows the run instead of being added to it.
|
|
93
|
+
UNIT_ARGS=(-m "not integration" -v)
|
|
69
94
|
if [[ "$RUN_COVERAGE" == "true" ]]; then
|
|
70
95
|
UNIT_ARGS+=(--cov=mreg_api --cov-report=)
|
|
71
96
|
else
|
|
72
97
|
UNIT_ARGS+=(--no-cov)
|
|
73
98
|
fi
|
|
99
|
+
UNIT_ARGS+=(${EXTRA_ARGS[@]+"${EXTRA_ARGS[@]}"})
|
|
74
100
|
uv run pytest "${UNIT_ARGS[@]}" || UNIT_EXIT=$?
|
|
75
101
|
fi
|
|
76
102
|
|
|
77
103
|
if [[ "$RUN_INTEGRATION" == "true" ]]; then
|
|
78
104
|
echo "Running integration tests..."
|
|
79
|
-
INTEGRATION_ARGS=(
|
|
105
|
+
INTEGRATION_ARGS=(-m integration -v)
|
|
80
106
|
if [[ "$RUN_COVERAGE" == "true" ]]; then
|
|
81
107
|
INTEGRATION_ARGS+=(--cov=mreg_api --cov-append --cov-report=html --cov-report=term)
|
|
82
108
|
else
|
|
83
109
|
INTEGRATION_ARGS+=(--no-cov)
|
|
84
110
|
fi
|
|
111
|
+
INTEGRATION_ARGS+=(${EXTRA_ARGS[@]+"${EXTRA_ARGS[@]}"})
|
|
85
112
|
MREG_URL="$MREG_URL" \
|
|
86
113
|
MREG_USERNAME="$MREG_USERNAME" \
|
|
87
114
|
MREG_PASSWORD="$MREG_PASSWORD" \
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
icon: lucide/key-round
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Authentication
|
|
6
|
+
|
|
7
|
+
The client does not authenticate on construction and never reads credentials from the
|
|
8
|
+
environment or a token file on its own — authentication is always explicit. There are two
|
|
9
|
+
ways to authenticate.
|
|
10
|
+
|
|
11
|
+
## Username and password
|
|
12
|
+
|
|
13
|
+
[`login()`][mreg_api.client.MregClient.login] exchanges credentials for a token, stores
|
|
14
|
+
it on the client, and returns it. Reading credentials from the environment is a common
|
|
15
|
+
pattern:
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
import os
|
|
19
|
+
from mreg_api import MregClient
|
|
20
|
+
|
|
21
|
+
client = MregClient(url="https://mreg.example.com", domain="example.com")
|
|
22
|
+
client.login(
|
|
23
|
+
username=os.environ["MREG_USERNAME"],
|
|
24
|
+
password=os.environ["MREG_PASSWORD"],
|
|
25
|
+
)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`login()` raises [`LoginFailedError`][mreg_api.exceptions.LoginFailedError] on a
|
|
29
|
+
connection failure or bad credentials.
|
|
30
|
+
|
|
31
|
+
## Existing token
|
|
32
|
+
|
|
33
|
+
!!! note
|
|
34
|
+
|
|
35
|
+
Token auth is primarily relevant to persistent sessions for applications such as [mreg-cli](https://github.com/unioslo/mreg-cli), not for scripts or ephemeral sessions.
|
|
36
|
+
|
|
37
|
+
If you already have a token, set it directly with
|
|
38
|
+
[`set_token()`][mreg_api.client.MregClient.set_token] — no `login()` call needed:
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
client = MregClient(url="https://mreg.example.com")
|
|
42
|
+
client.set_token(os.environ["MREG_TOKEN"])
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Managing the token
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
client.get_token() # current token, or None
|
|
49
|
+
client.test_auth() # raises InvalidAuthTokenError if the token is invalid
|
|
50
|
+
client.unset_token() # clear the token locally
|
|
51
|
+
client.logout() # invalidate the token on the server
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Correlation IDs
|
|
55
|
+
|
|
56
|
+
To make requests easier to trace in server logs, attach a correlation ID that is sent
|
|
57
|
+
with every subsequent request:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
client.set_correlation_id("nightly-sync")
|
|
61
|
+
client.get_correlation_id()
|
|
62
|
+
```
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
icon: lucide/database
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Caching
|
|
6
|
+
|
|
7
|
+
The client can cache `GET` responses on disk to avoid refetching unchanged data. Caching
|
|
8
|
+
is **off by default**. Any successful `POST`/`PATCH`/`DELETE` clears the cache, so writes
|
|
9
|
+
never leave you reading stale data.
|
|
10
|
+
|
|
11
|
+
## Enabling at construction
|
|
12
|
+
|
|
13
|
+
Pass `cache=True` for defaults, or a [`CacheConfig`][mreg_api.cache.CacheConfig] to
|
|
14
|
+
customize:
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from mreg_api import MregClient, CacheConfig
|
|
18
|
+
|
|
19
|
+
# Defaults
|
|
20
|
+
client = MregClient(url="https://mreg.example.com", cache=True)
|
|
21
|
+
|
|
22
|
+
# Custom configuration
|
|
23
|
+
client = MregClient(
|
|
24
|
+
url="https://mreg.example.com",
|
|
25
|
+
cache=CacheConfig(ttl=600, directory="/var/tmp/mreg-cache"),
|
|
26
|
+
)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## `CacheConfig` options
|
|
30
|
+
|
|
31
|
+
| Field | Type | Default | Description |
|
|
32
|
+
|---|---|---|---|
|
|
33
|
+
| `enable` | `bool` | `True` | Whether the cache is active. |
|
|
34
|
+
| `ttl` | `int` | `300` | Time-to-live for cached entries, in seconds. |
|
|
35
|
+
| `tag` | `str` | `"mreg-api"` | Tag used to namespace cache entries. |
|
|
36
|
+
| `timeout` | `int` | `60` | Open timeout for the underlying disk cache. |
|
|
37
|
+
| `directory` | `str | None` | `None` | Cache directory. `None` uses a system temp directory. |
|
|
38
|
+
|
|
39
|
+
## Controlling the cache at runtime
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
client.enable_cache() # turn caching on
|
|
43
|
+
client.enable_cache(CacheConfig(ttl=60)) # reconfigure and turn on
|
|
44
|
+
client.disable_cache() # turn off (clears by default)
|
|
45
|
+
client.disable_cache(clear=False) # turn off, keep cached data
|
|
46
|
+
client.clear_cache() # drop all cached entries
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Use the [`caching()`][mreg_api.client.MregClient.caching] context manager to toggle
|
|
50
|
+
caching for a block:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
with client.caching(enable=True):
|
|
54
|
+
client.host.list() # served from / stored in the cache
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Inspecting the cache
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
info = client.get_cache_info() # CacheInfo, or None if caching is disabled
|
|
61
|
+
if info:
|
|
62
|
+
print(info.items, info.hits, info.misses, info.size)
|
|
63
|
+
```
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
icon: lucide/settings
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Client configuration
|
|
6
|
+
|
|
7
|
+
Everything starts with an [`MregClient`][mreg_api.client.MregClient]. Constructing one
|
|
8
|
+
sets up the HTTP session but does **not** authenticate or make any network requests — see
|
|
9
|
+
[Authentication](authentication.md) for that.
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
from mreg_api import MregClient
|
|
13
|
+
|
|
14
|
+
client = MregClient(
|
|
15
|
+
url="https://mreg.example.com",
|
|
16
|
+
domain="example.com",
|
|
17
|
+
)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Constructor options
|
|
21
|
+
|
|
22
|
+
| Argument | Type | Default | Description |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| `url` | `str` | *required* | Base URL of the MREG server. All request paths are joined onto it. |
|
|
25
|
+
| `domain` | `str | None` | `None` | Default DNS domain used to expand bare hostnames into FQDNs. See [Domain handling](#domain-handling). |
|
|
26
|
+
| `user` | `str | None` | `None` | Informational username stored on the client. Does **not** authenticate. |
|
|
27
|
+
| `timeout` | `int | float | None` | `60` | Request timeout in seconds, passed to the underlying HTTP client. |
|
|
28
|
+
| `cache` | `CacheConfig | bool` | `False` | Enable GET-response caching. `True` uses defaults; pass a [`CacheConfig`][mreg_api.cache.CacheConfig] to customize. See [Caching](caching.md). |
|
|
29
|
+
| `follow_redirects` | `bool` | `False` | Whether the HTTP client follows redirects. |
|
|
30
|
+
| `page_size` | `int | None` | `None` | Default pagination page size sent as a query parameter on GET requests. |
|
|
31
|
+
| `history_size` | `int | None` | `100` | Maximum number of request/response records kept in `client.history`. |
|
|
32
|
+
| `event_log_size` | `int | None` | `100` | Maximum number of entries kept in the [event log](../reference/events.md). |
|
|
33
|
+
| `user_agent` | `str | None` | `None` | Custom `User-Agent` header. Defaults to `mreg-api-<version>`. |
|
|
34
|
+
|
|
35
|
+
## Domain handling
|
|
36
|
+
|
|
37
|
+
When `domain` is set, bare hostnames are expanded to FQDNs automatically by resource
|
|
38
|
+
methods. You can also expand a name explicitly or override the domain temporarily:
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
client.fqdn("web") # -> "web.example.com"
|
|
42
|
+
|
|
43
|
+
with client.domain_override("other.example.com"):
|
|
44
|
+
client.fqdn("web") # -> "web.other.example.com"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Timeout
|
|
48
|
+
|
|
49
|
+
`timeout` is also available as a settable property after construction:
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
client.timeout = 120
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Request history
|
|
56
|
+
|
|
57
|
+
Every request/response pair is recorded in a bounded deque, sized by `history_size`:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
for record in client.get_client_history():
|
|
61
|
+
print(record.method, record.status, record.url)
|
|
62
|
+
|
|
63
|
+
client.clear_client_history()
|
|
64
|
+
```
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
icon: lucide/chart-no-axes-gantt
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Event Log
|
|
6
|
+
|
|
7
|
+
The client records an event log of resolutions, mutations, and notices that happen in-between requests for complex queries and multi-step operations. Typically, such events are things like CNAME and PTR resolution that happen when resolving Host or host records.
|
|
8
|
+
|
|
9
|
+
!!! note
|
|
10
|
+
|
|
11
|
+
The event log system is a new feature and is still under development. The API may change in future releases. As of 0.3.0, it only records CNAME and PTR resolution events, but future releases will include more event types.
|
|
12
|
+
|
|
13
|
+
## Accessing the event log
|
|
14
|
+
|
|
15
|
+
The event log is accessible via the `client.events` property, which returns an [`EventLog`][mreg_api.events.EventLog] instance. The size of the log is controlled by the `event_log_size` argument to [`MregClient`][mreg_api.client.MregClient].
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
client = MregClient(...)
|
|
19
|
+
events = client.events.get()
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Filtering by event kind
|
|
23
|
+
|
|
24
|
+
Each event is categorized by kind ([`EventKind`][mreg_api.events.EventKind]). You can filter the event log by kind using the `get` method with the `kind` argument:
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from mreg_api.events import EventKind
|
|
28
|
+
|
|
29
|
+
client.events.get(kind=EventKind.RESOLUTION)
|
|
30
|
+
client.events.get(kind=EventKind.MUTATION)
|
|
31
|
+
client.events.get(kind=EventKind.NOTICE)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Filtering by event level
|
|
35
|
+
|
|
36
|
+
Each event is also categorized by level ([`EventLevel`][mreg_api.events.EventLevel]). You can filter the event log by level using the `get` method with the `level` argument:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from mreg_api.events import EventLevel
|
|
40
|
+
|
|
41
|
+
client.events.get(level=EventLevel.DEBUG)
|
|
42
|
+
client.events.get(level=EventLevel.INFO)
|
|
43
|
+
client.events.get(level=EventLevel.WARNING)
|
|
44
|
+
client.events.get(level=EventLevel.ERROR)
|
|
45
|
+
client.events.get(level=EventLevel.CRITICAL)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The `min_level` argument can be used to retrieve events at or above a certain severity level instead of exactly matching a level:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
client.events.get(min_level=EventLevel.WARNING)
|
|
52
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
icon: lucide/timeline
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Request/Response History
|
|
6
|
+
|
|
7
|
+
The client records a request/response history of each interaction with the server. The history is a bounded deque, sized by the `history_size` argument to [`MregClient`][mreg_api.client.MregClient]. You can access the history via the `client.history` property, which returns a list of [`RequestRecord`][mreg_api.client.RequestRecord] instances, which contain the request and response objects for each interaction, as well as shortcuts for the request method, URL, data and json payloads, as well as response status code.
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
client = MregClient(...)
|
|
11
|
+
for record in client.get_client_history():
|
|
12
|
+
print(record.request.method, record.request.url, record.status)
|
|
13
|
+
assert record.status == record.response.status_code
|
|
14
|
+
print("Request payload:", record.data or record.json)
|
|
15
|
+
```
|