python-rundeck 1.0.1__tar.gz → 1.1.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 (33) hide show
  1. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/PKG-INFO +36 -13
  2. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/README.md +34 -11
  3. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/pyproject.toml +2 -2
  4. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/client.py +14 -10
  5. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/config.py +2 -1
  6. python_rundeck-1.1.0/src/rundeck/const.py +69 -0
  7. python_rundeck-1.1.0/src/rundeck/utils.py +35 -0
  8. python_rundeck-1.1.0/src/rundeck/v1/objects/acl.py +19 -0
  9. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/adhoc.py +3 -20
  10. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/config_management.py +16 -3
  11. python_rundeck-1.1.0/src/rundeck/v1/objects/executions.py +449 -0
  12. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/jobs.py +112 -43
  13. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/key_storage.py +10 -3
  14. python_rundeck-1.1.0/src/rundeck/v1/objects/metrics.py +77 -0
  15. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/projects.py +136 -71
  16. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/scheduler.py +15 -7
  17. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/scm.py +5 -0
  18. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/system.py +4 -5
  19. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/users.py +33 -16
  20. python_rundeck-1.0.1/src/rundeck/const.py +0 -45
  21. python_rundeck-1.0.1/src/rundeck/v1/objects/executions.py +0 -326
  22. python_rundeck-1.0.1/src/rundeck/v1/objects/metrics.py +0 -37
  23. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/LICENSE +0 -0
  24. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/__init__.py +0 -0
  25. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/base.py +0 -0
  26. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/exceptions.py +0 -0
  27. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/py.typed +0 -0
  28. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/__init__.py +0 -0
  29. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/__init__.py +0 -0
  30. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/features.py +0 -0
  31. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/plugins.py +0 -0
  32. {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/tokens.py +0 -0
  33. {python_rundeck-1.0.1 → python_rundeck-1.1.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: 1.1.0
4
+ Summary: Python client for the Rundeck API (v14-v58).
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
7
7
  Keywords: rundeck,api,client
@@ -43,7 +43,7 @@ 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 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).
47
47
 
48
48
  Contents
49
49
  --------
@@ -69,9 +69,9 @@ Quick start
69
69
  ```python
70
70
  from rundeck.client import Rundeck
71
71
 
72
- rd = Rundeck(url="https://rundeck.example.com", token="MY_TOKEN", api_version=56)
72
+ rd = Rundeck(url="https://rundeck.example.com", token="MY_TOKEN", api_version=58)
73
73
  # Password auth (session cookie) if no token
74
- rd = Rundeck(url="https://rundeck.example.com", username="admin", password="admin", api_version=56)
74
+ rd = Rundeck(url="https://rundeck.example.com", username="admin", password="admin", api_version=58)
75
75
 
76
76
  # List projects
77
77
  projects = rd.projects.list()
@@ -94,20 +94,24 @@ Main parameters:
94
94
  - `url`: Rundeck URL (e.g. `https://rundeck.example.com`)
95
95
  - `token`: API token (header `X-Rundeck-Auth-Token`)
96
96
  - `username` / `password`: Session authentication (j_security_check) if no token is provided.
97
- - `api_version`: API version (e.g. `56`)
97
+ - `api_version`: API version (default: `58`)
98
98
  - `timeout`: Request timeout (float, seconds)
99
99
  - `ssl_verify`: TLS verification (bool or CA path)
100
+ - `user_agent`: Custom HTTP User-Agent (string)
101
+ - `config_section`: Section name in config files (default: `rundeck`)
100
102
 
101
103
  Config files: if needed, pass `config_files` or `Rundeck.from_config(config_section=...)`.
102
104
  Useful env vars (client config):
103
105
  - `RUNDECK_URL`: Base URL
104
106
  - `RUNDECK_TOKEN`: API token (header `X-Rundeck-Auth-Token`)
105
107
  - `RUNDECK_USERNAME` / `RUNDECK_PASSWORD`: Session auth (if no token)
106
- - `RUNDECK_API_VERSION`: API version (e.g. 56)
108
+ - `RUNDECK_API_VERSION`: API version (e.g. 58)
107
109
  - `RUNDECK_TIMEOUT`: Request timeout (seconds)
108
110
  - `RUNDECK_SSL_VERIFY`: TLS verification (bool or CA path)
109
111
  - `RUNDECK_USER_AGENT`: HTTP User-Agent
110
112
 
113
+ Rundeck 6.0+ accepts JSON for REST requests and responses. XML/YAML remain supported only as job, archive, and resource document formats.
114
+
111
115
  Available resources
112
116
  -------------------
113
117
  - `projects` (`ProjectManager`): CRUD projects, job export/import, project config, archive (export/import).
@@ -115,13 +119,15 @@ Available resources
115
119
  - `executions` (`ExecutionManager`): list/filter, running, get/delete, advanced query.
116
120
  - `tokens` (`TokenManager`): list, get, create, delete.
117
121
  - `users` (`UserManager`): user operations (per current implementation).
118
- - `metrics` (`MetricsManager`): `/metrics` endpoints (list/data/healthcheck/ping).
122
+ - `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).
119
124
  - `plugins` (`PluginManager`): list installed plugins (`/plugin/list`).
120
125
  - `webhooks` (`WebhookEventManager` + `ProjectWebhookManager`): project webhook management and sending via token.
121
126
  - `key_storage` (`StorageKeyManager`): key storage management `/storage/keys`.
122
127
  - `adhoc` (`AdhocManager`, via `project.adhoc`): run AdHoc commands/scripts.
123
128
  - `system` (`SystemManager`): system info, executions enable/disable, logstorage, ACL.
124
- - `config_management` (`ConfigManagementManager`): global configuration `/config`.
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).
125
131
  - `scm` (via `project.scm` and `job.scm`): import/export plugins, setup, enable/disable, status, actions (commit/import/export...).
126
132
 
127
133
  Return types policy
@@ -130,7 +136,7 @@ Return types policy
130
136
  - Factory managers return the created resource object for actions that create it
131
137
  (e.g., `project.adhoc` returns `Execution`).
132
138
  - Utility managers return raw API responses (dict/str/bytes).
133
- - `delete(...)` returns `None`.
139
+ - CRUD `delete(...)` returns `None`; action endpoints returning a result body return that raw result.
134
140
  - Object methods return raw API responses and update the object in place when needed.
135
141
  - Explicit flags are used when an object return is requested (e.g., `as_execution=True`).
136
142
 
@@ -257,9 +263,11 @@ job.enable_schedule()
257
263
  job.disable_schedule()
258
264
  info = job.info()
259
265
  meta = job.meta(meta="name,description")
260
- tags = job.tags()
266
+ meta = job.meta(meta="*", meta_exclude="stats") # API v58+
261
267
  workflow = job.workflow()
262
- forecast = job.forecast(time="2024-05-01T10:00:00Z", max=5)
268
+ forecast = job.forecast(time="2024-05-01T10:00:00Z", max=5, past=False)
269
+ executions = job.executions(include_job_ref=True)
270
+ deleted = job.delete_executions()
263
271
 
264
272
  # Export/import jobs via manager (project parameter or parent)
265
273
  rd.jobs.export(project="demo", format="xml", idlist="id1,id2", groupPath="group")
@@ -462,6 +470,7 @@ if features:
462
470
 
463
471
  Global configuration `/config`
464
472
  ```python
473
+ # Commercial compatibility surface; deprecated and removed in 2.0.
465
474
  cfg = rd.config_management
466
475
  all_configs = cfg.list()
467
476
  cfg.save([{"key": "ui.banner", "value": "Hello"}])
@@ -470,6 +479,19 @@ cfg.refresh()
470
479
  cfg.restart()
471
480
  ```
472
481
 
482
+ Monitoring
483
+ ----------
484
+ ```python
485
+ # Rundeck 6.0+ modern endpoints, outside /api/V.
486
+ health = rd.monitoring.health()
487
+ prometheus_text = rd.monitoring.prometheus()
488
+ metric = rd.monitoring.metric("jvm.memory.used", tags=["area:heap"])
489
+ thread_dump = rd.monitoring.thread_dump()
490
+
491
+ # Legacy metrics require rundeck.metrics.legacy.enabled=true on Rundeck 6.0.
492
+ legacy_threads = rd.metrics.threads()
493
+ ```
494
+
473
495
  Pagination
474
496
  ----------
475
497
  Managers inherit `RundeckObjectManager.iter(...)` (offset/max). Example:
@@ -488,7 +510,8 @@ Development and testing
488
510
  - Formatting/Lint: `black src/rundeck tests/`, `ruff check src/rundeck tests/`
489
511
  - Typing: `mypy src/rundeck/`
490
512
  - 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`.
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`.
514
+ - 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
515
 
493
516
  Code structure
494
517
  --------------
@@ -5,7 +5,7 @@ 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 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).
9
9
 
10
10
  Contents
11
11
  --------
@@ -31,9 +31,9 @@ Quick start
31
31
  ```python
32
32
  from rundeck.client import Rundeck
33
33
 
34
- rd = Rundeck(url="https://rundeck.example.com", token="MY_TOKEN", api_version=56)
34
+ rd = Rundeck(url="https://rundeck.example.com", token="MY_TOKEN", api_version=58)
35
35
  # Password auth (session cookie) if no token
36
- rd = Rundeck(url="https://rundeck.example.com", username="admin", password="admin", api_version=56)
36
+ rd = Rundeck(url="https://rundeck.example.com", username="admin", password="admin", api_version=58)
37
37
 
38
38
  # List projects
39
39
  projects = rd.projects.list()
@@ -56,20 +56,24 @@ Main parameters:
56
56
  - `url`: Rundeck URL (e.g. `https://rundeck.example.com`)
57
57
  - `token`: API token (header `X-Rundeck-Auth-Token`)
58
58
  - `username` / `password`: Session authentication (j_security_check) if no token is provided.
59
- - `api_version`: API version (e.g. `56`)
59
+ - `api_version`: API version (default: `58`)
60
60
  - `timeout`: Request timeout (float, seconds)
61
61
  - `ssl_verify`: TLS verification (bool or CA path)
62
+ - `user_agent`: Custom HTTP User-Agent (string)
63
+ - `config_section`: Section name in config files (default: `rundeck`)
62
64
 
63
65
  Config files: if needed, pass `config_files` or `Rundeck.from_config(config_section=...)`.
64
66
  Useful env vars (client config):
65
67
  - `RUNDECK_URL`: Base URL
66
68
  - `RUNDECK_TOKEN`: API token (header `X-Rundeck-Auth-Token`)
67
69
  - `RUNDECK_USERNAME` / `RUNDECK_PASSWORD`: Session auth (if no token)
68
- - `RUNDECK_API_VERSION`: API version (e.g. 56)
70
+ - `RUNDECK_API_VERSION`: API version (e.g. 58)
69
71
  - `RUNDECK_TIMEOUT`: Request timeout (seconds)
70
72
  - `RUNDECK_SSL_VERIFY`: TLS verification (bool or CA path)
71
73
  - `RUNDECK_USER_AGENT`: HTTP User-Agent
72
74
 
75
+ Rundeck 6.0+ accepts JSON for REST requests and responses. XML/YAML remain supported only as job, archive, and resource document formats.
76
+
73
77
  Available resources
74
78
  -------------------
75
79
  - `projects` (`ProjectManager`): CRUD projects, job export/import, project config, archive (export/import).
@@ -77,13 +81,15 @@ Available resources
77
81
  - `executions` (`ExecutionManager`): list/filter, running, get/delete, advanced query.
78
82
  - `tokens` (`TokenManager`): list, get, create, delete.
79
83
  - `users` (`UserManager`): user operations (per current implementation).
80
- - `metrics` (`MetricsManager`): `/metrics` endpoints (list/data/healthcheck/ping).
84
+ - `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).
81
86
  - `plugins` (`PluginManager`): list installed plugins (`/plugin/list`).
82
87
  - `webhooks` (`WebhookEventManager` + `ProjectWebhookManager`): project webhook management and sending via token.
83
88
  - `key_storage` (`StorageKeyManager`): key storage management `/storage/keys`.
84
89
  - `adhoc` (`AdhocManager`, via `project.adhoc`): run AdHoc commands/scripts.
85
90
  - `system` (`SystemManager`): system info, executions enable/disable, logstorage, ACL.
86
- - `config_management` (`ConfigManagementManager`): global configuration `/config`.
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).
87
93
  - `scm` (via `project.scm` and `job.scm`): import/export plugins, setup, enable/disable, status, actions (commit/import/export...).
88
94
 
89
95
  Return types policy
@@ -92,7 +98,7 @@ Return types policy
92
98
  - Factory managers return the created resource object for actions that create it
93
99
  (e.g., `project.adhoc` returns `Execution`).
94
100
  - Utility managers return raw API responses (dict/str/bytes).
95
- - `delete(...)` returns `None`.
101
+ - CRUD `delete(...)` returns `None`; action endpoints returning a result body return that raw result.
96
102
  - Object methods return raw API responses and update the object in place when needed.
97
103
  - Explicit flags are used when an object return is requested (e.g., `as_execution=True`).
98
104
 
@@ -219,9 +225,11 @@ job.enable_schedule()
219
225
  job.disable_schedule()
220
226
  info = job.info()
221
227
  meta = job.meta(meta="name,description")
222
- tags = job.tags()
228
+ meta = job.meta(meta="*", meta_exclude="stats") # API v58+
223
229
  workflow = job.workflow()
224
- forecast = job.forecast(time="2024-05-01T10:00:00Z", max=5)
230
+ forecast = job.forecast(time="2024-05-01T10:00:00Z", max=5, past=False)
231
+ executions = job.executions(include_job_ref=True)
232
+ deleted = job.delete_executions()
225
233
 
226
234
  # Export/import jobs via manager (project parameter or parent)
227
235
  rd.jobs.export(project="demo", format="xml", idlist="id1,id2", groupPath="group")
@@ -424,6 +432,7 @@ if features:
424
432
 
425
433
  Global configuration `/config`
426
434
  ```python
435
+ # Commercial compatibility surface; deprecated and removed in 2.0.
427
436
  cfg = rd.config_management
428
437
  all_configs = cfg.list()
429
438
  cfg.save([{"key": "ui.banner", "value": "Hello"}])
@@ -432,6 +441,19 @@ cfg.refresh()
432
441
  cfg.restart()
433
442
  ```
434
443
 
444
+ Monitoring
445
+ ----------
446
+ ```python
447
+ # Rundeck 6.0+ modern endpoints, outside /api/V.
448
+ health = rd.monitoring.health()
449
+ prometheus_text = rd.monitoring.prometheus()
450
+ metric = rd.monitoring.metric("jvm.memory.used", tags=["area:heap"])
451
+ thread_dump = rd.monitoring.thread_dump()
452
+
453
+ # Legacy metrics require rundeck.metrics.legacy.enabled=true on Rundeck 6.0.
454
+ legacy_threads = rd.metrics.threads()
455
+ ```
456
+
435
457
  Pagination
436
458
  ----------
437
459
  Managers inherit `RundeckObjectManager.iter(...)` (offset/max). Example:
@@ -450,7 +472,8 @@ Development and testing
450
472
  - Formatting/Lint: `black src/rundeck tests/`, `ruff check src/rundeck tests/`
451
473
  - Typing: `mypy src/rundeck/`
452
474
  - 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`.
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`.
476
+ - 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
477
 
455
478
  Code structure
456
479
  --------------
@@ -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 = "1.1.0"
4
+ description = "Python client for the Rundeck API (v14-v58)."
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:
@@ -84,7 +86,7 @@ class Rundeck:
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
@@ -98,6 +100,7 @@ class Rundeck:
98
100
  self.executions = ExecutionManager(self)
99
101
  self.config_management = ConfigManagementManager(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)
@@ -127,6 +130,7 @@ class Rundeck:
127
130
  cls,
128
131
  config_section: str | None = None,
129
132
  config_files: list[str] | None = None,
133
+ user_agent: str | None = None,
130
134
  **kwargs: Any,
131
135
  ) -> "Rundeck":
132
136
  """
@@ -144,8 +148,10 @@ class Rundeck:
144
148
  api_version=conf.api_version,
145
149
  timeout=conf.timeout,
146
150
  ssl_verify=conf.ssl_verify,
151
+ user_agent=user_agent,
147
152
  session=kwargs.get("session"),
148
153
  config_files=config_files,
154
+ config_section=config_section,
149
155
  )
150
156
 
151
157
  def _authenticate_with_password(self) -> None:
@@ -265,14 +271,12 @@ class Rundeck:
265
271
  if raw:
266
272
  return response
267
273
 
268
- if method == HTTP_DELETE:
269
- return None
270
274
  if response.text:
271
275
  try:
272
276
  return response.json()
273
277
  except ValueError:
274
278
  return response.text
275
- return {}
279
+ return None if method == HTTP_DELETE else {}
276
280
 
277
281
  def http_get(
278
282
  self,
@@ -331,8 +335,8 @@ class Rundeck:
331
335
  url: str,
332
336
  raw: bool = False,
333
337
  **kwargs: Any,
334
- ) -> None:
335
- self._request(HTTP_DELETE, url, raw=raw, **kwargs)
338
+ ) -> Any:
339
+ return self._request(HTTP_DELETE, url, raw=raw, **kwargs)
336
340
 
337
341
  def __enter__(self) -> "Rundeck":
338
342
  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
+ from importlib.metadata import PackageNotFoundError, version
6
+ from pathlib import Path
7
+ import tomllib
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 = "58"
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
+ ]
@@ -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,19 @@
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())
@@ -19,23 +19,6 @@ class AdhocManager(RundeckObjectManager[Execution]):
19
19
  raise ValueError("Le nom du projet est requis pour les commandes AdHoc")
20
20
  return project_name
21
21
 
22
- def _wrap_execution(self, result: Any, refresh: bool = True) -> Execution:
23
- data = (
24
- result.get("execution")
25
- if isinstance(result, dict) and "execution" in result
26
- else result
27
- )
28
- if isinstance(data, dict):
29
- exec_id = data.get("id")
30
- # Les réponses AdHoc ne sont pas complètes,
31
- # Le rafraîchissement permet d'obtenir toutes les données
32
- if refresh and exec_id:
33
- try:
34
- return self.rd.executions.get(exec_id)
35
- except Exception:
36
- return Execution(self.rd.executions, data)
37
- return Execution(self.rd.executions, data)
38
-
39
22
  def run_command(
40
23
  self,
41
24
  exec: str,
@@ -49,7 +32,7 @@ class AdhocManager(RundeckObjectManager[Execution]):
49
32
  payload.update(options)
50
33
  path = f"/project/{project_name}/run/command"
51
34
  result = self.rd.http_post(path, json=payload)
52
- return self._wrap_execution(result, refresh=refresh)
35
+ return self.rd.executions.wrap_execution(result, refresh=refresh)
53
36
 
54
37
  def run_script(
55
38
  self,
@@ -72,7 +55,7 @@ class AdhocManager(RundeckObjectManager[Execution]):
72
55
  payload: dict[str, Any] = {"script": script or "", "project": project_name}
73
56
  payload.update(options)
74
57
  result = self.rd.http_post(path, json=payload)
75
- return self._wrap_execution(result, refresh=refresh)
58
+ return self.rd.executions.wrap_execution(result, refresh=refresh)
76
59
 
77
60
  def run_url(
78
61
  self,
@@ -87,7 +70,7 @@ class AdhocManager(RundeckObjectManager[Execution]):
87
70
  payload.update(options)
88
71
  path = f"/project/{project_name}/run/url"
89
72
  result = self.rd.http_post(path, json=payload)
90
- return self._wrap_execution(result, refresh=refresh)
73
+ return self.rd.executions.wrap_execution(result, refresh=refresh)
91
74
 
92
75
 
93
76
  __all__ = ["AdhocManager"]
@@ -1,8 +1,8 @@
1
+ """Gestion de la configuration Rundeck (instance globale)."""
2
+
1
3
  from __future__ import annotations
2
4
 
3
- """
4
- Gestion de la configuration Rundeck (instance globale).
5
- """
5
+ import warnings
6
6
 
7
7
  from rundeck.base import RundeckObjectManager
8
8
 
@@ -14,8 +14,17 @@ class ConfigManagementManager(RundeckObjectManager):
14
14
 
15
15
  _path = "/config"
16
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
+
17
25
  def list(self) -> list[dict[str, str]]:
18
26
  """Liste toutes les configs et propriétés."""
27
+ self._warn_commercial()
19
28
  path = self._build_path("list")
20
29
  return self.rd.http_get(path)
21
30
 
@@ -23,6 +32,7 @@ class ConfigManagementManager(RundeckObjectManager):
23
32
  """
24
33
  Crée ou met à jour des configs (payload: liste de dicts {key, value, strata?}).
25
34
  """
35
+ self._warn_commercial()
26
36
  path = self._build_path("save")
27
37
  return self.rd.http_post(path, json=entries)
28
38
 
@@ -30,6 +40,7 @@ class ConfigManagementManager(RundeckObjectManager):
30
40
  """
31
41
  Supprime une config via /config/delete avec payload JSON.
32
42
  """
43
+ self._warn_commercial()
33
44
  payload: dict[str, str] = {"key": key}
34
45
  if strata:
35
46
  payload["strata"] = strata
@@ -40,6 +51,7 @@ class ConfigManagementManager(RundeckObjectManager):
40
51
  """
41
52
  Recharge les configurations depuis les fichiers de propriétés.
42
53
  """
54
+ self._warn_commercial()
43
55
  path = self._build_path("refresh")
44
56
  return self.rd.http_post(path)
45
57
 
@@ -47,5 +59,6 @@ class ConfigManagementManager(RundeckObjectManager):
47
59
  """
48
60
  Redémarre le serveur Rundeck.
49
61
  """
62
+ self._warn_commercial()
50
63
  path = self._build_path("restart")
51
64
  return self.rd.http_post(path)