python-rundeck 1.0.1__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 (36) hide show
  1. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/PKG-INFO +63 -24
  2. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/README.md +61 -22
  3. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/pyproject.toml +2 -2
  4. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/client.py +20 -12
  5. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/config.py +2 -1
  6. python_rundeck-2.0.0/src/rundeck/const.py +69 -0
  7. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/exceptions.py +1 -1
  8. python_rundeck-2.0.0/src/rundeck/utils.py +35 -0
  9. python_rundeck-2.0.0/src/rundeck/v1/objects/acl.py +24 -0
  10. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/v1/objects/adhoc.py +3 -20
  11. python_rundeck-2.0.0/src/rundeck/v1/objects/authorizations.py +45 -0
  12. python_rundeck-2.0.0/src/rundeck/v1/objects/executions.py +449 -0
  13. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/v1/objects/jobs.py +129 -47
  14. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/v1/objects/key_storage.py +10 -3
  15. python_rundeck-2.0.0/src/rundeck/v1/objects/metrics.py +81 -0
  16. python_rundeck-2.0.0/src/rundeck/v1/objects/project_plugins.py +29 -0
  17. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/v1/objects/projects.py +163 -74
  18. python_rundeck-2.0.0/src/rundeck/v1/objects/scheduler.py +67 -0
  19. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/v1/objects/scm.py +5 -0
  20. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/v1/objects/system.py +11 -6
  21. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/v1/objects/tokens.py +4 -0
  22. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/v1/objects/users.py +33 -16
  23. python_rundeck-1.0.1/src/rundeck/const.py +0 -45
  24. python_rundeck-1.0.1/src/rundeck/v1/objects/config_management.py +0 -51
  25. python_rundeck-1.0.1/src/rundeck/v1/objects/executions.py +0 -326
  26. python_rundeck-1.0.1/src/rundeck/v1/objects/metrics.py +0 -37
  27. python_rundeck-1.0.1/src/rundeck/v1/objects/scheduler.py +0 -50
  28. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/LICENSE +0 -0
  29. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/__init__.py +0 -0
  30. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/base.py +0 -0
  31. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/py.typed +0 -0
  32. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/v1/__init__.py +0 -0
  33. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/v1/objects/__init__.py +0 -0
  34. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/v1/objects/features.py +0 -0
  35. {python_rundeck-1.0.1 → python_rundeck-2.0.0}/src/rundeck/v1/objects/plugins.py +0 -0
  36. {python_rundeck-1.0.1 → 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.0.1
4
- Summary: Python client for the Rundeck API (v14-v56).
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-v56), inspired by the python-gitlab architecture. Provides typed managers for key resources (projects, jobs, executions, tokens, users, system, configuration) 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=56)
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=56)
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,20 +96,24 @@ 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 (e.g. `56`)
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)
102
+ - `user_agent`: Custom HTTP User-Agent (string)
103
+ - `config_section`: Section name in config files (default: `rundeck`)
100
104
 
101
105
  Config files: if needed, pass `config_files` or `Rundeck.from_config(config_section=...)`.
102
106
  Useful env vars (client config):
103
107
  - `RUNDECK_URL`: Base URL
104
108
  - `RUNDECK_TOKEN`: API token (header `X-Rundeck-Auth-Token`)
105
109
  - `RUNDECK_USERNAME` / `RUNDECK_PASSWORD`: Session auth (if no token)
106
- - `RUNDECK_API_VERSION`: API version (e.g. 56)
110
+ - `RUNDECK_API_VERSION`: API version (default `59`; older server versions can be selected explicitly)
107
111
  - `RUNDECK_TIMEOUT`: Request timeout (seconds)
108
112
  - `RUNDECK_SSL_VERIFY`: TLS verification (bool or CA path)
109
113
  - `RUNDECK_USER_AGENT`: HTTP User-Agent
110
114
 
115
+ Rundeck 6.0+ accepts JSON for REST requests and responses. XML/YAML remain supported only as job, archive, and resource document formats.
116
+
111
117
  Available resources
112
118
  -------------------
