python-rundeck 1.1.0__tar.gz → 2.0.1__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.
- python_rundeck-2.0.1/API_COVERAGE.md +88 -0
- python_rundeck-2.0.1/CHANGELOG.md +100 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/PKG-INFO +58 -29
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/README.md +53 -24
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/pyproject.toml +12 -8
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/client.py +6 -2
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/const.py +4 -3
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/exceptions.py +1 -1
- python_rundeck-2.0.1/src/rundeck/v1/objects/acl.py +37 -0
- python_rundeck-2.0.1/src/rundeck/v1/objects/authorizations.py +45 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/jobs.py +26 -13
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/metrics.py +4 -0
- python_rundeck-2.0.1/src/rundeck/v1/objects/project_plugins.py +29 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/projects.py +28 -4
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/scheduler.py +16 -7
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/system.py +5 -2
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/tokens.py +4 -0
- python_rundeck-1.1.0/src/rundeck/v1/objects/acl.py +0 -19
- python_rundeck-1.1.0/src/rundeck/v1/objects/config_management.py +0 -64
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/LICENSE +0 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/__init__.py +0 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/base.py +0 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/config.py +0 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/py.typed +0 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/utils.py +0 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/__init__.py +0 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/__init__.py +0 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/adhoc.py +0 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/executions.py +0 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/features.py +0 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/key_storage.py +0 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/plugins.py +0 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/scm.py +0 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/users.py +0 -0
- {python_rundeck-1.1.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/webhooks.py +0 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Rundeck Community API coverage
|
|
2
|
+
|
|
3
|
+
Audited against the Community source tag [v6.3.0](https://github.com/rundeck/rundeck/tree/v6.3.0)
|
|
4
|
+
and the [6.2.1–6.3.0 changes](https://github.com/rundeck/rundeck/compare/v6.2.1...v6.3.0),
|
|
5
|
+
the [API reference](https://docs.rundeck.com/docs/api/), the
|
|
6
|
+
[OpenAPI contract](https://docs.rundeck.com/docs/files/rundeck-api.yml), and the
|
|
7
|
+
[API version history](https://docs.rundeck.com/docs/api/rundeck-api-versions.html).
|
|
8
|
+
The package defaults to API v59 and retains explicit API v14+ selection; each row
|
|
9
|
+
describes the minimum version of the operation rather than the package's oldest
|
|
10
|
+
supported API version. API v60 can be selected explicitly on 6.3.0.
|
|
11
|
+
`Community` means the operation is part of Rundeck Community.
|
|
12
|
+
|
|
13
|
+
## Community 6.3.0 compatibility (2.0.1)
|
|
14
|
+
|
|
15
|
+
No new Community routes were introduced in the compared route mappings. API v60
|
|
16
|
+
promotes `/enterprise/cluster/info` and `/enterprise/cluster/member/{memberId}`;
|
|
17
|
+
both are excluded. The Community scheduler remains available.
|
|
18
|
+
|
|
19
|
+
| HTTP | Route | Minimum API | Edition | Python interface / change | Official source | Tests |
|
|
20
|
+
|---|---|---:|---|---|---|---|
|
|
21
|
+
| POST, PUT | `/system/acl/{name}`, `/project/{project}/acl/{name}` | 17 system / 13 project | Community | JSON `contents` writes; unchanged YAML reads | API ACL reference; RUN-4790 | `test_community_630.py`, `test_system_acl.py`, `test_project_acl.py` (unit); `test_acl_json_lifecycle`, `test_yaml_request_json_response_regression` (integration) |
|
|
22
|
+
| GET; GET, POST | `/job/{id}/meta`, `/project/{project}/jobs/browse` | 46 | Community | Preserve `executionAclValid` metadata, including false values; added in server 6.3.0 | `JobExecutionAclMetadataComponent` at v6.3.0 | `test_job_metadata_is_raw_for_get_and_browse` (unit); `test_job_acl_metadata` (integration) |
|
|
23
|
+
| GET | `/plugin/list`, `/plugin/detail/{service}/{provider}` | 14 / 49 | Community | Preserve `outputs` and property `outputMetadata` | `PluginApiService` at v6.3.0 | `test_plugin_fields_are_preserved` (unit); existing plugin integrations |
|
|
24
|
+
| PUT | `/project/{project}/import` | 14 | Community | Additional configure permission for configuration or node-source import in server 6.3.0 | `ProjectController.apiProjectImport`, PR #10650 | `test_archive_permission_error_keeps_false_options_and_details` (unit); `test_archive_import_requires_configure` (integration) |
|
|
25
|
+
| POST | `/webhook/{token}` | 30 | Community | Opaque public secret unchanged by server-side token hashing | `WebhookService` and `WebhookTokenSecureMigrationService` at v6.3.0 | `test_webhook_event_send_supports_json_and_data` (unit); `test_project_webhook_lifecycle_and_send` (integration) |
|
|
26
|
+
| GET | `/metrics/*`, `/monitoring/*` | legacy / unversioned | Community | Docker legacy metrics variable honored in server 6.3.0 | RUN-4859 | `test_legacy_metrics_enabled_by_docker_variable`, existing monitoring integrations |
|
|
27
|
+
|
|
28
|
+
Server-version features above are not gated on the selected API version. The
|
|
29
|
+
`executionAclValid` warning does not enforce execution permissions. The source
|
|
30
|
+
tag restores the `${job.serverUrl}` trailing slash (RUN-5051); no URL rewrite is
|
|
31
|
+
performed by this client. Session cookies follow requests' standard behavior.
|
|
32
|
+
|
|
33
|
+
## Added or corrected in 2.0.0
|
|
34
|
+
|
|
35
|
+
| HTTP | Route | Minimum API | Edition | Python interface | Official reference | Test |
|
|
36
|
+
|---|---|---:|---|---|---|---|
|
|
37
|
+
| GET | `/api/{v}/` | 14 | Community | `Rundeck.api_info()` | API root / API reference | `tests/unit/test_community_v59.py::test_api_info_and_default_api_version` |
|
|
38
|
+
| GET | `/api/{v}/home/summary` | 14 | Community | `rd.system.summary()` | System endpoints | `tests/unit/test_community_v59.py::test_system_summary_scheduler_and_expired_tokens_routes` |
|
|
39
|
+
| GET | `/api/{v}/scheduler/jobs` | 14 | Community | `rd.scheduler.jobs()` | Scheduler endpoints; v6.2.1 route mapping | `tests/unit/test_community_v59.py::test_system_summary_scheduler_and_expired_tokens_routes` |
|
|
40
|
+
| GET | `/api/{v}/scheduler/server/{uuid}/jobs` | 14 | Community | `rd.scheduler.jobs(server_uuid=...)` | Scheduler endpoints; v6.2.1 route mapping | `tests/unit/test_community_v59.py::test_system_summary_scheduler_and_expired_tokens_routes` |
|
|
41
|
+
| PUT | `/api/{v}/scheduler/takeover` | 14 | Community | `rd.scheduler.takeover(job_id=... or job_ids=[...])` | Scheduler endpoints; v6.2.1 route mapping | `tests/unit/test_scheduler.py` |
|
|
42
|
+
| POST | `/api/{v}/tokens/{user}/removeExpired` | 14 | Community | `rd.tokens.remove_expired(user)` | Tokens endpoints | `tests/unit/test_community_v59.py::test_system_summary_scheduler_and_expired_tokens_routes` |
|
|
43
|
+
| GET | `/monitoring/health/readiness` | n/a | Community | `rd.monitoring.readiness()` | Monitoring endpoints | `tests/unit/test_community_v59.py::test_async_export_post_uses_form_and_monitoring_readiness_is_unversioned` |
|
|
44
|
+
| POST | `/api/{v}/project/{project}/jobs/validateOption` | 47 | Community | `rd.jobs.validate_option(...)` / `project.jobs.validate_option(...)` | Jobs endpoints | `tests/unit/test_community_v59.py::test_option_validation_preserves_false_and_project_context` |
|
|
45
|
+
| POST | `/api/{v}/project/{project}/plugins/save` | 55 | Community | `project.plugins.save(...)` | Project plugin configuration | `tests/unit/test_community_v59.py::test_project_plugins_and_browse_post_contracts` |
|
|
46
|
+
| POST | `/api/{v}/project/{project}/jobs/browse` | 46 | Community | `rd.jobs.browse(..., use_post=True)` | Jobs browse endpoint | `tests/unit/test_community_v59.py::test_project_plugins_and_browse_post_contracts` |
|
|
47
|
+
| POST | `/api/{v}/project/{project}/export/async` | 14 | Community | `project.archive.export_async(..., use_post=True)` | Project archive endpoints | `tests/unit/test_community_v59.py::test_async_export_post_uses_form_and_monitoring_readiness_is_unversioned` |
|
|
48
|
+
| GET | `/api/{v}/authorizations/application/{kind}` | 14 | Community, experimental | `rd.authorizations.application_kind(...)` | Authorization evaluation endpoints | `tests/unit/test_community_v59.py::test_authorization_routes_repeat_actions_as_values` |
|
|
49
|
+
| GET | `/api/{v}/authorizations/application/{type}/{specifier}` | 14 | Community, experimental | `rd.authorizations.application_resource(...)` | Authorization evaluation endpoints | `tests/unit/test_community_v59.py::test_authorization_routes_repeat_actions_as_values` |
|
|
50
|
+
| GET | `/api/{v}/authorizations/project/{project}/{kind}` | 14 | Community, experimental | `rd.authorizations.project_kind(...)` | Authorization evaluation endpoints | `tests/unit/test_community_v59.py::test_authorization_routes_repeat_actions_as_values` |
|
|
51
|
+
| GET | `/api/{v}/authorizations/project/{project}/{type}/{specifier}` | 14 | Community, experimental | `rd.authorizations.project_resource(...)` | Authorization evaluation endpoints | `tests/unit/test_community_v59.py::test_authorization_routes_repeat_actions_as_values` |
|
|
52
|
+
| GET | `/api/{v}/authorizations/project/{project}/job/{id}` | 14 | Community, experimental | `rd.authorizations.project_job(...)` | Authorization evaluation endpoints | `tests/unit/test_community_v59.py::test_authorization_routes_repeat_actions_as_values` |
|
|
53
|
+
| GET | `/api/{v}/system/acl/{name}` | 14 | Community | `rd.system.acl.get(name)` (`Accept: application/yaml`) | System ACL endpoints | `tests/unit/test_system_acl.py` |
|
|
54
|
+
| GET | `/api/{v}/project/{project}/acl/{name}` | 14 | Community | `project.acl.get(name)` (`Accept: application/yaml`) | Project ACL endpoints | `tests/unit/test_project_acl.py` |
|
|
55
|
+
|
|
56
|
+
The authorization evaluation API is documented as experimental. `actions` is
|
|
57
|
+
sent as a repeated query parameter. Job browse POST keeps metadata and path
|
|
58
|
+
parameters in the query and sends search filters as JSON. Async archive POST
|
|
59
|
+
uses form encoding for execution IDs. `Execution.get_output()` returns the
|
|
60
|
+
server payload unchanged in both historical API v58 and compacted API v59 modes.
|
|
61
|
+
|
|
62
|
+
## Existing Community operations
|
|
63
|
+
|
|
64
|
+
The following endpoint families are also exposed by this package and are checked
|
|
65
|
+
by their focused unit tests. Paths below use `{v}` for the selected `/api/{v}`
|
|
66
|
+
prefix. See each test module for the supported verbs, request fields, response
|
|
67
|
+
handling, and pagination behavior.
|
|
68
|
+
|
|
69
|
+
| HTTP | Route(s) | Minimum API | Edition | Python interface | Official reference | Test |
|
|
70
|
+
|---|---|---:|---|---|---|---|
|
|
71
|
+
| GET, POST, PUT, DELETE | `/project`, `/project/{project}`, `/project/{project}/resources`, `/project/{project}/config`, `/project/{project}/readme`, `/project/{project}/motd`, `/project/{project}/history`, `/project/{project}/acl/{name}` | 14 | Community | `rd.projects` and nested project managers | Projects endpoints | `tests/unit/test_project_*.py`, `tests/unit/test_project_acl.py` |
|
|
72
|
+
| GET, POST, PUT, DELETE | `/project/{project}/jobs`, `/job/{id}`, `/job/{id}/run`, `/job/{id}/executions`, `/project/{project}/jobs/bulk`, `/project/{project}/jobs/delete`, `/project/{project}/jobs/browse` | 14 (browse 46) | Community | `rd.jobs`, `project.jobs`, `Job` | Jobs endpoints | `tests/unit/test_jobs.py`, `tests/unit/test_community_v59.py` |
|
|
73
|
+
| GET, POST, PUT, DELETE | `/execution/{id}`, `/execution/{id}/output`, `/execution/{id}/state`, `/execution/{id}/abort`, `/execution/{id}/retry`, `/project/{project}/executions` | 14 | Community | `rd.executions`, `Execution` | Executions endpoints | `tests/unit/test_executions.py` |
|
|
74
|
+
| GET, POST, PUT, DELETE | `/system/acl`, `/system/executions/{enable,disable,status}`, `/system/logstorage`, `/system/keys/{path}` | 14 | Community | `rd.system`, `rd.keys` | System, key storage endpoints | `tests/unit/test_system_*.py`, `tests/unit/test_key_storage.py` |
|
|
75
|
+
| GET, POST, DELETE | `/tokens`, `/tokens/{id}`, `/tokens/{user}/removeExpired`, `/user`, `/user/{login}` | 14 | Community | `rd.tokens`, `rd.users` | Tokens and user endpoints | `tests/unit/test_tokens.py`, `tests/unit/test_users.py` |
|
|
76
|
+
| GET, POST, PUT, DELETE | `/project/{project}/scm/{plugin}/{action}`, `/plugin/{service}/{name}`, `/project/{project}/webhooks` | 14 | Community | SCM, plugin, and webhook managers | SCM, plugins, webhooks endpoints | `tests/unit/test_project_scm.py`, `tests/unit/test_plugins.py`, `tests/unit/test_webhooks.py` |
|
|
77
|
+
| GET | `/metrics[/metrics|/healthcheck|/ping|/threads]`, `/monitoring[/metrics|/health|/info|/prometheus|/threaddump]` | 14 / unversioned | Community | `rd.metrics`, `rd.monitoring` | Metrics and monitoring endpoints | `tests/unit/test_metrics.py` |
|
|
78
|
+
| POST | `/run/command`, `/project/{project}/run/command` | 14 | Community | `rd.run_command`, `project.run_command` | Command execution endpoint | `tests/unit/test_adhoc.py` |
|
|
79
|
+
|
|
80
|
+
## Excluded commercial surfaces
|
|
81
|
+
|
|
82
|
+
| Removed interface / route | Reason | Verification |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| `rd.config_management` (`/config/...`) | Commercial Config Management product surface | `tests/unit/test_community_v59.py::test_api_info_and_default_api_version` |
|
|
85
|
+
| `Job.tags()` (`/job/{id}/tags`) | Commercial endpoint absent from the Community v6.2.1 contract | `tests/unit/test_jobs.py` |
|
|
86
|
+
|
|
87
|
+
Commercial-only calendars, runners, licenses, and other product-specific routes
|
|
88
|
+
are outside this client’s Community API coverage.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
|
+
|
|
8
|
+
## [2.0.1] - 2026-11-08
|
|
9
|
+
### Fixed
|
|
10
|
+
- Refresh vulnerable locked dependencies to their latest compatible stable releases;
|
|
11
|
+
require Requests 2.33+, Black 26.3.1+ and pytest 9.0.3+.
|
|
12
|
+
- Refresh the virtual environment's pip before auditing cached CI environments.
|
|
13
|
+
- ACL writes use the official JSON `contents` envelope and request JSON responses,
|
|
14
|
+
avoiding raw YAML response errors while retaining YAML reads and public return types.
|
|
15
|
+
- ACL reads unwrap older controllers' JSON envelopes even when YAML was requested.
|
|
16
|
+
- Integration webhook discovery now fails if the created resource disappears.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- Rundeck Community 6.3.0 integration coverage in API v59 and v60, alongside
|
|
20
|
+
6.2.1/v59, 6.0.1/v58 and 5.18.0/v56 compatibility targets.
|
|
21
|
+
- Regression coverage for job execution ACL metadata, plugin output metadata,
|
|
22
|
+
archive import permissions, forwarded session cookies and legacy Docker metrics.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
- Current known API is v60; the default remains v59. Enterprise v60 endpoints remain excluded.
|
|
26
|
+
- Local integration image defaults to `rundeck/rundeck:6.3.0-20261022`.
|
|
27
|
+
- Integration containers are isolated by Compose project and cleaned up on failures.
|
|
28
|
+
- Gitflow feature branches run the integration and Python compatibility matrices.
|
|
29
|
+
|
|
30
|
+
## [2.0.0] - 2026-10-10
|
|
31
|
+
### Added
|
|
32
|
+
- Community API v59 support, including API discovery, system summary, scheduler job
|
|
33
|
+
listing, expired-token cleanup, monitoring readiness, option validation, project
|
|
34
|
+
plugin configuration, POST job browsing, and asynchronous archive export.
|
|
35
|
+
- Experimental authorization-evaluation endpoints and a Community API coverage matrix.
|
|
36
|
+
- Community integration defaults for Rundeck 6.2.1/API v59, with documented 6.0.1/v58
|
|
37
|
+
and 5.18.0/v56 compatibility runs.
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
- Default API version is now v59; explicitly selected older versions remain supported.
|
|
41
|
+
- System and project ACL reads explicitly request YAML. HTTP 422 responses map to
|
|
42
|
+
`RundeckValidationError` while retaining the response body.
|
|
43
|
+
- Scheduler cluster takeover accepts one or multiple job IDs. In Community without
|
|
44
|
+
cluster mode, takeover has no scheduling state to transfer.
|
|
45
|
+
|
|
46
|
+
### Removed
|
|
47
|
+
- Removed commercial Config Management interfaces and `Job.tags()`.
|
|
48
|
+
|
|
49
|
+
## [1.1.0] - 2026-07-25
|
|
50
|
+
### Added
|
|
51
|
+
- Support for `user_agent` and `config_section` parameters in the client configuration.
|
|
52
|
+
- API v57/v58 support: execution metrics, job browse, `metaExclude`, modern
|
|
53
|
+
monitoring endpoints, and v56/v57 response metadata coverage.
|
|
54
|
+
- Community endpoints for project history/meta/node tags, execution input and
|
|
55
|
+
output state, job executions, project SCM toggle, and current-user update.
|
|
56
|
+
|
|
57
|
+
### Changed
|
|
58
|
+
- `__version__` now resolves from the installed package metadata, with a local
|
|
59
|
+
fallback to `pyproject.toml` when the package is not installed.
|
|
60
|
+
- README configuration section updated to include `user_agent` and `config_section`.
|
|
61
|
+
- Default Rundeck API version updated to v58; the client retains v14
|
|
62
|
+
compatibility and documents the current server minimum v17 and v34 deprecation.
|
|
63
|
+
- Corrected Community routes and verbs for job forecasts, resource model
|
|
64
|
+
sources, bulk job actions, bulk job deletion, and job pagination.
|
|
65
|
+
- `Job.tags` and Config Management were incorrectly grouped with scheduler
|
|
66
|
+
cluster operations in this entry. The first two are commercial surfaces;
|
|
67
|
+
scheduler listing and takeover are Community endpoints and remain supported.
|
|
68
|
+
|
|
69
|
+
## [1.0.1] - 2026-01-21
|
|
70
|
+
### Changed
|
|
71
|
+
- CI: skip lint/tests on `main` and build only on tags.
|
|
72
|
+
- Classifier updated to `Development Status :: 5 - Production/Stable`.
|
|
73
|
+
|
|
74
|
+
## [1.0.0] - 2026-01-21
|
|
75
|
+
### Changed
|
|
76
|
+
- `Job.run` and `Job.retry` now return raw responses by default and support `as_execution=True` for `Execution`.
|
|
77
|
+
- `RundeckObject.refresh` and `Execution.refresh` now return `None` (in-place update).
|
|
78
|
+
- `User.update` now returns the raw response and updates the object in place.
|
|
79
|
+
- Key storage API now uses `StorageKey` objects for `create`/`update`, moves raw content access to `StorageKey.content()`, renames `get_metadata` to `get`, and supports updating via `StorageKey.update()`.
|
|
80
|
+
- System ACL policies are treated as resources and `SystemACL.update()` now updates the object in place.
|
|
81
|
+
- Project webhooks are treated as resources (`project.webhooks`), while event sending remains a utility manager.
|
|
82
|
+
|
|
83
|
+
## [0.3.0] - 2026-01-14
|
|
84
|
+
### Added
|
|
85
|
+
- README badges for PyPI version, supported Python versions, license, and downloads.
|
|
86
|
+
- Contributor dev setup note in README.
|
|
87
|
+
|
|
88
|
+
### Changed
|
|
89
|
+
- README translated to English.
|
|
90
|
+
- Installation section now targets PyPI installs.
|
|
91
|
+
- GitLab CI PyPI deployment uses verbose `twine upload`.
|
|
92
|
+
|
|
93
|
+
## [0.2.0] - 2026-01-12
|
|
94
|
+
### Added
|
|
95
|
+
- Project metadata URLs in `pyproject.toml` (Homepage, Repository, Documentation, Issues, Changelog).
|
|
96
|
+
- Changelog file to track releases.
|
|
97
|
+
|
|
98
|
+
## [0.1.0] - 2026-01-11
|
|
99
|
+
### Added
|
|
100
|
+
- Initial release of the python-rundeck client library.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-rundeck
|
|
3
|
-
Version:
|
|
4
|
-
Summary: Python client for the Rundeck API (v14-
|
|
3
|
+
Version: 2.0.1
|
|
4
|
+
Summary: Python client for the Rundeck Community API (v14-v60, default v59).
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
Keywords: rundeck,api,client
|
|
@@ -21,12 +21,12 @@ Classifier: Topic :: System :: Systems Administration
|
|
|
21
21
|
Classifier: Typing :: Typed
|
|
22
22
|
Provides-Extra: dev
|
|
23
23
|
Requires-Dist: bandit (>=1.7.9,<2.0.0) ; extra == "dev"
|
|
24
|
-
Requires-Dist: black (>=
|
|
24
|
+
Requires-Dist: black (>=26.3.1,<27.0.0) ; extra == "dev"
|
|
25
25
|
Requires-Dist: flake8 (>=7.0.0,<8.0.0) ; extra == "dev"
|
|
26
26
|
Requires-Dist: isort (>=7.0.0,<8.0.0) ; extra == "dev"
|
|
27
|
-
Requires-Dist: pytest (>=9.0.
|
|
27
|
+
Requires-Dist: pytest (>=9.0.3,<10.0.0) ; extra == "dev"
|
|
28
28
|
Requires-Dist: pytest-cov (>=5.0.0,<6.0.0) ; extra == "dev"
|
|
29
|
-
Requires-Dist: requests (>=2.
|
|
29
|
+
Requires-Dist: requests (>=2.33.0,<3.0.0)
|
|
30
30
|
Requires-Dist: ruff (>=0.7.0,<1.0.0) ; extra == "dev"
|
|
31
31
|
Requires-Dist: safety (>=3.2.0,<4.0.0) ; extra == "dev"
|
|
32
32
|
Project-URL: Changelog, https://gitlab.com/pascal.seckinger/python-rundeck/-/blob/main/CHANGELOG.md
|
|
@@ -43,7 +43,9 @@ python-rundeck
|
|
|
43
43
|

|
|
44
44
|

|
|
45
45
|
|
|
46
|
-
Python client for the Rundeck API (v14-
|
|
46
|
+
Python client for the Rundeck Community API (v14-v60), inspired by the python-gitlab architecture. Rundeck Community 6.3.0 is the integration reference. The default API version remains v59; use `api_version=60` explicitly with 6.3.0. Current Rundeck servers require v17 or later and versions below v34 are deprecated. Provides typed managers for Community resources (projects, jobs, executions, tokens, users, system) and SCM (import/export).
|
|
47
|
+
|
|
48
|
+
Version 2.0 removes commercial-only Config Management and job-tag endpoints. Cluster schedule listing and takeover are Community operations and remain available. The authorization-evaluation endpoints are experimental in Rundeck and are exposed as such by this client.
|
|
47
49
|
|
|
48
50
|
Contents
|
|
49
51
|
--------
|
|
@@ -69,9 +71,9 @@ Quick start
|
|
|
69
71
|
```python
|
|
70
72
|
from rundeck.client import Rundeck
|
|
71
73
|
|
|
72
|
-
rd = Rundeck(url="https://rundeck.example.com", token="MY_TOKEN"
|
|
74
|
+
rd = Rundeck(url="https://rundeck.example.com", token="MY_TOKEN")
|
|
73
75
|
# Password auth (session cookie) if no token
|
|
74
|
-
rd = Rundeck(url="https://rundeck.example.com", username="admin", password="admin"
|
|
76
|
+
rd = Rundeck(url="https://rundeck.example.com", username="admin", password="admin")
|
|
75
77
|
|
|
76
78
|
# List projects
|
|
77
79
|
projects = rd.projects.list()
|
|
@@ -94,7 +96,7 @@ Main parameters:
|
|
|
94
96
|
- `url`: Rundeck URL (e.g. `https://rundeck.example.com`)
|
|
95
97
|
- `token`: API token (header `X-Rundeck-Auth-Token`)
|
|
96
98
|
- `username` / `password`: Session authentication (j_security_check) if no token is provided.
|
|
97
|
-
- `api_version`: API version (default: `
|
|
99
|
+
- `api_version`: API version (default: `59`; older versions can be selected explicitly)
|
|
98
100
|
- `timeout`: Request timeout (float, seconds)
|
|
99
101
|
- `ssl_verify`: TLS verification (bool or CA path)
|
|
100
102
|
- `user_agent`: Custom HTTP User-Agent (string)
|
|
@@ -105,7 +107,7 @@ Useful env vars (client config):
|
|
|
105
107
|
- `RUNDECK_URL`: Base URL
|
|
106
108
|
- `RUNDECK_TOKEN`: API token (header `X-Rundeck-Auth-Token`)
|
|
107
109
|
- `RUNDECK_USERNAME` / `RUNDECK_PASSWORD`: Session auth (if no token)
|
|
108
|
-
- `RUNDECK_API_VERSION`: API version (
|
|
110
|
+
- `RUNDECK_API_VERSION`: API version (default `59`; older server versions can be selected explicitly)
|
|
109
111
|
- `RUNDECK_TIMEOUT`: Request timeout (seconds)
|
|
110
112
|
- `RUNDECK_SSL_VERIFY`: TLS verification (bool or CA path)
|
|
111
113
|
- `RUNDECK_USER_AGENT`: HTTP User-Agent
|
|
@@ -120,14 +122,14 @@ Available resources
|
|
|
120
122
|
- `tokens` (`TokenManager`): list, get, create, delete.
|
|
121
123
|
- `users` (`UserManager`): user operations (per current implementation).
|
|
122
124
|
- `metrics` (`MetricsManager`): legacy `/api/V/metrics` endpoints (list/data/healthcheck/ping/threads).
|
|
123
|
-
- `monitoring` (`MonitoringManager`): modern non-versioned `/monitoring/*` endpoints (Prometheus, metrics, health, info, thread dump).
|
|
125
|
+
- `monitoring` (`MonitoringManager`): modern non-versioned `/monitoring/*` endpoints (Prometheus, metrics, health, readiness, info, thread dump).
|
|
126
|
+
- `authorizations` (`AuthorizationsManager`): experimental authorization evaluation endpoints.
|
|
124
127
|
- `plugins` (`PluginManager`): list installed plugins (`/plugin/list`).
|
|
125
128
|
- `webhooks` (`WebhookEventManager` + `ProjectWebhookManager`): project webhook management and sending via token.
|
|
126
129
|
- `key_storage` (`StorageKeyManager`): key storage management `/storage/keys`.
|
|
127
130
|
- `adhoc` (`AdhocManager`, via `project.adhoc`): run AdHoc commands/scripts.
|
|
128
|
-
- `system` (`SystemManager`): system info, executions enable/disable, logstorage, ACL.
|
|
129
|
-
- `
|
|
130
|
-
- `scheduler` (`SchedulerManager`): cluster scheduler takeover (commercial, deprecated and scheduled for removal in 2.0).
|
|
131
|
+
- `system` (`SystemManager`): system info and summary, executions enable/disable, logstorage, ACL.
|
|
132
|
+
- `scheduler` (`SchedulerManager`): scheduled job listing and cluster schedule takeover (Community).
|
|
131
133
|
- `scm` (via `project.scm` and `job.scm`): import/export plugins, setup, enable/disable, status, actions (commit/import/export...).
|
|
132
134
|
|
|
133
135
|
Return types policy
|
|
@@ -148,7 +150,7 @@ Factory managers:
|
|
|
148
150
|
Returns `Execution` objects (execution factory).
|
|
149
151
|
|
|
150
152
|
Utility managers:
|
|
151
|
-
- `system`, `
|
|
153
|
+
- `system`, `metrics`, `scheduler`, `webhooks` (event send), `authorizations` (experimental).
|
|
152
154
|
- `scm` (via `project.scm` and `job.scm`), and project sub-managers like
|
|
153
155
|
`project.config`, `project.resources`, `project.sources`, `project.readme`,
|
|
154
156
|
`project.archive`, `project.acl`.
|
|
@@ -156,6 +158,23 @@ Utility managers:
|
|
|
156
158
|
Note: `project.webhooks.create(...)` returns the raw API response (e.g., `{"msg": "Saved webhook"}`)
|
|
157
159
|
because the Rundeck API does not return the created webhook object.
|
|
158
160
|
|
|
161
|
+
Compatibility with Community 6.3.0 (2.0.1)
|
|
162
|
+
---------------------------------------
|
|
163
|
+
- API v60 is recognized; the default stays v59 to retain compatibility with Community 6.2.1. The new v60 cluster endpoints are Enterprise-only and excluded.
|
|
164
|
+
- ACL creation and updates send the YAML text inside a JSON `contents` envelope and request JSON responses. Reads still request YAML and unwrap legacy JSON responses from older project ACL controllers. Python signatures and resource return conventions are unchanged.
|
|
165
|
+
- `job.meta(meta="executionAclValid")` and `project.jobs.browse(meta="executionAclValid")` expose the server's saved-user authorization warning. It does not block execution. Plugin `outputs` and property `outputMetadata` are preserved when returned by the server.
|
|
166
|
+
- Archive imports with `importConfig=True` or `importNodesSources=True` also require project `configure` authorization on 6.3.0. Use explicit `False` values for jobs-only imports. Authorization failures retain the server response in `RundeckAuthenticationError.response_body`.
|
|
167
|
+
- Webhook tokens remain opaque public secrets. The server handles hashing and migration; callers must continue sending the original secret.
|
|
168
|
+
- Session authentication uses standard cookie handling; 6.3.0 fixes direct HTTP authentication when the public URL is HTTPS behind forwarded headers.
|
|
169
|
+
- The stable 6.3.0 sources restore the trailing slash on `${job.serverUrl}` (RUN-5051), despite the earlier release-note wording. The client does not rewrite job context URLs.
|
|
170
|
+
|
|
171
|
+
Migration from 1.1.0
|
|
172
|
+
-------------------
|
|
173
|
+
- Set `api_version=59` explicitly when upgrading a server/client pair gradually; the default is now 59.
|
|
174
|
+
- Remove calls to `rd.config_management` and `job.tags()`: their endpoints are only available in commercial Rundeck products.
|
|
175
|
+
- `rd.scheduler.takeover()` and scheduler job listing remain supported by Community. On a non-cluster server, takeover returns a successful response indicating that no action was performed.
|
|
176
|
+
- `rd.authorizations` wraps experimental endpoints and can change with Rundeck releases.
|
|
177
|
+
|
|
159
178
|
Example:
|
|
160
179
|
```python
|
|
161
180
|
job = rd.jobs.get("job-id") # -> Job (object)
|
|
@@ -468,17 +487,6 @@ if features:
|
|
|
468
487
|
print(first.name, status.enabled)
|
|
469
488
|
```
|
|
470
489
|
|
|
471
|
-
Global configuration `/config`
|
|
472
|
-
```python
|
|
473
|
-
# Commercial compatibility surface; deprecated and removed in 2.0.
|
|
474
|
-
cfg = rd.config_management
|
|
475
|
-
all_configs = cfg.list()
|
|
476
|
-
cfg.save([{"key": "ui.banner", "value": "Hello"}])
|
|
477
|
-
cfg.delete("ui.banner", strata="default")
|
|
478
|
-
cfg.refresh()
|
|
479
|
-
cfg.restart()
|
|
480
|
-
```
|
|
481
|
-
|
|
482
490
|
Monitoring
|
|
483
491
|
----------
|
|
484
492
|
```python
|
|
@@ -490,6 +498,24 @@ thread_dump = rd.monitoring.thread_dump()
|
|
|
490
498
|
|
|
491
499
|
# Legacy metrics require rundeck.metrics.legacy.enabled=true on Rundeck 6.0.
|
|
492
500
|
legacy_threads = rd.metrics.threads()
|
|
501
|
+
ready = rd.monitoring.readiness()
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
Community additions
|
|
505
|
+
-------------------
|
|
506
|
+
```python
|
|
507
|
+
api_info = rd.api_info()
|
|
508
|
+
summary = rd.system.summary()
|
|
509
|
+
scheduled_jobs = rd.scheduler.jobs()
|
|
510
|
+
rd.tokens.remove_expired("admin") # use "*" with suitable administrator rights
|
|
511
|
+
|
|
512
|
+
project = rd.projects.get("demo")
|
|
513
|
+
project.plugins.save("ResourceModelSource", "resources.source", plugins=[])
|
|
514
|
+
project.archive.export_async(execution_ids=["1", "2"], use_post=True)
|
|
515
|
+
project.jobs.validate_option(option_data, job_was_scheduled=False)
|
|
516
|
+
|
|
517
|
+
# Experimental authorization API; actions are repeated query parameters.
|
|
518
|
+
permissions = rd.authorizations.application_kind("job", ["read", "run"])
|
|
493
519
|
```
|
|
494
520
|
|
|
495
521
|
Pagination
|
|
@@ -510,13 +536,16 @@ Development and testing
|
|
|
510
536
|
- Formatting/Lint: `black src/rundeck tests/`, `ruff check src/rundeck tests/`
|
|
511
537
|
- Typing: `mypy src/rundeck/`
|
|
512
538
|
- Tests: `pytest`
|
|
513
|
-
- Local integration tests: `scripts/run-integration.sh` starts
|
|
539
|
+
- Local integration tests: `scripts/run-integration.sh` starts `rundeck/rundeck:6.3.0-20261022` with API v59. Each run has an isolated Compose project and cleans up even when tests fail. With `KEEP_STACK=1`, the script prints the project name needed by `scripts/stop-integration.sh`.
|
|
540
|
+
- GitLab runs five integration targets: 6.3.0/API 59, 6.3.0/API 60, 6.2.1/API 59, 6.0.1/API 58 and 5.18.0/API 56. Set `RUNDECK_IMAGE` and `RUNDECK_API_VERSION` to run each target locally. Python compatibility tests retain 3.11–3.15 (3.15-rc Docker image).
|
|
541
|
+
- To exercise the 6.3.0 session regression and legacy metrics: `RUNDECK_PUBLIC_URL=https://rundeck.example.invalid RUNDECK_METRICS_LEGACY_ENABLED=true scripts/run-integration.sh`. The client still connects to `RUNDECK_URL` (default `http://localhost:4440`). The public URL defaults to the client URL, ensuring session redirects also work on older servers. Optional `RUNDECK_HTTP_PORT` changes the published port; set `RUNDECK_URL` accordingly.
|
|
514
542
|
- The docker compose stack mounts `tokens.properties` at the repo root to seed a local admin token for integration tests. This file is only intended for local testing.
|
|
543
|
+
- Run local compatibility targets sequentially, stopping each stack before starting the next. This keeps at most one Rundeck JVM and one PostgreSQL container active.
|
|
515
544
|
|
|
516
545
|
Code structure
|
|
517
546
|
--------------
|
|
518
547
|
- `src/rundeck/base.py`: generic objects/managers, `_build_path` helpers, pagination, CRUD.
|
|
519
548
|
- `src/rundeck/client.py`: HTTP client, `http_get/post/put/delete/list` methods.
|
|
520
|
-
- `src/rundeck/v1/objects/`: domain managers and objects (projects, jobs, executions, system, tokens, users,
|
|
521
|
-
- Managers/objects schema: we apply the manager -> object pattern wherever the API exposes an identifiable resource (jobs, projects, users, tokens, executions, etc.). For
|
|
549
|
+
- `src/rundeck/v1/objects/`: Community domain managers and objects (projects, jobs, executions, system, tokens, users, authorizations).
|
|
550
|
+
- Managers/objects schema: we apply the manager -> object pattern wherever the API exposes an identifiable resource (jobs, projects, users, tokens, executions, etc.). For global or utility endpoints without a resource (e.g., `/system`, `/scheduler`, `/metrics`), we use dedicated sub-managers rather than forcing an artificial object.
|
|
522
551
|
|
|
@@ -5,7 +5,9 @@ python-rundeck
|
|
|
5
5
|

|
|
6
6
|

|
|
7
7
|
|
|
8
|
-
Python client for the Rundeck API (v14-
|
|
8
|
+
Python client for the Rundeck Community API (v14-v60), inspired by the python-gitlab architecture. Rundeck Community 6.3.0 is the integration reference. The default API version remains v59; use `api_version=60` explicitly with 6.3.0. Current Rundeck servers require v17 or later and versions below v34 are deprecated. Provides typed managers for Community resources (projects, jobs, executions, tokens, users, system) and SCM (import/export).
|
|
9
|
+
|
|
10
|
+
Version 2.0 removes commercial-only Config Management and job-tag endpoints. Cluster schedule listing and takeover are Community operations and remain available. The authorization-evaluation endpoints are experimental in Rundeck and are exposed as such by this client.
|
|
9
11
|
|
|
10
12
|
Contents
|
|
11
13
|
--------
|
|
@@ -31,9 +33,9 @@ Quick start
|
|
|
31
33
|
```python
|
|
32
34
|
from rundeck.client import Rundeck
|
|
33
35
|
|
|
34
|
-
rd = Rundeck(url="https://rundeck.example.com", token="MY_TOKEN"
|
|
36
|
+
rd = Rundeck(url="https://rundeck.example.com", token="MY_TOKEN")
|
|
35
37
|
# Password auth (session cookie) if no token
|
|
36
|
-
rd = Rundeck(url="https://rundeck.example.com", username="admin", password="admin"
|
|
38
|
+
rd = Rundeck(url="https://rundeck.example.com", username="admin", password="admin")
|
|
37
39
|
|
|
38
40
|
# List projects
|
|
39
41
|
projects = rd.projects.list()
|
|
@@ -56,7 +58,7 @@ Main parameters:
|
|
|
56
58
|
- `url`: Rundeck URL (e.g. `https://rundeck.example.com`)
|
|
57
59
|
- `token`: API token (header `X-Rundeck-Auth-Token`)
|
|
58
60
|
- `username` / `password`: Session authentication (j_security_check) if no token is provided.
|
|
59
|
-
- `api_version`: API version (default: `
|
|
61
|
+
- `api_version`: API version (default: `59`; older versions can be selected explicitly)
|
|
60
62
|
- `timeout`: Request timeout (float, seconds)
|
|
61
63
|
- `ssl_verify`: TLS verification (bool or CA path)
|
|
62
64
|
- `user_agent`: Custom HTTP User-Agent (string)
|
|
@@ -67,7 +69,7 @@ Useful env vars (client config):
|
|
|
67
69
|
- `RUNDECK_URL`: Base URL
|
|
68
70
|
- `RUNDECK_TOKEN`: API token (header `X-Rundeck-Auth-Token`)
|
|
69
71
|
- `RUNDECK_USERNAME` / `RUNDECK_PASSWORD`: Session auth (if no token)
|
|
70
|
-
- `RUNDECK_API_VERSION`: API version (
|
|
72
|
+
- `RUNDECK_API_VERSION`: API version (default `59`; older server versions can be selected explicitly)
|
|
71
73
|
- `RUNDECK_TIMEOUT`: Request timeout (seconds)
|
|
72
74
|
- `RUNDECK_SSL_VERIFY`: TLS verification (bool or CA path)
|
|
73
75
|
- `RUNDECK_USER_AGENT`: HTTP User-Agent
|
|
@@ -82,14 +84,14 @@ Available resources
|
|
|
82
84
|
- `tokens` (`TokenManager`): list, get, create, delete.
|
|
83
85
|
- `users` (`UserManager`): user operations (per current implementation).
|
|
84
86
|
- `metrics` (`MetricsManager`): legacy `/api/V/metrics` endpoints (list/data/healthcheck/ping/threads).
|
|
85
|
-
- `monitoring` (`MonitoringManager`): modern non-versioned `/monitoring/*` endpoints (Prometheus, metrics, health, info, thread dump).
|
|
87
|
+
- `monitoring` (`MonitoringManager`): modern non-versioned `/monitoring/*` endpoints (Prometheus, metrics, health, readiness, info, thread dump).
|
|
88
|
+
- `authorizations` (`AuthorizationsManager`): experimental authorization evaluation endpoints.
|
|
86
89
|
- `plugins` (`PluginManager`): list installed plugins (`/plugin/list`).
|
|
87
90
|
- `webhooks` (`WebhookEventManager` + `ProjectWebhookManager`): project webhook management and sending via token.
|
|
88
91
|
- `key_storage` (`StorageKeyManager`): key storage management `/storage/keys`.
|
|
89
92
|
- `adhoc` (`AdhocManager`, via `project.adhoc`): run AdHoc commands/scripts.
|
|
90
|
-
- `system` (`SystemManager`): system info, executions enable/disable, logstorage, ACL.
|
|
91
|
-
- `
|
|
92
|
-
- `scheduler` (`SchedulerManager`): cluster scheduler takeover (commercial, deprecated and scheduled for removal in 2.0).
|
|
93
|
+
- `system` (`SystemManager`): system info and summary, executions enable/disable, logstorage, ACL.
|
|
94
|
+
- `scheduler` (`SchedulerManager`): scheduled job listing and cluster schedule takeover (Community).
|
|
93
95
|
- `scm` (via `project.scm` and `job.scm`): import/export plugins, setup, enable/disable, status, actions (commit/import/export...).
|
|
94
96
|
|
|
95
97
|
Return types policy
|
|
@@ -110,7 +112,7 @@ Factory managers:
|
|
|
110
112
|
Returns `Execution` objects (execution factory).
|
|
111
113
|
|
|
112
114
|
Utility managers:
|
|
113
|
-
- `system`, `
|
|
115
|
+
- `system`, `metrics`, `scheduler`, `webhooks` (event send), `authorizations` (experimental).
|
|
114
116
|
- `scm` (via `project.scm` and `job.scm`), and project sub-managers like
|
|
115
117
|
`project.config`, `project.resources`, `project.sources`, `project.readme`,
|
|
116
118
|
`project.archive`, `project.acl`.
|
|
@@ -118,6 +120,23 @@ Utility managers:
|
|
|
118
120
|
Note: `project.webhooks.create(...)` returns the raw API response (e.g., `{"msg": "Saved webhook"}`)
|
|
119
121
|
because the Rundeck API does not return the created webhook object.
|
|
120
122
|
|
|
123
|
+
Compatibility with Community 6.3.0 (2.0.1)
|
|
124
|
+
---------------------------------------
|
|
125
|
+
- API v60 is recognized; the default stays v59 to retain compatibility with Community 6.2.1. The new v60 cluster endpoints are Enterprise-only and excluded.
|
|
126
|
+
- ACL creation and updates send the YAML text inside a JSON `contents` envelope and request JSON responses. Reads still request YAML and unwrap legacy JSON responses from older project ACL controllers. Python signatures and resource return conventions are unchanged.
|
|
127
|
+
- `job.meta(meta="executionAclValid")` and `project.jobs.browse(meta="executionAclValid")` expose the server's saved-user authorization warning. It does not block execution. Plugin `outputs` and property `outputMetadata` are preserved when returned by the server.
|
|
128
|
+
- Archive imports with `importConfig=True` or `importNodesSources=True` also require project `configure` authorization on 6.3.0. Use explicit `False` values for jobs-only imports. Authorization failures retain the server response in `RundeckAuthenticationError.response_body`.
|
|
129
|
+
- Webhook tokens remain opaque public secrets. The server handles hashing and migration; callers must continue sending the original secret.
|
|
130
|
+
- Session authentication uses standard cookie handling; 6.3.0 fixes direct HTTP authentication when the public URL is HTTPS behind forwarded headers.
|
|
131
|
+
- The stable 6.3.0 sources restore the trailing slash on `${job.serverUrl}` (RUN-5051), despite the earlier release-note wording. The client does not rewrite job context URLs.
|
|
132
|
+
|
|
133
|
+
Migration from 1.1.0
|
|
134
|
+
-------------------
|
|
135
|
+
- Set `api_version=59` explicitly when upgrading a server/client pair gradually; the default is now 59.
|
|
136
|
+
- Remove calls to `rd.config_management` and `job.tags()`: their endpoints are only available in commercial Rundeck products.
|
|
137
|
+
- `rd.scheduler.takeover()` and scheduler job listing remain supported by Community. On a non-cluster server, takeover returns a successful response indicating that no action was performed.
|
|
138
|
+
- `rd.authorizations` wraps experimental endpoints and can change with Rundeck releases.
|
|
139
|
+
|
|
121
140
|
Example:
|
|
122
141
|
```python
|
|
123
142
|
job = rd.jobs.get("job-id") # -> Job (object)
|
|
@@ -430,17 +449,6 @@ if features:
|
|
|
430
449
|
print(first.name, status.enabled)
|
|
431
450
|
```
|
|
432
451
|
|
|
433
|
-
Global configuration `/config`
|
|
434
|
-
```python
|
|
435
|
-
# Commercial compatibility surface; deprecated and removed in 2.0.
|
|
436
|
-
cfg = rd.config_management
|
|
437
|
-
all_configs = cfg.list()
|
|
438
|
-
cfg.save([{"key": "ui.banner", "value": "Hello"}])
|
|
439
|
-
cfg.delete("ui.banner", strata="default")
|
|
440
|
-
cfg.refresh()
|
|
441
|
-
cfg.restart()
|
|
442
|
-
```
|
|
443
|
-
|
|
444
452
|
Monitoring
|
|
445
453
|
----------
|
|
446
454
|
```python
|
|
@@ -452,6 +460,24 @@ thread_dump = rd.monitoring.thread_dump()
|
|
|
452
460
|
|
|
453
461
|
# Legacy metrics require rundeck.metrics.legacy.enabled=true on Rundeck 6.0.
|
|
454
462
|
legacy_threads = rd.metrics.threads()
|
|
463
|
+
ready = rd.monitoring.readiness()
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
Community additions
|
|
467
|
+
-------------------
|
|
468
|
+
```python
|
|
469
|
+
api_info = rd.api_info()
|
|
470
|
+
summary = rd.system.summary()
|
|
471
|
+
scheduled_jobs = rd.scheduler.jobs()
|
|
472
|
+
rd.tokens.remove_expired("admin") # use "*" with suitable administrator rights
|
|
473
|
+
|
|
474
|
+
project = rd.projects.get("demo")
|
|
475
|
+
project.plugins.save("ResourceModelSource", "resources.source", plugins=[])
|
|
476
|
+
project.archive.export_async(execution_ids=["1", "2"], use_post=True)
|
|
477
|
+
project.jobs.validate_option(option_data, job_was_scheduled=False)
|
|
478
|
+
|
|
479
|
+
# Experimental authorization API; actions are repeated query parameters.
|
|
480
|
+
permissions = rd.authorizations.application_kind("job", ["read", "run"])
|
|
455
481
|
```
|
|
456
482
|
|
|
457
483
|
Pagination
|
|
@@ -472,12 +498,15 @@ Development and testing
|
|
|
472
498
|
- Formatting/Lint: `black src/rundeck tests/`, `ruff check src/rundeck tests/`
|
|
473
499
|
- Typing: `mypy src/rundeck/`
|
|
474
500
|
- Tests: `pytest`
|
|
475
|
-
- Local integration tests: `scripts/run-integration.sh` starts
|
|
501
|
+
- Local integration tests: `scripts/run-integration.sh` starts `rundeck/rundeck:6.3.0-20261022` with API v59. Each run has an isolated Compose project and cleans up even when tests fail. With `KEEP_STACK=1`, the script prints the project name needed by `scripts/stop-integration.sh`.
|
|
502
|
+
- GitLab runs five integration targets: 6.3.0/API 59, 6.3.0/API 60, 6.2.1/API 59, 6.0.1/API 58 and 5.18.0/API 56. Set `RUNDECK_IMAGE` and `RUNDECK_API_VERSION` to run each target locally. Python compatibility tests retain 3.11–3.15 (3.15-rc Docker image).
|
|
503
|
+
- To exercise the 6.3.0 session regression and legacy metrics: `RUNDECK_PUBLIC_URL=https://rundeck.example.invalid RUNDECK_METRICS_LEGACY_ENABLED=true scripts/run-integration.sh`. The client still connects to `RUNDECK_URL` (default `http://localhost:4440`). The public URL defaults to the client URL, ensuring session redirects also work on older servers. Optional `RUNDECK_HTTP_PORT` changes the published port; set `RUNDECK_URL` accordingly.
|
|
476
504
|
- The docker compose stack mounts `tokens.properties` at the repo root to seed a local admin token for integration tests. This file is only intended for local testing.
|
|
505
|
+
- Run local compatibility targets sequentially, stopping each stack before starting the next. This keeps at most one Rundeck JVM and one PostgreSQL container active.
|
|
477
506
|
|
|
478
507
|
Code structure
|
|
479
508
|
--------------
|
|
480
509
|
- `src/rundeck/base.py`: generic objects/managers, `_build_path` helpers, pagination, CRUD.
|
|
481
510
|
- `src/rundeck/client.py`: HTTP client, `http_get/post/put/delete/list` methods.
|
|
482
|
-
- `src/rundeck/v1/objects/`: domain managers and objects (projects, jobs, executions, system, tokens, users,
|
|
483
|
-
- Managers/objects schema: we apply the manager -> object pattern wherever the API exposes an identifiable resource (jobs, projects, users, tokens, executions, etc.). For
|
|
511
|
+
- `src/rundeck/v1/objects/`: Community domain managers and objects (projects, jobs, executions, system, tokens, users, authorizations).
|
|
512
|
+
- Managers/objects schema: we apply the manager -> object pattern wherever the API exposes an identifiable resource (jobs, projects, users, tokens, executions, etc.). For global or utility endpoints without a resource (e.g., `/system`, `/scheduler`, `/metrics`), we use dedicated sub-managers rather than forcing an artificial object.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-rundeck"
|
|
3
|
-
version = "
|
|
4
|
-
description = "Python client for the Rundeck API (v14-
|
|
3
|
+
version = "2.0.1"
|
|
4
|
+
description = "Python client for the Rundeck Community API (v14-v60, default v59)."
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "Pascal Seckinger",email = "pascal.seckinger@protonmail.com"}
|
|
7
7
|
]
|
|
@@ -23,7 +23,7 @@ classifiers = [
|
|
|
23
23
|
"Typing :: Typed",
|
|
24
24
|
]
|
|
25
25
|
dependencies = [
|
|
26
|
-
"requests (>=2.
|
|
26
|
+
"requests (>=2.33.0,<3.0.0)"
|
|
27
27
|
]
|
|
28
28
|
|
|
29
29
|
[project.urls]
|
|
@@ -36,10 +36,10 @@ Changelog = "https://gitlab.com/pascal.seckinger/python-rundeck/-/blob/main/CHAN
|
|
|
36
36
|
[project.optional-dependencies]
|
|
37
37
|
dev = [
|
|
38
38
|
"bandit (>=1.7.9,<2.0.0)",
|
|
39
|
-
"black (>=
|
|
39
|
+
"black (>=26.3.1,<27.0.0)",
|
|
40
40
|
"flake8 (>=7.0.0,<8.0.0)",
|
|
41
41
|
"isort (>=7.0.0,<8.0.0)",
|
|
42
|
-
"pytest (>=9.0.
|
|
42
|
+
"pytest (>=9.0.3,<10.0.0)",
|
|
43
43
|
"pytest-cov (>=5.0.0,<6.0.0)",
|
|
44
44
|
"ruff (>=0.7.0,<1.0.0)",
|
|
45
45
|
"safety (>=3.2.0,<4.0.0)",
|
|
@@ -47,7 +47,11 @@ dev = [
|
|
|
47
47
|
|
|
48
48
|
[tool.poetry]
|
|
49
49
|
packages = [{include = "rundeck", from = "src"}]
|
|
50
|
-
include = [
|
|
50
|
+
include = [
|
|
51
|
+
"src/rundeck/py.typed",
|
|
52
|
+
{path = "API_COVERAGE.md", format = "sdist"},
|
|
53
|
+
{path = "CHANGELOG.md", format = "sdist"},
|
|
54
|
+
]
|
|
51
55
|
|
|
52
56
|
[build-system]
|
|
53
57
|
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
@@ -56,10 +60,10 @@ build-backend = "poetry.core.masonry.api"
|
|
|
56
60
|
[dependency-groups]
|
|
57
61
|
dev = [
|
|
58
62
|
"bandit (>=1.7.9,<2.0.0)",
|
|
59
|
-
"black (>=
|
|
63
|
+
"black (>=26.3.1,<27.0.0)",
|
|
60
64
|
"flake8 (>=7.0.0,<8.0.0)",
|
|
61
65
|
"isort (>=7.0.0,<8.0.0)",
|
|
62
|
-
"pytest (>=9.0.
|
|
66
|
+
"pytest (>=9.0.3,<10.0.0)",
|
|
63
67
|
"pytest-cov (>=5.0.0,<6.0.0)",
|
|
64
68
|
"ruff (>=0.7.0,<1.0.0)",
|
|
65
69
|
"safety (>=3.2.0,<4.0.0)"
|
|
@@ -81,7 +81,7 @@ class Rundeck:
|
|
|
81
81
|
def _init_managers(self) -> None:
|
|
82
82
|
"""Initialise les managers d'objets."""
|
|
83
83
|
# Import paresseux pour éviter les boucles d'import.
|
|
84
|
-
from rundeck.v1.objects.
|
|
84
|
+
from rundeck.v1.objects.authorizations import AuthorizationsManager
|
|
85
85
|
from rundeck.v1.objects.executions import ExecutionManager
|
|
86
86
|
from rundeck.v1.objects.features import FeatureManager
|
|
87
87
|
from rundeck.v1.objects.jobs import JobManager
|
|
@@ -98,7 +98,7 @@ class Rundeck:
|
|
|
98
98
|
self.projects = ProjectManager(self)
|
|
99
99
|
self.jobs = JobManager(self)
|
|
100
100
|
self.executions = ExecutionManager(self)
|
|
101
|
-
self.
|
|
101
|
+
self.authorizations = AuthorizationsManager(self)
|
|
102
102
|
self.metrics = MetricsManager(self)
|
|
103
103
|
self.monitoring = MonitoringManager(self)
|
|
104
104
|
self.plugins = PluginManager(self)
|
|
@@ -110,6 +110,10 @@ class Rundeck:
|
|
|
110
110
|
self.tokens = TokenManager(self)
|
|
111
111
|
self.users = UserManager(self)
|
|
112
112
|
|
|
113
|
+
def api_info(self) -> dict[str, Any]:
|
|
114
|
+
"""Récupère les informations de l'API utilisée par ce client."""
|
|
115
|
+
return self.http_get("/")
|
|
116
|
+
|
|
113
117
|
@property
|
|
114
118
|
def url(self) -> str:
|
|
115
119
|
"""URL fournie par l'utilisateur."""
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Constantes partagées pour le client Rundeck.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import tomllib
|
|
5
6
|
from importlib.metadata import PackageNotFoundError, version
|
|
6
7
|
from pathlib import Path
|
|
7
|
-
import tomllib
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
# Package metadata
|
|
@@ -40,13 +40,14 @@ FORMAT_JSON = "json"
|
|
|
40
40
|
|
|
41
41
|
# API versions. The library remains compatible with legacy Rundeck servers
|
|
42
42
|
# using v14, while current Rundeck servers require at least v17.
|
|
43
|
-
API_VERSION_CURRENT = "
|
|
43
|
+
API_VERSION_CURRENT = "60"
|
|
44
44
|
API_VERSION_MIN = "14"
|
|
45
45
|
API_VERSION_SERVER_MIN = "17"
|
|
46
46
|
API_VERSION_DEPRECATION = "34"
|
|
47
47
|
|
|
48
48
|
# Defaults
|
|
49
|
-
|
|
49
|
+
# v60 adds Enterprise endpoints only; keep the Community-compatible default.
|
|
50
|
+
DEFAULT_API_VERSION = "59"
|
|
50
51
|
DEFAULT_TIMEOUT = 30
|
|
51
52
|
USER_AGENT = "python-rundeck"
|
|
52
53
|
|
|
@@ -131,7 +131,7 @@ def raise_for_status(response: requests.Response) -> None:
|
|
|
131
131
|
raise RundeckAuthenticationError(message, error_code, response)
|
|
132
132
|
if code_lower == "api-version-unsupported":
|
|
133
133
|
raise RundeckApiVersionUnsupportedError(message, error_code, response)
|
|
134
|
-
if status
|
|
134
|
+
if status in (400, 422):
|
|
135
135
|
raise RundeckValidationError(message, error_code, response)
|
|
136
136
|
if status in (401, 403):
|
|
137
137
|
raise RundeckAuthenticationError(message, error_code, response)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from rundeck.utils import build_headers
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class YamlPolicyMixin:
|
|
9
|
+
def _get_yaml(self, path: str) -> str:
|
|
10
|
+
response = self.rd.http_get(
|
|
11
|
+
path, raw=True, headers={"Accept": "application/yaml"}
|
|
12
|
+
)
|
|
13
|
+
# Some older project ACL controllers return a JSON envelope despite Accept.
|
|
14
|
+
if (
|
|
15
|
+
"application/json"
|
|
16
|
+
in getattr(response, "headers", {}).get("Content-Type", "").lower()
|
|
17
|
+
):
|
|
18
|
+
result = response.json()
|
|
19
|
+
if isinstance(result, dict) and isinstance(result.get("contents"), str):
|
|
20
|
+
return result["contents"]
|
|
21
|
+
return response.text
|
|
22
|
+
|
|
23
|
+
def _yaml_headers(self) -> dict[str, str]:
|
|
24
|
+
return (
|
|
25
|
+
build_headers(accept="application/json", content_type="application/json")
|
|
26
|
+
or {}
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
def _post_yaml(self, path: str, content: Any) -> Any:
|
|
30
|
+
return self.rd.http_post(
|
|
31
|
+
path, json={"contents": content}, headers=self._yaml_headers()
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def _put_yaml(self, path: str, content: Any) -> Any:
|
|
35
|
+
return self.rd.http_put(
|
|
36
|
+
path, json={"contents": content}, headers=self._yaml_headers()
|
|
37
|
+
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Endpoints expérimentaux d'évaluation des autorisations."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from rundeck.base import RundeckObjectManager
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AuthorizationsManager(RundeckObjectManager):
|
|
9
|
+
"""Évalue les droits du sujet courant (API expérimentale)."""
|
|
10
|
+
|
|
11
|
+
_path = "/authorizations"
|
|
12
|
+
|
|
13
|
+
def _check(self, path: str, actions: list[str]) -> Any:
|
|
14
|
+
return self.rd.http_get(path, params={"actions": actions})
|
|
15
|
+
|
|
16
|
+
def application_kind(self, kind: str, actions: list[str]) -> Any:
|
|
17
|
+
"""Vérifie des actions sur un type de ressource de l'application."""
|
|
18
|
+
return self._check(f"/authorizations/application/{kind}", actions)
|
|
19
|
+
|
|
20
|
+
def application_resource(
|
|
21
|
+
self, resource_type: str, specifier: str, actions: list[str]
|
|
22
|
+
) -> Any:
|
|
23
|
+
"""Vérifie des actions sur une ressource de l'application."""
|
|
24
|
+
return self._check(
|
|
25
|
+
f"/authorizations/application/{resource_type}/{specifier}", actions
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
def project_kind(self, project: str, kind: str, actions: list[str]) -> Any:
|
|
29
|
+
"""Vérifie des actions sur un type de ressource du projet."""
|
|
30
|
+
return self._check(f"/authorizations/project/{project}/{kind}", actions)
|
|
31
|
+
|
|
32
|
+
def project_resource(
|
|
33
|
+
self, project: str, resource_type: str, specifier: str, actions: list[str]
|
|
34
|
+
) -> Any:
|
|
35
|
+
"""Vérifie des actions sur une ressource du projet."""
|
|
36
|
+
return self._check(
|
|
37
|
+
f"/authorizations/project/{project}/{resource_type}/{specifier}", actions
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def project_job(self, project: str, job_id: str, actions: list[str]) -> Any:
|
|
41
|
+
"""Vérifie des actions sur un job du projet."""
|
|
42
|
+
return self._check(f"/authorizations/project/{project}/job/{job_id}", actions)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
__all__ = ["AuthorizationsManager"]
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Gestion des jobs Rundeck
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import warnings
|
|
6
5
|
from typing import Any, Iterator
|
|
7
6
|
|
|
8
7
|
from rundeck.base import RundeckObject, RundeckObjectManager
|
|
@@ -114,16 +113,6 @@ class Job(RundeckObject):
|
|
|
114
113
|
path = self._job_path("meta")
|
|
115
114
|
return self.rd.http_get(path, params=params or None)
|
|
116
115
|
|
|
117
|
-
def tags(self) -> list[str]:
|
|
118
|
-
"""Retourne les tags du job (commercial, endpoint /job/{id}/tags)."""
|
|
119
|
-
warnings.warn(
|
|
120
|
-
"Job.tags() cible un endpoint commercial et sera retiré en 2.0.",
|
|
121
|
-
DeprecationWarning,
|
|
122
|
-
stacklevel=2,
|
|
123
|
-
)
|
|
124
|
-
path = self._job_path("tags")
|
|
125
|
-
return self.rd.http_get(path)
|
|
126
|
-
|
|
127
116
|
def executions(
|
|
128
117
|
self,
|
|
129
118
|
status: str | None = None,
|
|
@@ -327,18 +316,42 @@ class JobManager(RundeckObjectManager[Job]):
|
|
|
327
316
|
meta: str | None = None,
|
|
328
317
|
meta_exclude: str | None = None,
|
|
329
318
|
breakpoint: int | None = None,
|
|
319
|
+
use_post: bool = False,
|
|
330
320
|
**filters: Any,
|
|
331
321
|
) -> dict[str, Any]:
|
|
332
322
|
"""Parcourt un groupe de jobs et ses sous-groupes (API v46+)."""
|
|
333
323
|
project_path = self._project_path(project)
|
|
334
|
-
|
|
324
|
+
query = compact(meta=meta, metaExclude=meta_exclude, breakpoint=breakpoint)
|
|
325
|
+
browse_path = f"{project_path}/browse"
|
|
326
|
+
if use_post:
|
|
327
|
+
if path is not None:
|
|
328
|
+
query["path"] = path
|
|
329
|
+
return self.rd.http_post(browse_path, params=query or None, json=filters)
|
|
330
|
+
query = compact(
|
|
335
331
|
filters,
|
|
336
332
|
path=path,
|
|
337
333
|
meta=meta,
|
|
338
334
|
metaExclude=meta_exclude,
|
|
339
335
|
breakpoint=breakpoint,
|
|
340
336
|
)
|
|
341
|
-
return self.rd.http_get(
|
|
337
|
+
return self.rd.http_get(browse_path, params=query or None)
|
|
338
|
+
|
|
339
|
+
def validate_option(
|
|
340
|
+
self,
|
|
341
|
+
option_data: dict[str, Any],
|
|
342
|
+
*,
|
|
343
|
+
job_was_scheduled: bool,
|
|
344
|
+
project: str | None = None,
|
|
345
|
+
) -> Any:
|
|
346
|
+
"""Valide une option de job (API v47+)."""
|
|
347
|
+
project_name = project or (self.parent.id if self.parent else None)
|
|
348
|
+
if not project_name:
|
|
349
|
+
raise ValueError("Le paramètre project est requis")
|
|
350
|
+
return self.rd.http_post(
|
|
351
|
+
f"/project/{project_name}/jobs/validateOption",
|
|
352
|
+
params={"jobWasScheduled": job_was_scheduled},
|
|
353
|
+
json=option_data,
|
|
354
|
+
)
|
|
342
355
|
|
|
343
356
|
def get(self, id: str) -> "Job":
|
|
344
357
|
"""Récupère un job par identifiant."""
|
|
@@ -65,6 +65,10 @@ class MonitoringManager(RundeckObjectManager):
|
|
|
65
65
|
"""Récupère l'état de santé de l'application."""
|
|
66
66
|
return self.rd.http_get(self._monitoring_path("health"))
|
|
67
67
|
|
|
68
|
+
def readiness(self) -> dict[str, Any]:
|
|
69
|
+
"""Récupère l'état de disponibilité pour les sondes de readiness."""
|
|
70
|
+
return self.rd.http_get(self._monitoring_path("health/readiness"))
|
|
71
|
+
|
|
68
72
|
def info(self) -> dict[str, Any]:
|
|
69
73
|
"""Récupère les informations applicatives."""
|
|
70
74
|
return self.rd.http_get(self._monitoring_path("info"))
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Configuration des plugins au niveau d'un projet."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from rundeck.base import RundeckObjectManager
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ProjectPluginsManager(RundeckObjectManager):
|
|
9
|
+
"""Sauvegarde les configurations de plugins d'un projet (API v55+)."""
|
|
10
|
+
|
|
11
|
+
_path = "/project/{parent}/plugins"
|
|
12
|
+
|
|
13
|
+
def save(
|
|
14
|
+
self,
|
|
15
|
+
service_name: str,
|
|
16
|
+
config_prefix: str,
|
|
17
|
+
plugins: list[dict[str, Any]],
|
|
18
|
+
removed_plugins: list[dict[str, Any]] | None = None,
|
|
19
|
+
) -> Any:
|
|
20
|
+
"""Crée, modifie ou retire des configurations de plugins projet."""
|
|
21
|
+
path = self._build_path("save")
|
|
22
|
+
return self.rd.http_post(
|
|
23
|
+
path,
|
|
24
|
+
params={"serviceName": service_name, "configPrefix": config_prefix},
|
|
25
|
+
json={"plugins": plugins, "removedPlugins": removed_plugins or []},
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
__all__ = ["ProjectPluginsManager"]
|
|
@@ -10,6 +10,7 @@ from rundeck.v1.objects.acl import YamlPolicyMixin
|
|
|
10
10
|
from rundeck.v1.objects.adhoc import AdhocManager
|
|
11
11
|
from rundeck.v1.objects.executions import ExecutionManager
|
|
12
12
|
from rundeck.v1.objects.jobs import JobManager
|
|
13
|
+
from rundeck.v1.objects.project_plugins import ProjectPluginsManager
|
|
13
14
|
from rundeck.v1.objects.scm import ProjectSCMManager
|
|
14
15
|
from rundeck.v1.objects.webhooks import ProjectWebhookManager
|
|
15
16
|
|
|
@@ -65,6 +66,11 @@ class Project(RundeckObject):
|
|
|
65
66
|
"""Accès aux opérations SCM du projet (import/export)."""
|
|
66
67
|
return ProjectSCMManager(self.rd, parent=self)
|
|
67
68
|
|
|
69
|
+
@property
|
|
70
|
+
def plugins(self) -> ProjectPluginsManager:
|
|
71
|
+
"""Accès à la configuration des plugins du projet."""
|
|
72
|
+
return ProjectPluginsManager(self.rd, parent=self)
|
|
73
|
+
|
|
68
74
|
@property
|
|
69
75
|
def webhooks(self) -> ProjectWebhookManager:
|
|
70
76
|
"""Accès aux webhooks du projet."""
|
|
@@ -187,8 +193,7 @@ class ProjectACLManager(YamlPolicyMixin, RundeckObjectManager):
|
|
|
187
193
|
def get(self, policy_name: str) -> str:
|
|
188
194
|
"""Récupère une politique ACL projet (contenu texte)."""
|
|
189
195
|
path = self._build_path(policy_name)
|
|
190
|
-
|
|
191
|
-
return response.text
|
|
196
|
+
return self._get_yaml(path)
|
|
192
197
|
|
|
193
198
|
def create(self, policy_name: str, content: str) -> dict[str, Any]:
|
|
194
199
|
"""Crée une politique ACL projet."""
|
|
@@ -429,9 +434,25 @@ class ProjectArchiveManager(RundeckObjectManager):
|
|
|
429
434
|
)
|
|
430
435
|
return self.rd.http_get(path, params=params or None, raw=True)
|
|
431
436
|
|
|
432
|
-
def export_async(
|
|
433
|
-
|
|
437
|
+
def export_async(
|
|
438
|
+
self,
|
|
439
|
+
*,
|
|
440
|
+
execution_ids: list[str] | None = None,
|
|
441
|
+
use_post: bool = False,
|
|
442
|
+
**params: Any,
|
|
443
|
+
) -> Any:
|
|
444
|
+
"""Lance une export async, en POST pour les longues listes d'IDs."""
|
|
434
445
|
path = self._build_path("export/async")
|
|
446
|
+
if use_post:
|
|
447
|
+
form = {"executionIds": execution_ids} if execution_ids else None
|
|
448
|
+
return self.rd.http_post(
|
|
449
|
+
path,
|
|
450
|
+
params=params or None,
|
|
451
|
+
data=form,
|
|
452
|
+
headers=build_headers(content_type="application/x-www-form-urlencoded"),
|
|
453
|
+
)
|
|
454
|
+
if execution_ids:
|
|
455
|
+
params["executionIds"] = execution_ids
|
|
435
456
|
return self.rd.http_get(path, params=params or None)
|
|
436
457
|
|
|
437
458
|
def export_status(self, token: str) -> Any:
|
|
@@ -460,6 +481,9 @@ class ProjectArchiveManager(RundeckObjectManager):
|
|
|
460
481
|
) -> Any:
|
|
461
482
|
"""
|
|
462
483
|
Importe une archive ZIP dans le projet.
|
|
484
|
+
|
|
485
|
+
Community 6.3+ exige aussi le droit configure lorsque importConfig ou
|
|
486
|
+
importNodesSources est activé. Les options et refus sont transmis tels quels.
|
|
463
487
|
"""
|
|
464
488
|
params = compact(
|
|
465
489
|
component_options,
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Gestion des endpoints /scheduler
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import warnings
|
|
6
5
|
from typing import Any
|
|
7
6
|
|
|
8
7
|
from rundeck.base import RundeckObjectManager
|
|
@@ -20,24 +19,24 @@ class SchedulerManager(RundeckObjectManager):
|
|
|
20
19
|
all_servers: bool = False,
|
|
21
20
|
project: str | None = None,
|
|
22
21
|
job_id: str | None = None,
|
|
22
|
+
job_ids: list[str] | None = None,
|
|
23
23
|
) -> dict[str, Any]:
|
|
24
24
|
"""
|
|
25
|
-
Reprend le planning des jobs
|
|
25
|
+
Reprend le planning des jobs. Sur un serveur sans mode cluster,
|
|
26
|
+
l'API est disponible, mais aucun planning distant n'est transféré.
|
|
26
27
|
|
|
27
28
|
Args:
|
|
28
29
|
server_uuid: UUID du serveur cible.
|
|
29
30
|
all_servers: True pour reprendre tous les serveurs.
|
|
30
31
|
project: Projet concerné (optionnel).
|
|
31
32
|
job_id: Job spécifique (optionnel).
|
|
33
|
+
job_ids: Liste de jobs (exclusif avec job_id).
|
|
32
34
|
|
|
33
35
|
Returns:
|
|
34
36
|
Résultat de la reprise.
|
|
35
37
|
"""
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
DeprecationWarning,
|
|
39
|
-
stacklevel=2,
|
|
40
|
-
)
|
|
38
|
+
if job_id is not None and job_ids is not None:
|
|
39
|
+
raise ValueError("job_id et job_ids ne peuvent pas être utilisés ensemble")
|
|
41
40
|
path = self._build_path("takeover")
|
|
42
41
|
|
|
43
42
|
server = None
|
|
@@ -50,9 +49,19 @@ class SchedulerManager(RundeckObjectManager):
|
|
|
50
49
|
server=server,
|
|
51
50
|
project=project if project else None,
|
|
52
51
|
job={"id": job_id} if job_id else None,
|
|
52
|
+
jobs=[{"id": item} for item in job_ids] if job_ids else None,
|
|
53
53
|
)
|
|
54
54
|
|
|
55
55
|
return self.rd.http_put(path, json=data)
|
|
56
56
|
|
|
57
|
+
def jobs(self, server_uuid: str | None = None) -> Any:
|
|
58
|
+
"""Liste les jobs planifiés sur le serveur courant ou le serveur donné."""
|
|
59
|
+
path = (
|
|
60
|
+
f"/scheduler/server/{server_uuid}/jobs"
|
|
61
|
+
if server_uuid
|
|
62
|
+
else "/scheduler/jobs"
|
|
63
|
+
)
|
|
64
|
+
return self.rd.http_get(path)
|
|
65
|
+
|
|
57
66
|
|
|
58
67
|
__all__ = ["SchedulerManager"]
|
|
@@ -67,8 +67,7 @@ class SystemACLManager(YamlPolicyMixin, RundeckObjectManager[SystemACL]):
|
|
|
67
67
|
def get(self, policy_name: str) -> SystemACL:
|
|
68
68
|
"""Récupère une politique ACL (contenu texte)."""
|
|
69
69
|
path = self._build_path(policy_name)
|
|
70
|
-
|
|
71
|
-
return self._wrap({"name": policy_name, "content": response.text})
|
|
70
|
+
return self._wrap({"name": policy_name, "content": self._get_yaml(path)})
|
|
72
71
|
|
|
73
72
|
def create(self, policy_name: str, content: str) -> SystemACL:
|
|
74
73
|
"""Crée une politique ACL système."""
|
|
@@ -143,3 +142,7 @@ class SystemManager(RundeckObjectManager):
|
|
|
143
142
|
"""
|
|
144
143
|
path = self._build_path("info")
|
|
145
144
|
return self.rd.http_get(path)
|
|
145
|
+
|
|
146
|
+
def summary(self) -> dict[str, Any]:
|
|
147
|
+
"""Récupère le résumé des exécutions et projets."""
|
|
148
|
+
return self.rd.http_get("/home/summary")
|
|
@@ -100,3 +100,7 @@ class TokenManager(RundeckObjectManager):
|
|
|
100
100
|
"""
|
|
101
101
|
path = self._token_path(token_id)
|
|
102
102
|
self._delete(token_id, path=path)
|
|
103
|
+
|
|
104
|
+
def remove_expired(self, user: str) -> Any:
|
|
105
|
+
"""Supprime les tokens expirés d'un utilisateur ou de tous (``*``)."""
|
|
106
|
+
return self.rd.http_post(self._build_path(f"{user}/removeExpired"))
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import Any
|
|
4
|
-
|
|
5
|
-
from rundeck.utils import build_headers
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class YamlPolicyMixin:
|
|
9
|
-
_yaml_content_type = "application/yaml"
|
|
10
|
-
|
|
11
|
-
def _yaml_headers(self) -> dict[str, str]:
|
|
12
|
-
headers = build_headers(content_type=self._yaml_content_type)
|
|
13
|
-
return headers or {"Content-Type": self._yaml_content_type}
|
|
14
|
-
|
|
15
|
-
def _post_yaml(self, path: str, content: Any) -> Any:
|
|
16
|
-
return self.rd.http_post(path, data=content, headers=self._yaml_headers())
|
|
17
|
-
|
|
18
|
-
def _put_yaml(self, path: str, content: Any) -> Any:
|
|
19
|
-
return self.rd.http_put(path, data=content, headers=self._yaml_headers())
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
"""Gestion de la configuration Rundeck (instance globale)."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import warnings
|
|
6
|
-
|
|
7
|
-
from rundeck.base import RundeckObjectManager
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class ConfigManagementManager(RundeckObjectManager):
|
|
11
|
-
"""
|
|
12
|
-
Gestion des configurations globales (plugin/custom) via /config.
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
_path = "/config"
|
|
16
|
-
|
|
17
|
-
@staticmethod
|
|
18
|
-
def _warn_commercial() -> None:
|
|
19
|
-
warnings.warn(
|
|
20
|
-
"Config Management est une surface commerciale et sera retirée en 2.0.",
|
|
21
|
-
DeprecationWarning,
|
|
22
|
-
stacklevel=3,
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
def list(self) -> list[dict[str, str]]:
|
|
26
|
-
"""Liste toutes les configs et propriétés."""
|
|
27
|
-
self._warn_commercial()
|
|
28
|
-
path = self._build_path("list")
|
|
29
|
-
return self.rd.http_get(path)
|
|
30
|
-
|
|
31
|
-
def save(self, entries: list[dict[str, str]]) -> dict[str, str | list[str]]:
|
|
32
|
-
"""
|
|
33
|
-
Crée ou met à jour des configs (payload: liste de dicts {key, value, strata?}).
|
|
34
|
-
"""
|
|
35
|
-
self._warn_commercial()
|
|
36
|
-
path = self._build_path("save")
|
|
37
|
-
return self.rd.http_post(path, json=entries)
|
|
38
|
-
|
|
39
|
-
def delete(self, key: str, strata: str | None = None) -> None:
|
|
40
|
-
"""
|
|
41
|
-
Supprime une config via /config/delete avec payload JSON.
|
|
42
|
-
"""
|
|
43
|
-
self._warn_commercial()
|
|
44
|
-
payload: dict[str, str] = {"key": key}
|
|
45
|
-
if strata:
|
|
46
|
-
payload["strata"] = strata
|
|
47
|
-
path = self._build_path("delete")
|
|
48
|
-
self.rd.http_delete(path, json=payload)
|
|
49
|
-
|
|
50
|
-
def refresh(self) -> dict[str, str]:
|
|
51
|
-
"""
|
|
52
|
-
Recharge les configurations depuis les fichiers de propriétés.
|
|
53
|
-
"""
|
|
54
|
-
self._warn_commercial()
|
|
55
|
-
path = self._build_path("refresh")
|
|
56
|
-
return self.rd.http_post(path)
|
|
57
|
-
|
|
58
|
-
def restart(self) -> dict[str, str]:
|
|
59
|
-
"""
|
|
60
|
-
Redémarre le serveur Rundeck.
|
|
61
|
-
"""
|
|
62
|
-
self._warn_commercial()
|
|
63
|
-
path = self._build_path("restart")
|
|
64
|
-
return self.rd.http_post(path)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|