python-rundeck 1.1.0__tar.gz → 2.0.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.
Files changed (32) hide show
  1. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/PKG-INFO +42 -26
  2. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/README.md +40 -24
  3. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/pyproject.toml +2 -2
  4. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/client.py +6 -2
  5. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/const.py +2 -2
  6. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/exceptions.py +1 -1
  7. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/acl.py +7 -2
  8. python_rundeck-2.0.0/src/rundeck/v1/objects/authorizations.py +45 -0
  9. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/jobs.py +26 -13
  10. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/metrics.py +4 -0
  11. python_rundeck-2.0.0/src/rundeck/v1/objects/project_plugins.py +29 -0
  12. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/projects.py +27 -3
  13. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/scheduler.py +16 -7
  14. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/system.py +7 -1
  15. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/tokens.py +4 -0
  16. python_rundeck-1.1.0/src/rundeck/v1/objects/config_management.py +0 -64
  17. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/LICENSE +0 -0
  18. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/__init__.py +0 -0
  19. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/base.py +0 -0
  20. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/config.py +0 -0
  21. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/py.typed +0 -0
  22. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/utils.py +0 -0
  23. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/__init__.py +0 -0
  24. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/__init__.py +0 -0
  25. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/adhoc.py +0 -0
  26. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/executions.py +0 -0
  27. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/features.py +0 -0
  28. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/key_storage.py +0 -0
  29. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/plugins.py +0 -0
  30. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/scm.py +0 -0
  31. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/users.py +0 -0
  32. {python_rundeck-1.1.0 → python_rundeck-2.0.0}/src/rundeck/v1/objects/webhooks.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-rundeck
3
- Version: 1.1.0
4
- Summary: Python client for the Rundeck API (v14-v58).
3
+ Version: 2.0.0
4
+ Summary: Python client for the Rundeck Community API (v14-v59).
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
7
7
  Keywords: rundeck,api,client
@@ -43,7 +43,9 @@ python-rundeck
43
43
  ![License](https://img.shields.io/pypi/l/python-rundeck)
44
44
  ![Downloads](https://static.pepy.tech/badge/python-rundeck)
45
45
 
46
- Python client for the Rundeck API (v14-v58), inspired by the python-gitlab architecture. The default API version is v58; 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).
46
+ Python client for the Rundeck Community API (v14-v59), inspired by the python-gitlab architecture. The default API version is v59; 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", api_version=58)
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", api_version=58)
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: `58`)
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 (e.g. 58)
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
- - `config_management` (`ConfigManagementManager`): global configuration `/config` (commercial, deprecated and scheduled for removal in 2.0).
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`, `config_management`, `metrics`, `scheduler`, `webhooks` (event send).
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,13 @@ 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
+ Migration from 1.1.0
162
+ -------------------
163
+ - Set `api_version=59` explicitly when upgrading a server/client pair gradually; the default is now 59.
164
+ - Remove calls to `rd.config_management` and `job.tags()`: their endpoints are only available in commercial Rundeck products.
165
+ - `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.
166
+ - `rd.authorizations` wraps experimental endpoints and can change with Rundeck releases.
167
+
159
168
  Example:
160
169
  ```python
161
170
  job = rd.jobs.get("job-id") # -> Job (object)
@@ -468,17 +477,6 @@ if features:
468
477
  print(first.name, status.enabled)
469
478
  ```
470
479
 
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
480
  Monitoring
483
481
  ----------
484
482
  ```python
@@ -490,6 +488,24 @@ thread_dump = rd.monitoring.thread_dump()
490
488
 
491
489
  # Legacy metrics require rundeck.metrics.legacy.enabled=true on Rundeck 6.0.
492
490
  legacy_threads = rd.metrics.threads()
491
+ ready = rd.monitoring.readiness()
492
+ ```
493
+
494
+ Community additions
495
+ -------------------
496
+ ```python
497
+ api_info = rd.api_info()
498
+ summary = rd.system.summary()
499
+ scheduled_jobs = rd.scheduler.jobs()
500
+ rd.tokens.remove_expired("admin") # use "*" with suitable administrator rights
501
+
502
+ project = rd.projects.get("demo")
503
+ project.plugins.save("ResourceModelSource", "resources.source", plugins=[])
504
+ project.archive.export_async(execution_ids=["1", "2"], use_post=True)
505
+ project.jobs.validate_option(option_data, job_was_scheduled=False)
506
+
507
+ # Experimental authorization API; actions are repeated query parameters.
508
+ permissions = rd.authorizations.application_kind("job", ["read", "run"])
493
509
  ```
494
510
 
495
511
  Pagination
@@ -510,13 +526,13 @@ Development and testing
510
526
  - Formatting/Lint: `black src/rundeck tests/`, `ruff check src/rundeck tests/`
511
527
  - Typing: `mypy src/rundeck/`
512
528
  - Tests: `pytest`