113
119
  - `projects` (`ProjectManager`): CRUD projects, job export/import, project config, archive (export/import).
@@ -115,13 +121,15 @@ Available resources
115
121
  - `executions` (`ExecutionManager`): list/filter, running, get/delete, advanced query.
116
122
  - `tokens` (`TokenManager`): list, get, create, delete.
117
123
  - `users` (`UserManager`): user operations (per current implementation).
118
- - `metrics` (`MetricsManager`): `/metrics` endpoints (list/data/healthcheck/ping).
124
+ - `metrics` (`MetricsManager`): legacy `/api/V/metrics` endpoints (list/data/healthcheck/ping/threads).
125
+ - `monitoring` (`MonitoringManager`): modern non-versioned `/monitoring/*` endpoints (Prometheus, metrics, health, readiness, info, thread dump).
126
+ - `authorizations` (`AuthorizationsManager`): experimental authorization evaluation endpoints.
119
127
  - `plugins` (`PluginManager`): list installed plugins (`/plugin/list`).
120
128
  - `webhooks` (`WebhookEventManager` + `ProjectWebhookManager`): project webhook management and sending via token.
121
129
  - `key_storage` (`StorageKeyManager`): key storage management `/storage/keys`.
122
130
  - `adhoc` (`AdhocManager`, via `project.adhoc`): run AdHoc commands/scripts.
123
- - `system` (`SystemManager`): system info, executions enable/disable, logstorage, ACL.
124
- - `config_management` (`ConfigManagementManager`): global configuration `/config`.
131
+ - `system` (`SystemManager`): system info and summary, executions enable/disable, logstorage, ACL.
132
+ - `scheduler` (`SchedulerManager`): scheduled job listing and cluster schedule takeover (Community).
125
133
  - `scm` (via `project.scm` and `job.scm`): import/export plugins, setup, enable/disable, status, actions (commit/import/export...).
126
134
 
127
135
  Return types policy
@@ -130,7 +138,7 @@ Return types policy
130
138
  - Factory managers return the created resource object for actions that create it
131
139
  (e.g., `project.adhoc` returns `Execution`).
132
140
  - Utility managers return raw API responses (dict/str/bytes).
133
- - `delete(...)` returns `None`.
141
+ - CRUD `delete(...)` returns `None`; action endpoints returning a result body return that raw result.
134
142
  - Object methods return raw API responses and update the object in place when needed.
135
143
  - Explicit flags are used when an object return is requested (e.g., `as_execution=True`).
136
144
 
@@ -142,7 +150,7 @@ Factory managers:
142
150
  Returns `Execution` objects (execution factory).
143
151
 
144
152
  Utility managers:
145
- - `system`, `config_management`, `metrics`, `scheduler`, `webhooks` (event send).
153
+ - `system`, `metrics`, `scheduler`, `webhooks` (event send), `authorizations` (experimental).
146
154
  - `scm` (via `project.scm` and `job.scm`), and project sub-managers like
147
155
  `project.config`, `project.resources`, `project.sources`, `project.readme`,
148
156
  `project.archive`, `project.acl`.
@@ -150,6 +158,13 @@ Utility managers:
150
158
  Note: `project.webhooks.create(...)` returns the raw API response (e.g., `{"msg": "Saved webhook"}`)
151
159
  because the Rundeck API does not return the created webhook object.
152
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
+
153
168
  Example:
154
169
  ```python
155
170
  job = rd.jobs.get("job-id") # -> Job (object)
@@ -257,9 +272,11 @@ job.enable_schedule()
257
272
  job.disable_schedule()
258
273
  info = job.info()
259
274
  meta = job.meta(meta="name,description")
260
- tags = job.tags()
275
+ meta = job.meta(meta="*", meta_exclude="stats") # API v58+
261
276
  workflow = job.workflow()
262
- forecast = job.forecast(time="2024-05-01T10:00:00Z", max=5)
277
+ forecast = job.forecast(time="2024-05-01T10:00:00Z", max=5, past=False)
278
+ executions = job.executions(include_job_ref=True)
279
+ deleted = job.delete_executions()
263
280
 
264
281
  # Export/import jobs via manager (project parameter or parent)
265
282
  rd.jobs.export(project="demo", format="xml", idlist="id1,id2", groupPath="group")
@@ -460,14 +477,35 @@ if features:
460
477
  print(first.name, status.enabled)
461
478
  ```
