mreg-api 0.2.3__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.4.0/.github/workflows/test.yml +52 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/.gitignore +5 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/.markdownlint.json +5 -1
- {mreg_api-0.2.3 → mreg_api-0.4.0}/CHANGELOG.md +48 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/PKG-INFO +24 -3
- mreg_api-0.4.0/README.md +44 -0
- mreg_api-0.4.0/TESTING.md +152 -0
- mreg_api-0.4.0/ci/Dockerfile +15 -0
- mreg_api-0.4.0/ci/docker-compose.yml +40 -0
- mreg_api-0.4.0/ci/run_tests.sh +121 -0
- 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.2.3 → mreg_api-0.4.0}/mreg_api/_version.py +3 -3
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api/cache.py +27 -2
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api/client.py +261 -185
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api/endpoints.py +3 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api/events.py +87 -10
- mreg_api-0.4.0/mreg_api/managers.py +4793 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api/models/__init__.py +2 -0
- mreg_api-0.4.0/mreg_api/models/abstracts.py +33 -0
- mreg_api-0.4.0/mreg_api/models/fields.py +198 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api/models/history.py +0 -30
- mreg_api-0.4.0/mreg_api/models/models.py +1297 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api/types.py +1 -11
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api.egg-info/PKG-INFO +24 -3
- mreg_api-0.4.0/mreg_api.egg-info/SOURCES.txt +86 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api.egg-info/requires.txt +1 -1
- mreg_api-0.4.0/mreg_api.egg-info/scm_file_list.json +82 -0
- mreg_api-0.4.0/mreg_api.egg-info/scm_version.json +8 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/pyproject.toml +61 -23
- mreg_api-0.4.0/tests/__init__.py +0 -0
- mreg_api-0.4.0/tests/conftest.py +12 -0
- mreg_api-0.4.0/tests/integration/__init__.py +0 -0
- mreg_api-0.4.0/tests/integration/conftest.py +226 -0
- mreg_api-0.4.0/tests/integration/test_atoms.py +302 -0
- mreg_api-0.4.0/tests/integration/test_cname.py +175 -0
- mreg_api-0.4.0/tests/integration/test_dhcp.py +68 -0
- mreg_api-0.4.0/tests/integration/test_host_records.py +773 -0
- mreg_api-0.4.0/tests/integration/test_hostgroups.py +284 -0
- mreg_api-0.4.0/tests/integration/test_hosts.py +227 -0
- mreg_api-0.4.0/tests/integration/test_ip.py +154 -0
- mreg_api-0.4.0/tests/integration/test_labels.py +185 -0
- mreg_api-0.4.0/tests/integration/test_meta.py +53 -0
- mreg_api-0.4.0/tests/integration/test_nameservers.py +130 -0
- mreg_api-0.4.0/tests/integration/test_network_policy.py +362 -0
- mreg_api-0.4.0/tests/integration/test_networks.py +298 -0
- mreg_api-0.4.0/tests/integration/test_permissions.py +202 -0
- mreg_api-0.4.0/tests/integration/test_roles.py +323 -0
- mreg_api-0.4.0/tests/integration/test_zones.py +242 -0
- mreg_api-0.4.0/tests/models/test_fields.py +457 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/tests/models/test_models.py +20 -2
- {mreg_api-0.2.3 → mreg_api-0.4.0}/tests/test_client.py +142 -196
- {mreg_api-0.2.3 → mreg_api-0.4.0}/tests/test_events.py +20 -24
- {mreg_api-0.2.3 → mreg_api-0.4.0}/tests/test_exceptions.py +1 -5
- mreg_api-0.4.0/tests/test_managers.py +173 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/uv.lock +368 -11
- mreg_api-0.4.0/zensical.toml +398 -0
- mreg_api-0.2.3/.github/workflows/test.yml +0 -30
- mreg_api-0.2.3/README.md +0 -23
- mreg_api-0.2.3/mreg_api/models/abstracts.py +0 -558
- mreg_api-0.2.3/mreg_api/models/fields.py +0 -198
- mreg_api-0.2.3/mreg_api/models/models.py +0 -4435
- mreg_api-0.2.3/mreg_api.egg-info/SOURCES.txt +0 -45
- mreg_api-0.2.3/tests/conftest.py +0 -39
- mreg_api-0.2.3/tests/models/test_fields.py +0 -275
- mreg_api-0.2.3/tests/models/test_history.py +0 -40
- /mreg_api-0.2.3/mreg_api/py.typed → /mreg_api-0.4.0/.claude/CLAUDE.md +0 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/.github/workflows/publish.yml +0 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/.pre-commit-config.yaml +0 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/LICENSE +0 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/NOTES.md +0 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api/__about__.py +0 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api/__init__.py +0 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api/exceptions.py +0 -0
- /mreg_api-0.2.3/tests/__init__.py → /mreg_api-0.4.0/mreg_api/py.typed +0 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api/utilities/__init__.py +0 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api/utilities/fs.py +0 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api/utilities/shared.py +0 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api.egg-info/dependency_links.txt +0 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/mreg_api.egg-info/top_level.txt +0 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/setup.cfg +0 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/tests/models/__init__.py +0 -0
- {mreg_api-0.2.3 → mreg_api-0.4.0}/tests/test_cache.py +0 -0
- {mreg_api-0.2.3 → 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
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
on:
|
|
2
|
+
push:
|
|
3
|
+
pull_request:
|
|
4
|
+
|
|
5
|
+
env:
|
|
6
|
+
UV_FROZEN: 1
|
|
7
|
+
|
|
8
|
+
name: Tests
|
|
9
|
+
jobs:
|
|
10
|
+
unit:
|
|
11
|
+
name: Unit tests
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
python-version:
|
|
17
|
+
- "3.11"
|
|
18
|
+
- "3.12"
|
|
19
|
+
- "3.13"
|
|
20
|
+
- "3.14"
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
- name: Install uv
|
|
24
|
+
uses: astral-sh/setup-uv@v2
|
|
25
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
26
|
+
run: uv python install ${{ matrix.python-version }}
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: uv sync
|
|
29
|
+
- name: Run unit tests
|
|
30
|
+
run: bash ci/run_tests.sh --unit-only --no-cov
|
|
31
|
+
|
|
32
|
+
integration:
|
|
33
|
+
name: Integration tests
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
strategy:
|
|
36
|
+
fail-fast: false
|
|
37
|
+
matrix:
|
|
38
|
+
python-version:
|
|
39
|
+
- "3.11"
|
|
40
|
+
- "3.12"
|
|
41
|
+
- "3.13"
|
|
42
|
+
- "3.14"
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@v4
|
|
45
|
+
- name: Install uv
|
|
46
|
+
uses: astral-sh/setup-uv@v2
|
|
47
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
48
|
+
run: uv python install ${{ matrix.python-version }}
|
|
49
|
+
- name: Install dependencies
|
|
50
|
+
run: uv sync
|
|
51
|
+
- name: Run integration tests
|
|
52
|
+
run: bash ci/run_tests.sh --integration-only --no-cov
|
|
@@ -7,6 +7,54 @@ 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
|
+
|
|
42
|
+
## [0.3.0](https://github.com/unioslo/mreg-api/releases/tag/0.3.0) - 2026-08-12
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
|
|
46
|
+
- `Host.get_community_associations(name: str)` method to retrieve all ipaddress->community associations for the host with the given community name.
|
|
47
|
+
- `Network.get_communities(name: str)` method to retrieve all communities with the given name.
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
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.
|
|
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.
|
|
53
|
+
|
|
54
|
+
### Removed
|
|
55
|
+
|
|
56
|
+
- **BREAKING**: `MregClient.reset_instance` removed because the singleton pattern has been removed.
|
|
57
|
+
|
|
10
58
|
## [0.2.3](https://github.com/unioslo/mreg-api/releases/tag/0.2.3) - 2026-05-21
|
|
11
59
|
|
|
12
60
|
### Fixed
|
|
@@ -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>
|
|
@@ -692,7 +692,7 @@ Requires-Python: >=3.11
|
|
|
692
692
|
Description-Content-Type: text/markdown
|
|
693
693
|
License-File: LICENSE
|
|
694
694
|
Requires-Dist: httpx[socks]>=0.28.1
|
|
695
|
-
Requires-Dist:
|
|
695
|
+
Requires-Dist: typing-extensions>=4.16.0
|
|
696
696
|
Requires-Dist: pydantic>=2.12
|
|
697
697
|
Requires-Dist: pydantic-extra-types>=2.1.0
|
|
698
698
|
Requires-Dist: diskcache>=5.6.3
|
|
@@ -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
|
+
```
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Testing
|
|
2
|
+
|
|
3
|
+
mreg-api has two types of tests:
|
|
4
|
+
|
|
5
|
+
- **Unit tests** — Unit testing of functions and methods used by the package. No interaction with a live mreg server is required.
|
|
6
|
+
- **Integration tests** — Run against a live (containerized) mreg server. Skipped automatically when no server URL is configured.
|
|
7
|
+
|
|
8
|
+
## Unit tests
|
|
9
|
+
|
|
10
|
+
Unit tests use `pytest-httpserver` to mock MREG server responses for any tests that require HTTP interactions. No external services required.
|
|
11
|
+
|
|
12
|
+
Bare `pytest` invocations ignore integration tests (skipped automatically when no server URL is configured):
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
uv run pytest
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
In case some configuration defines `MREG_URL`, unit tests can still be run exclusively by ignoring the integration tests via markers:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
uv run pytest -m "not integration"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Integration tests
|
|
25
|
+
|
|
26
|
+
Integration tests run against a live mreg server. They are **skipped automatically** when no server URL is configured, so `uv run pytest` never fails due to a missing server.
|
|
27
|
+
|
|
28
|
+
### Prerequisites
|
|
29
|
+
|
|
30
|
+
A running mreg instance (and PostgreSQL). The fastest way is the containerized setup:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
bash ci/run_tests.sh
|
|
34
|
+
|
|
35
|
+
# If port 8000 is already in use (e.g., a local mreg dev server):
|
|
36
|
+
MREG_PORT=8081 bash ci/run_tests.sh
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This starts containers, creates a superuser, then runs both unit and integration tests with combined coverage output in `htmlcov/`.
|
|
40
|
+
|
|
41
|
+
Flags:
|
|
42
|
+
|
|
43
|
+
| Flag | Effect |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `--unit-only` | Skip integration tests (no containers started) |
|
|
46
|
+
| `--integration-only` | Skip unit tests |
|
|
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
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
### Running manually against a local server
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Minimal — username/password default to "test"
|
|
69
|
+
MREG_URL=http://127.0.0.1:8000 uv run pytest tests/integration/
|
|
70
|
+
|
|
71
|
+
# All options explicit
|
|
72
|
+
MREG_URL=http://127.0.0.1:8000 \
|
|
73
|
+
MREG_USERNAME=myuser \
|
|
74
|
+
MREG_PASSWORD=secret \
|
|
75
|
+
MREG_DOMAIN=example.com \
|
|
76
|
+
MREG_CACHE=0 \
|
|
77
|
+
MREG_TEST_NETWORK=10.0.0.0/8 \
|
|
78
|
+
uv run pytest tests/integration/ -v
|
|
79
|
+
|
|
80
|
+
# Via CLI flags instead of env vars
|
|
81
|
+
uv run pytest tests/integration/ \
|
|
82
|
+
--mreg-url http://127.0.0.1:8000 \
|
|
83
|
+
--mreg-username myuser \
|
|
84
|
+
--mreg-password secret
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Configuration
|
|
88
|
+
|
|
89
|
+
| Env var | CLI flag | Default | Description |
|
|
90
|
+
|---|---|---|---|
|
|
91
|
+
| `MREG_URL` | `--mreg-url` | *(none — required to activate integration tests)* | mreg server base URL |
|
|
92
|
+
| `MREG_USERNAME` | `--mreg-username` | `test` | Login username |
|
|
93
|
+
| `MREG_PASSWORD` | `--mreg-password` | `test` | Login password |
|
|
94
|
+
| `MREG_DOMAIN` | `--mreg-domain` | `example.com` | Default domain for the client. Controls the main zone used in integration tests |
|
|
95
|
+
| `MREG_CACHE` | `--mreg-cache` | `false` | Enable mreg client cache (`1`/`true`/`yes` = on) |
|
|
96
|
+
| `MREG_TEST_NETWORK` | `--test-network` | `10.0.0.0/8` | Network CIDR created as shared test network |
|
|
97
|
+
| `MREG_TEST_IP` | `--test-ip` | `10.0.0.1` | IP address used in IP-related tests |
|
|
98
|
+
|
|
99
|
+
CLI flags take precedence over env vars.
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
### Subset and extra arguments
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Fast run without coverage
|
|
107
|
+
bash ci/run_tests.sh --no-cov
|
|
108
|
+
|
|
109
|
+
# Single module
|
|
110
|
+
bash ci/run_tests.sh --integration-only -- tests/integration/test_labels.py
|
|
111
|
+
|
|
112
|
+
# Stop on first failure, filter by name
|
|
113
|
+
bash ci/run_tests.sh --integration-only -- -x -k labels
|
|
114
|
+
```
|
|
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
|
+
|
|
120
|
+
## Coverage
|
|
121
|
+
|
|
122
|
+
### Unit tests only
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
uv run pytest tests/ --ignore=tests/integration \
|
|
126
|
+
--cov=mreg_api --cov-report=term-missing
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Combined unit + integration
|
|
130
|
+
|
|
131
|
+
Run `ci/run_tests.sh` (uses `--cov-append` to merge both passes), or manually:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Pass 1: unit tests — write .coverage
|
|
135
|
+
uv run pytest tests/ --ignore=tests/integration \
|
|
136
|
+
--cov=mreg_api --cov-report=
|
|
137
|
+
|
|
138
|
+
# Pass 2: integration tests — append to .coverage
|
|
139
|
+
MREG_URL=http://127.0.0.1:8000 MREG_USERNAME=test MREG_PASSWORD=test \
|
|
140
|
+
uv run pytest tests/integration/ \
|
|
141
|
+
--cov=mreg_api --cov-append --cov-report=html --cov-report=term
|
|
142
|
+
|
|
143
|
+
# Open report
|
|
144
|
+
open htmlcov/index.html
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Markers
|
|
148
|
+
|
|
149
|
+
| Marker | Meaning |
|
|
150
|
+
|---|---|
|
|
151
|
+
| `integration` | Requires live mreg server — skipped without `MREG_URL` |
|
|
152
|
+
| `readonly` | Test only reads data, safe against staging/production servers |
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
FROM ubuntu:latest
|
|
2
|
+
|
|
3
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
4
|
+
curl \
|
|
5
|
+
git \
|
|
6
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
7
|
+
|
|
8
|
+
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
9
|
+
ENV PATH="/root/.local/bin:$PATH"
|
|
10
|
+
|
|
11
|
+
RUN uv python install 3.12
|
|
12
|
+
|
|
13
|
+
WORKDIR /build
|
|
14
|
+
COPY . .
|
|
15
|
+
RUN uv sync -q
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
services:
|
|
2
|
+
postgres:
|
|
3
|
+
image: postgres
|
|
4
|
+
environment:
|
|
5
|
+
POSTGRES_USER: mreg
|
|
6
|
+
POSTGRES_DB: mreg
|
|
7
|
+
POSTGRES_PASSWORD: mreg
|
|
8
|
+
healthcheck:
|
|
9
|
+
test: ["CMD", "pg_isready", "--username=mreg"]
|
|
10
|
+
interval: 5s
|
|
11
|
+
timeout: 5s
|
|
12
|
+
retries: 10
|
|
13
|
+
|
|
14
|
+
mreg:
|
|
15
|
+
image: ${MREG_IMAGE:-ghcr.io/unioslo/mreg:master}
|
|
16
|
+
pull_policy: ${MREG_IMAGE_PULL_POLICY:-missing}
|
|
17
|
+
container_name: mreg
|
|
18
|
+
depends_on:
|
|
19
|
+
postgres:
|
|
20
|
+
condition: service_healthy
|
|
21
|
+
ports:
|
|
22
|
+
- "${MREG_PORT:-8000}:8000"
|
|
23
|
+
environment:
|
|
24
|
+
MREG_DB_HOST: postgres
|
|
25
|
+
MREG_DB_NAME: mreg
|
|
26
|
+
MREG_DB_USER: mreg
|
|
27
|
+
MREG_DB_PASSWORD: mreg
|
|
28
|
+
MREG_MAP_GLOBAL_COMMUNITY_NAMES: "1"
|
|
29
|
+
CI: "yes"
|
|
30
|
+
healthcheck:
|
|
31
|
+
test: ["CMD", "test", "-f", "/var/run/gunicorn.pid"]
|
|
32
|
+
interval: 5s
|
|
33
|
+
timeout: 5s
|
|
34
|
+
retries: 20
|
|
35
|
+
|
|
36
|
+
wait:
|
|
37
|
+
image: hello-world
|
|
38
|
+
depends_on:
|
|
39
|
+
mreg:
|
|
40
|
+
condition: service_healthy
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
6
|
+
|
|
7
|
+
RUN_UNIT=true
|
|
8
|
+
RUN_INTEGRATION=true
|
|
9
|
+
RUN_COVERAGE=true
|
|
10
|
+
MREG_IMAGE="${MREG_IMAGE:-ghcr.io/unioslo/mreg:master}"
|
|
11
|
+
MREG_IMAGE_PULL_POLICY="${MREG_IMAGE_PULL_POLICY:-missing}"
|
|
12
|
+
# Host port the mreg container is exposed on. Override if 8000 is already in use.
|
|
13
|
+
MREG_PORT="${MREG_PORT:-8000}"
|
|
14
|
+
MREG_URL="${MREG_URL:-http://127.0.0.1:${MREG_PORT}}"
|
|
15
|
+
MREG_USERNAME="${MREG_USERNAME:-test}"
|
|
16
|
+
MREG_PASSWORD="${MREG_PASSWORD:-test}"
|
|
17
|
+
MREG_CACHE="${MREG_CACHE:-0}"
|
|
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
|
+
|
|
33
|
+
while [[ $# -gt 0 ]]; do
|
|
34
|
+
case $1 in
|
|
35
|
+
--unit-only) RUN_INTEGRATION=false; shift ;;
|
|
36
|
+
--integration-only) RUN_UNIT=false; shift ;;
|
|
37
|
+
--no-cov) RUN_COVERAGE=false; shift ;;
|
|
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
|
+
;;
|
|
45
|
+
esac
|
|
46
|
+
done
|
|
47
|
+
|
|
48
|
+
if command -v podman &>/dev/null && ! command -v docker &>/dev/null; then
|
|
49
|
+
DOCKER=podman
|
|
50
|
+
else
|
|
51
|
+
DOCKER=docker
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
if [[ "$RUN_INTEGRATION" == "true" ]]; then
|
|
55
|
+
# Check if port is already in use before starting containers
|
|
56
|
+
if lsof -i ":${MREG_PORT}" 2>/dev/null | grep -q LISTEN; then
|
|
57
|
+
echo "ERROR: Port ${MREG_PORT} is already in use." >&2
|
|
58
|
+
echo "Set MREG_PORT to a free port: MREG_PORT=8081 bash ci/run_tests.sh" >&2
|
|
59
|
+
exit 1
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
cleanup() {
|
|
63
|
+
cd "$SCRIPT_DIR"
|
|
64
|
+
$DOCKER compose down --remove-orphans 2>/dev/null || true
|
|
65
|
+
}
|
|
66
|
+
trap cleanup EXIT
|
|
67
|
+
|
|
68
|
+
cd "$SCRIPT_DIR"
|
|
69
|
+
|
|
70
|
+
echo "Starting mreg and postgres on 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
|
|
74
|
+
|
|
75
|
+
echo "Creating superuser..."
|
|
76
|
+
$DOCKER exec mreg uv run /app/manage.py create_mreg_superuser \
|
|
77
|
+
--username "$MREG_USERNAME" --password "$MREG_PASSWORD" 2>/dev/null \
|
|
78
|
+
|| $DOCKER exec mreg /app/manage.py create_mreg_superuser \
|
|
79
|
+
--username "$MREG_USERNAME" --password "$MREG_PASSWORD"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
cd "$REPO_ROOT"
|
|
85
|
+
|
|
86
|
+
UNIT_EXIT=0
|
|
87
|
+
INTEGRATION_EXIT=0
|
|
88
|
+
|
|
89
|
+
if [[ "$RUN_UNIT" == "true" ]]; then
|
|
90
|
+
echo "Running unit tests..."
|
|
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)
|
|
94
|
+
if [[ "$RUN_COVERAGE" == "true" ]]; then
|
|
95
|
+
UNIT_ARGS+=(--cov=mreg_api --cov-report=)
|
|
96
|
+
else
|
|
97
|
+
UNIT_ARGS+=(--no-cov)
|
|
98
|
+
fi
|
|
99
|
+
UNIT_ARGS+=(${EXTRA_ARGS[@]+"${EXTRA_ARGS[@]}"})
|
|
100
|
+
uv run pytest "${UNIT_ARGS[@]}" || UNIT_EXIT=$?
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
if [[ "$RUN_INTEGRATION" == "true" ]]; then
|
|
104
|
+
echo "Running integration tests..."
|
|
105
|
+
INTEGRATION_ARGS=(-m integration -v)
|
|
106
|
+
if [[ "$RUN_COVERAGE" == "true" ]]; then
|
|
107
|
+
INTEGRATION_ARGS+=(--cov=mreg_api --cov-append --cov-report=html --cov-report=term)
|
|
108
|
+
else
|
|
109
|
+
INTEGRATION_ARGS+=(--no-cov)
|
|
110
|
+
fi
|
|
111
|
+
INTEGRATION_ARGS+=(${EXTRA_ARGS[@]+"${EXTRA_ARGS[@]}"})
|
|
112
|
+
MREG_URL="$MREG_URL" \
|
|
113
|
+
MREG_USERNAME="$MREG_USERNAME" \
|
|
114
|
+
MREG_PASSWORD="$MREG_PASSWORD" \
|
|
115
|
+
uv run pytest "${INTEGRATION_ARGS[@]}" || INTEGRATION_EXIT=$?
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
if [[ $UNIT_EXIT -ne 0 || $INTEGRATION_EXIT -ne 0 ]]; then
|
|
119
|
+
exit 1
|
|
120
|
+
fi
|
|
121
|
+
exit 0
|
|
@@ -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
|
+
```
|