513
- - Local integration tests: `scripts/run-integration.sh` starts Rundeck Community 6.0.1 by default with API v58. Use `RUNDECK_IMAGE=rundeck/rundeck:5.18.0 RUNDECK_API_VERSION=56 scripts/run-integration.sh` for the v56 compatibility run. Add `KEEP_STACK=1` to keep the instance running after tests. Dedicated teardown script: `scripts/stop-integration.sh`.
529
+ - Local integration tests: `scripts/run-integration.sh` starts Rundeck Community 6.2.1 by default with API v59. Use `RUNDECK_IMAGE=rundeck/rundeck:6.0.1 RUNDECK_API_VERSION=58` or `RUNDECK_IMAGE=rundeck/rundeck:5.18.0 RUNDECK_API_VERSION=56` for compatibility runs. Add `KEEP_STACK=1` to keep the instance running after tests. Dedicated teardown script: `scripts/stop-integration.sh`.
514
530
  - 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.
515
531
 
516
532
  Code structure
517
533
  --------------
518
534
  - `src/rundeck/base.py`: generic objects/managers, `_build_path` helpers, pagination, CRUD.
519
535
  - `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, config_management).
521
- - Managers/objects schema: we apply the manager -> object pattern wherever the API exposes an identifiable resource (jobs, projects, users, tokens, executions, etc.). For purely global or utility endpoints without a resource (e.g., `/system` and its subdomains, `/config`, `/metrics`), we use dedicated sub-managers rather than forcing an artificial object.
536
+ - `src/rundeck/v1/objects/`: Community domain managers and objects (projects, jobs, executions, system, tokens, users, authorizations).
537
+ - 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
538
 
@@ -5,7 +5,9 @@ python-rundeck
5
5
  ![License](https://img.shields.io/pypi/l/python-rundeck)
6
6
  ![Downloads](https://static.pepy.tech/badge/python-rundeck)
7
7
 
8
- Python client for the Rundeck API (v14-v58), inspired by the python-gitlab architecture. The default API version is v58; 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).
8
+ Python client for the Rundeck Community API (v14-v59), inspired by the python-gitlab architecture. The default API version is v59; 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", api_version=58)
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", api_version=58)
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: `58`)
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 (e.g. 58)
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
- - `config_management` (`ConfigManagementManager`): global configuration `/config` (commercial, deprecated and scheduled for removal in 2.0).
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`, `config_management`, `metrics`, `scheduler`, `webhooks` (event send).
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,13 @@ 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
+ Migration from 1.1.0
124
+ -------------------
125
+ - Set `api_version=59` explicitly when upgrading a server/client pair gradually; the default is now 59.
126
+ - Remove calls to `rd.config_management` and `job.tags()`: their endpoints are only available in commercial Rundeck products.
127
+ - `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.
128
+ - `rd.authorizations` wraps experimental endpoints and can change with Rundeck releases.
129
+
121
130
  Example:
122
131
  ```python
123
132
  job = rd.jobs.get("job-id") # -> Job (object)
@@ -430,17 +439,6 @@ if features:
430
439
  print(first.name, status.enabled)
431
440
  ```
432
441
 
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
442
  Monitoring
445
443
  ----------
446
444
  ```python
@@ -452,6 +450,24 @@ thread_dump = rd.monitoring.thread_dump()
452
450
 
453
451
  # Legacy metrics require rundeck.metrics.legacy.enabled=true on Rundeck 6.0.
454
452
  legacy_threads = rd.metrics.threads()
453
+ ready = rd.monitoring.readiness()
454
+ ```
455
+
456
+ Community additions
457
+ -------------------
458
+ ```python
459
+ api_info = rd.api_info()
460
+ summary = rd.system.summary()
461
+ scheduled_jobs = rd.scheduler.jobs()
462
+ rd.tokens.remove_expired("admin") # use "*" with suitable administrator rights
463
+
464
+ project = rd.projects.get("demo")
465
+ project.plugins.save("ResourceModelSource", "resources.source", plugins=[])
466
+ project.archive.export_async(execution_ids=["1", "2"], use_post=True)
467
+ project.jobs.validate_option(option_data, job_was_scheduled=False)
468
+
469
+ # Experimental authorization API; actions are repeated query parameters.
470
+ permissions = rd.authorizations.application_kind("job", ["read", "run"])
455
471
  ```
456
472
 
457
473
  Pagination
@@ -472,12 +488,12 @@ Development and testing
472
488
  - Formatting/Lint: `black src/rundeck tests/`, `ruff check src/rundeck tests/`
473
489
  - Typing: `mypy src/rundeck/`
474
490
  - Tests: `pytest`
475
- - Local integration tests: `scripts/run-integration.sh` starts Rundeck Community 6.0.1 by default with API v58. Use `RUNDECK_IMAGE=rundeck/rundeck:5.18.0 RUNDECK_API_VERSION=56 scripts/run-integration.sh` for the v56 compatibility run. Add `KEEP_STACK=1` to keep the instance running after tests. Dedicated teardown script: `scripts/stop-integration.sh`.
491
+ - Local integration tests: `scripts/run-integration.sh` starts Rundeck Community 6.2.1 by default with API v59. Use `RUNDECK_IMAGE=rundeck/rundeck:6.0.1 RUNDECK_API_VERSION=58` or `RUNDECK_IMAGE=rundeck/rundeck:5.18.0 RUNDECK_API_VERSION=56` for compatibility runs. Add `KEEP_STACK=1` to keep the instance running after tests. Dedicated teardown script: `scripts/stop-integration.sh`.
476
492
  - 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.
477
493
 
478
494
  Code structure
479
495
  --------------
480
496
  - `src/rundeck/base.py`: generic objects/managers, `_build_path` helpers, pagination, CRUD.
481
497
  - `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, config_management).