462
479
 
463
- Global configuration `/config`
480
+ Monitoring
481
+ ----------
482
+ ```python
483
+ # Rundeck 6.0+ modern endpoints, outside /api/V.
484
+ health = rd.monitoring.health()
485
+ prometheus_text = rd.monitoring.prometheus()
486
+ metric = rd.monitoring.metric("jvm.memory.used", tags=["area:heap"])
487
+ thread_dump = rd.monitoring.thread_dump()
488
+
489
+ # Legacy metrics require rundeck.metrics.legacy.enabled=true on Rundeck 6.0.
490
+ legacy_threads = rd.metrics.threads()
491
+ ready = rd.monitoring.readiness()
492
+ ```
493
+
494
+ Community additions
495
+ -------------------
464
496
  ```python
465
- cfg = rd.config_management
466
- all_configs = cfg.list()
467
- cfg.save([{"key": "ui.banner", "value": "Hello"}])
468
- cfg.delete("ui.banner", strata="default")
469
- cfg.refresh()
470
- cfg.restart()
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"])
471
509
  ```
472
510
 
473
511
  Pagination
@@ -488,12 +526,13 @@ Development and testing
488
526
  - Formatting/Lint: `black src/rundeck tests/`, `ruff check src/rundeck tests/`
489
527
  - Typing: `mypy src/rundeck/`
490
528
  - Tests: `pytest`
491
- - Local integration tests: `scripts/run-integration.sh` (starts docker compose at repo root, exports by default `RUNDECK_URL=http://localhost:4440`, `RUNDECK_TOKEN=adminToken`, `RUNDECK_API_VERSION=56`, waits for the healthcheck, runs `poetry run pytest -m integration`). You can override env vars before running. 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`.
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.
492
531
 
493
532
  Code structure
494
533
  --------------
495
534
  - `src/rundeck/base.py`: generic objects/managers, `_build_path` helpers, pagination, CRUD.
496
535
  - `src/rundeck/client.py`: HTTP client, `http_get/post/put/delete/list` methods.
497
- - `src/rundeck/v1/objects/`: domain managers and objects (projects, jobs, executions, system, tokens, users, config_management).
498
- - 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.
499
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-v56), inspired by the python-gitlab architecture. Provides typed managers for key resources (projects, jobs, executions, tokens, users, system, configuration) 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=56)
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=56)
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,20 +58,24 @@ 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 (e.g. `56`)
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)
64
+ - `user_agent`: Custom HTTP User-Agent (string)
65
+ - `config_section`: Section name in config files (default: `rundeck`)
62
66
 
63
67
  Config files: if needed, pass `config_files` or `Rundeck.from_config(config_section=...)`.
64
68
  Useful env vars (client config):
65
69
  - `RUNDECK_URL`: Base URL
66
70
  - `RUNDECK_TOKEN`: API token (header `X-Rundeck-Auth-Token`)
67
71
  - `RUNDECK_USERNAME` / `RUNDECK_PASSWORD`: Session auth (if no token)
68
- - `RUNDECK_API_VERSION`: API version (e.g. 56)
72
+ - `RUNDECK_API_VERSION`: API version (default `59`; older server versions can be selected explicitly)
69
73
  - `RUNDECK_TIMEOUT`: Request timeout (seconds)
70
74
  - `RUNDECK_SSL_VERIFY`: TLS verification (bool or CA path)
71
75
  - `RUNDECK_USER_AGENT`: HTTP User-Agent
72
76
 
77
+ Rundeck 6.0+ accepts JSON for REST requests and responses. XML/YAML remain supported only as job, archive, and resource document formats.
78
+
73
79
  Available resources
74
80
  -------------------
75
81
  - `projects` (`ProjectManager`): CRUD projects, job export/import, project config, archive (export/import).
@@ -77,13 +83,15 @@ Available resources
77
83
  - `executions` (`ExecutionManager`): list/filter, running, get/delete, advanced query.
78
84
  - `tokens` (`TokenManager`): list, get, create, delete.
79
85
  - `users` (`UserManager`): user operations (per current implementation).
80
- - `metrics` (`MetricsManager`): `/metrics` endpoints (list/data/healthcheck/ping).
86
+ - `metrics` (`MetricsManager`): legacy `/api/V/metrics` endpoints (list/data/healthcheck/ping/threads).
87
+ - `monitoring` (`MonitoringManager`): modern non-versioned `/monitoring/*` endpoints (Prometheus, metrics, health, readiness, info, thread dump).
88
+ - `authorizations` (`AuthorizationsManager`): experimental authorization evaluation endpoints.
81
89
  - `plugins` (`PluginManager`): list installed plugins (`/plugin/list`).
82
90
  - `webhooks` (`WebhookEventManager` + `ProjectWebhookManager`): project webhook management and sending via token.
83
91
  - `key_storage` (`StorageKeyManager`): key storage management `/storage/keys`.
84
92
  - `adhoc` (`AdhocManager`, via `project.adhoc`): run AdHoc commands/scripts.
85
- - `system` (`SystemManager`): system info, executions enable/disable, logstorage, ACL.
86
- - `config_management` (`ConfigManagementManager`): global configuration `/config`.
93
+ - `system` (`SystemManager`): system info and summary, executions enable/disable, logstorage, ACL.
94
+ - `scheduler` (`SchedulerManager`): scheduled job listing and cluster schedule takeover (Community).
87
95
  - `scm` (via `project.scm` and `job.scm`): import/export plugins, setup, enable/disable, status, actions (commit/import/export...).
88
96
 
89
97
  Return types policy
@@ -92,7 +100,7 @@ Return types policy
92
100
  - Factory managers return the created resource object for actions that create it
93
101
  (e.g., `project.adhoc` returns `Execution`).
94
102
  - Utility managers return raw API responses (dict/str/bytes).
95
- - `delete(...)` returns `None`.
103
+ - CRUD `delete(...)` returns `None`; action endpoints returning a result body return that raw result.
96
104
  - Object methods return raw API responses and update the object in place when needed.
97
105
  - Explicit flags are used when an object return is requested (e.g., `as_execution=True`).
98
106
 
@@ -104,7 +112,7 @@ Factory managers:
104
112
  Returns `Execution` objects (execution factory).
105
113
 
106
114
  Utility managers:
107
- - `system`, `config_management`, `metrics`, `scheduler`, `webhooks` (event send).
115
+ - `system`, `metrics`, `scheduler`, `webhooks` (event send), `authorizations` (experimental).
108
116
  - `scm` (via `project.scm` and `job.scm`), and project sub-managers like
109
117
  `project.config`, `project.resources`, `project.sources`, `project.readme`,
110
118
  `project.archive`, `project.acl`.
@@ -112,6 +120,13 @@ Utility managers:
112
120
  Note: `project.webhooks.create(...)` returns the raw API response (e.g., `{"msg": "Saved webhook"}`)
113
121
  because the Rundeck API does not return the created webhook object.
114
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
+
115
130
  Example:
116
131
  ```python
117
132
  job = rd.jobs.get("job-id") # -> Job (object)
@@ -219,9 +234,11 @@ job.enable_schedule()
219
234
  job.disable_schedule()
220
235
  info = job.info()
221
236
  meta = job.meta(meta="name,description")
222
- tags = job.tags()
237
+ meta = job.meta(meta="*", meta_exclude="stats") # API v58+
223
238
  workflow = job.workflow()
224
- forecast = job.forecast(time="2024-05-01T10:00:00Z", max=5)
239
+ forecast = job.forecast(time="2024-05-01T10:00:00Z", max=5, past=False)
240
+ executions = job.executions(include_job_ref=True)
241
+ deleted = job.delete_executions()
225
242
 
226
243
  # Export/import jobs via manager (project parameter or parent)
227
244
  rd.jobs.export(project="demo", format="xml", idlist="id1,id2", groupPath="group")
@@ -422,14 +439,35 @@ if features:
422
439
  print(first.name, status.enabled)
423
440
  ```
424
441
 
425
- Global configuration `/config`
442
+ Monitoring
443
+ ----------
444
+ ```python
445
+ # Rundeck 6.0+ modern endpoints, outside /api/V.
446
+ health = rd.monitoring.health()
447
+ prometheus_text = rd.monitoring.prometheus()
448
+ metric = rd.monitoring.metric("jvm.memory.used", tags=["area:heap"])
449
+ thread_dump = rd.monitoring.thread_dump()
450
+
451
+ # Legacy metrics require rundeck.metrics.legacy.enabled=true on Rundeck 6.0.
452
+ legacy_threads = rd.metrics.threads()
453
+ ready = rd.monitoring.readiness()
454
+ ```
455
+
456
+ Community additions
457
+ -------------------
426
458
  ```python
427
- cfg = rd.config_management
428
- all_configs = cfg.list()
429
- cfg.save([{"key": "ui.banner", "value": "Hello"}])
430
- cfg.delete("ui.banner", strata="default")
431
- cfg.refresh()
432
- cfg.restart()
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"])
433
471
  ```
434
472
 
435
473
  Pagination
@@ -450,11 +488,12 @@ Development and testing
450
488
  - Formatting/Lint: `black src/rundeck tests/`, `ruff check src/rundeck tests/`
451
489
  - Typing: `mypy src/rundeck/`
452
490
  - Tests: `pytest`
453
- - Local integration tests: `scripts/run-integration.sh` (starts docker compose at repo root, exports by default `RUNDECK_URL=http://localhost:4440`, `RUNDECK_TOKEN=adminToken`, `RUNDECK_API_VERSION=56`, waits for the healthcheck, runs `poetry run pytest -m integration`). You can override env vars before running. 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`.
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.
454
493
 
455
494
  Code structure
456
495
  --------------
457
496
  - `src/rundeck/base.py`: generic objects/managers, `_build_path` helpers, pagination, CRUD.
458
497
  - `src/rundeck/client.py`: HTTP client, `http_get/post/put/delete/list` methods.
459
- - `src/rundeck/v1/objects/`: domain managers and objects (projects, jobs, executions, system, tokens, users, config_management).
460
- - 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.0.1"
4
- description = "Python client for the Rundeck API (v14-v56)."
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
  ]
@@ -1,8 +1,6 @@
1
- from __future__ import annotations
1
+ """Client principal pour l'API Rundeck."""
2
2
 
3
- """
4
- Client principal pour l'API Rundeck
5
- """
3
+ from __future__ import annotations
6
4
 
7
5
  from typing import Any
8
6
  from urllib.parse import urljoin
@@ -37,8 +35,10 @@ class Rundeck:
37
35
  api_version: int | None = None,
38
36
  timeout: float | None = None,
39
37
  ssl_verify: bool | None = None,
38
+ user_agent: str | None = None,
40
39
  session: requests.Session | None = None,
41
40
  config_files: list[str] | None = None,
41
+ config_section: str | None = None,
42
42
  ) -> None:
43
43
  self.config = RundeckConfig(
44
44
  url=url,
@@ -48,7 +48,9 @@ class Rundeck:
48
48
  api_version=api_version,
49
49
  timeout=timeout,
50
50
  ssl_verify=ssl_verify,
51
+ user_agent=user_agent,
51
52
  config_files=config_files,
53
+ config_section=config_section or "rundeck",
52
54
  )
53
55
 
54
56
  if not self.config.url:
@@ -79,12 +81,12 @@ class Rundeck:
79
81
  def _init_managers(self) -> None:
80
82
  """Initialise les managers d'objets."""
81
83
  # Import paresseux pour éviter les boucles d'import.
82
- from rundeck.v1.objects.config_management import ConfigManagementManager
84
+ from rundeck.v1.objects.authorizations import AuthorizationsManager
83
85
  from rundeck.v1.objects.executions import ExecutionManager
84
86
  from rundeck.v1.objects.features import FeatureManager
85
87
  from rundeck.v1.objects.jobs import JobManager
86
88
  from rundeck.v1.objects.key_storage import StorageKeyManager
87
- from rundeck.v1.objects.metrics import MetricsManager
89
+ from rundeck.v1.objects.metrics import MetricsManager, MonitoringManager
88
90
  from rundeck.v1.objects.plugins import PluginManager
89
91
  from rundeck.v1.objects.projects import ProjectManager
90
92
  from rundeck.v1.objects.scheduler import SchedulerManager
@@ -96,8 +98,9 @@ class Rundeck:
96
98
  self.projects = ProjectManager(self)
97
99
  self.jobs = JobManager(self)
98
100
  self.executions = ExecutionManager(self)
99
- self.config_management = ConfigManagementManager(self)
101
+ self.authorizations = AuthorizationsManager(self)
100
102
  self.metrics = MetricsManager(self)
103
+ self.monitoring = MonitoringManager(self)
101
104
  self.plugins = PluginManager(self)
102
105
  self.webhooks = WebhookEventManager(self)
103
106
  self.key_storage = StorageKeyManager(self)
@@ -107,6 +110,10 @@ class Rundeck:
107
110
  self.tokens = TokenManager(self)
108
111
  self.users = UserManager(self)
109
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
+
110
117
  @property
111
118
  def url(self) -> str:
112
119
  """URL fournie par l'utilisateur."""
@@ -127,6 +134,7 @@ class Rundeck:
127
134
  cls,
128
135
  config_section: str | None = None,
129
136
  config_files: list[str] | None = None,
137
+ user_agent: str | None = None,
130
138
  **kwargs: Any,
131
139
  ) -> "Rundeck":
132
140
  """
@@ -144,8 +152,10 @@ class Rundeck:
144
152
  api_version=conf.api_version,
145
153
  timeout=conf.timeout,
146
154
  ssl_verify=conf.ssl_verify,
155
+ user_agent=user_agent,
147
156
  session=kwargs.get("session"),
148
157
  config_files=config_files,
158
+ config_section=config_section,
149
159
  )
150
160
 
151
161
  def _authenticate_with_password(self) -> None:
@@ -265,14 +275,12 @@ class Rundeck:
265
275
  if raw:
266
276
  return response
267
277
 
268
- if method == HTTP_DELETE:
269
- return None
270
278
  if response.text:
271
279
  try:
272
280
  return response.json()
273
281
  except ValueError:
274
282
  return response.text
275
- return {}
283
+ return None if method == HTTP_DELETE else {}
276
284
 
277
285
  def http_get(
278
286
  self,
@@ -331,8 +339,8 @@ class Rundeck:
331
339
  url: str,
332
340
  raw: bool = False,
333
341
  **kwargs: Any,
334
- ) -> None:
335
- self._request(HTTP_DELETE, url, raw=raw, **kwargs)
342
+ ) -> Any:
343
+ return self._request(HTTP_DELETE, url, raw=raw, **kwargs)
336
344
 
337
345
  def __enter__(self) -> "Rundeck":
338
346
  return self
@@ -63,6 +63,7 @@ class RundeckConfig:
63
63
  api_version: int | str | None = None,
64
64
  timeout: float | None = None,
65
65
  ssl_verify: bool | str | None = None,
66
+ user_agent: str | None = None,
66
67
  config_files: list[str] | None = None,
67
68
  config_section: str = "rundeck",
68
69
  ) -> None:
@@ -103,7 +104,7 @@ class RundeckConfig:
103
104
  else _coerce_ssl_verify(env_ssl_verify or file_conf.get("ssl_verify"))
104
105
  )
105
106
  self.user_agent: str = (
106
- env_user_agent or file_conf.get("user_agent") or USER_AGENT
107
+ user_agent or env_user_agent or file_conf.get("user_agent") or USER_AGENT
107
108
  )
108
109
  self.config_files = files
109
110
 
@@ -0,0 +1,69 @@
1
+ """
2
+ Constantes partagées pour le client Rundeck.
3
+ """
4
+
5
+ import tomllib
6
+ from importlib.metadata import PackageNotFoundError, version
7
+ from pathlib import Path
8
+
9
+
10
+ # Package metadata
11
+ def _read_pyproject_version() -> str | None:
12
+ try:
13
+ root = Path(__file__).resolve().parents[2]
14
+ pyproject = root / "pyproject.toml"
15
+ if not pyproject.is_file():
16
+ return None
17
+ with pyproject.open("rb") as handle:
18
+ data = tomllib.load(handle)
19
+ return data.get("project", {}).get("version")
20
+ except Exception:
21
+ return None
22
+
23
+
24
+ try:
25
+ __version__ = version("python-rundeck")
26
+ except PackageNotFoundError: # pragma: no cover - fallback for local dev
27
+ __version__ = _read_pyproject_version() or "0.0.0"
28
+
29
+ # Auth
30
+ RUNDECK_AUTH_HEADER = "X-Rundeck-Auth-Token"
31
+
32
+ # HTTP methods
33
+ HTTP_GET = "GET"
34
+ HTTP_POST = "POST"
35
+ HTTP_PUT = "PUT"
36
+ HTTP_DELETE = "DELETE"
37
+
38
+ # Content / formats
39
+ FORMAT_JSON = "json"
40
+
41
+ # API versions. The library remains compatible with legacy Rundeck servers
42
+ # using v14, while current Rundeck servers require at least v17.
43
+ API_VERSION_CURRENT = "59"
44
+ API_VERSION_MIN = "14"
45
+ API_VERSION_SERVER_MIN = "17"
46
+ API_VERSION_DEPRECATION = "34"
47
+
48
+ # Defaults
49
+ DEFAULT_API_VERSION = API_VERSION_CURRENT
50
+ DEFAULT_TIMEOUT = 30
51
+ USER_AGENT = "python-rundeck"
52
+
53
+
54
+ __all__ = [
55
+ "__version__",
56
+ "API_VERSION_CURRENT",
57
+ "API_VERSION_DEPRECATION",
58
+ "API_VERSION_MIN",
59
+ "API_VERSION_SERVER_MIN",
60
+ "DEFAULT_API_VERSION",
61
+ "DEFAULT_TIMEOUT",
62
+ "FORMAT_JSON",
63
+ "HTTP_DELETE",
64
+ "HTTP_GET",
65
+ "HTTP_POST",
66
+ "HTTP_PUT",
67
+ "RUNDECK_AUTH_HEADER",
68
+ "USER_AGENT",
69
+ ]
@@ -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)
@@ -0,0 +1,35 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Mapping
4
+
5
+
6
+ def compact(*dicts: Mapping[str, Any], **kwargs: Any) -> dict[str, Any]:
7
+ """
8
+ Supprime les entrées dont la valeur est None.
9
+ """
10
+ result: dict[str, Any] = {}
11
+ for mapping in dicts:
12
+ if not mapping:
13
+ continue
14
+ for key, value in mapping.items():
15
+ if value is not None:
16
+ result[key] = value
17
+ for key, value in kwargs.items():
18
+ if value is not None:
19
+ result[key] = value
20
+ return result
21
+
22
+
23
+ def build_headers(
24
+ accept: str | None = None,
25
+ content_type: str | None = None,
26
+ ) -> dict[str, str] | None:
27
+ """
28
+ Construit les en-têtes standards (Accept/Content-Type).
29
+ """
30
+ headers: dict[str, str] = {}
31
+ if accept is not None:
32
+ headers["Accept"] = accept
33
+ if content_type is not None:
34
+ headers["Content-Type"] = content_type
35
+ return headers or None
@@ -0,0 +1,24 @@
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(
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
+ }
19
+
20
+ def _post_yaml(self, path: str, content: Any) -> Any:
21
+ return self.rd.http_post(path, data=content, headers=self._yaml_headers())
22
+
23
+ def _put_yaml(self, path: str, content: Any) -> Any:
24
+ return self.rd.http_put(path, data=content, headers=self._yaml_headers())