483
- - Managers/objects schema: we apply the manager -> object pattern wherever the API exposes an identifiable resource (jobs, projects, users, tokens, executions, etc.). For purely global or utility endpoints without a resource (e.g., `/system` and its subdomains, `/config`, `/metrics`), we use dedicated sub-managers rather than forcing an artificial object.
498
+ - `src/rundeck/v1/objects/`: Community domain managers and objects (projects, jobs, executions, system, tokens, users, authorizations).
499
+ - 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 = "1.1.0"
4
- description = "Python client for the Rundeck API (v14-v58)."
3
+ version = "2.0.0"
4
+ description = "Python client for the Rundeck Community API (v14-v59)."
5
5
  authors = [
6
6
  {name = "Pascal Seckinger",email = "pascal.seckinger@protonmail.com"}
7
7
  ]
@@ -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.config_management import ConfigManagementManager
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.config_management = ConfigManagementManager(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,7 +40,7 @@ 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 = "58"
43
+ API_VERSION_CURRENT = "59"
44
44
  API_VERSION_MIN = "14"
45
45
  API_VERSION_SERVER_MIN = "17"
46
46
  API_VERSION_DEPRECATION = "34"
@@ -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 == 400:
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)
@@ -9,8 +9,13 @@ class YamlPolicyMixin:
9
9
  _yaml_content_type = "application/yaml"
10
10
 
11
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}
12
+ headers = build_headers(
13
+ accept=self._yaml_content_type, content_type=self._yaml_content_type
14
+ )
15
+ return headers or {
16
+ "Accept": self._yaml_content_type,
17
+ "Content-Type": self._yaml_content_type,
18
+ }
14
19
 
15
20
  def _post_yaml(self, path: str, content: Any) -> Any:
16
21
  return self.rd.http_post(path, data=content, headers=self._yaml_headers())
@@ -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
- params = compact(
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(f"{project_path}/browse", params=params or None)
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,7 +193,9 @@ 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
- response = self.rd.http_get(path, raw=True)
196
+ response = self.rd.http_get(
197
+ path, raw=True, headers={"Accept": "application/yaml"}
198
+ )
191
199
  return response.text
192
200
 
193
201
  def create(self, policy_name: str, content: str) -> dict[str, Any]:
@@ -429,9 +437,25 @@ class ProjectArchiveManager(RundeckObjectManager):
429
437
  )
430
438
  return self.rd.http_get(path, params=params or None, raw=True)
431
439
 
432
- def export_async(self, **params: Any) -> Any:
433
- """Lance une export async, retourne le token."""
440
+ def export_async(
441
+ self,
442
+ *,
443
+ execution_ids: list[str] | None = None,
444
+ use_post: bool = False,
445
+ **params: Any,
446
+ ) -> Any:
447
+ """Lance une export async, en POST pour les longues listes d'IDs."""
434
448
  path = self._build_path("export/async")
449
+ if use_post:
450
+ form = {"executionIds": execution_ids} if execution_ids else None
451
+ return self.rd.http_post(
452
+ path,
453
+ params=params or None,
454
+ data=form,
455
+ headers=build_headers(content_type="application/x-www-form-urlencoded"),
456
+ )
457
+ if execution_ids:
458
+ params["executionIds"] = execution_ids
435
459
  return self.rd.http_get(path, params=params or None)
436
460
 
437
461
  def export_status(self, token: str) -> Any:
@@ -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 en mode cluster.
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
- warnings.warn(
37
- "Les opérations Scheduler Cluster sont commerciales et seront retirées en 2.0.",
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,7 +67,9 @@ 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
- response = self.rd.http_get(path, raw=True)
70
+ response = self.rd.http_get(
71
+ path, raw=True, headers={"Accept": "application/yaml"}
72
+ )
71
73
  return self._wrap({"name": policy_name, "content": response.text})
72
74
 
73
75
  def create(self, policy_name: str, content: str) -> SystemACL:
@@ -143,3 +145,7 @@ class SystemManager(RundeckObjectManager):
143
145
  """
144
146
  path = self._build_path("info")
145
147
  return self.rd.http_get(path)
148
+
149
+ def summary(self) -> dict[str, Any]:
150
+ """Récupère le résumé des exécutions et projets."""
151
+ 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,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