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.
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/PKG-INFO +36 -13
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/README.md +34 -11
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/pyproject.toml +2 -2
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/client.py +14 -10
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/config.py +2 -1
- python_rundeck-1.1.0/src/rundeck/const.py +69 -0
- python_rundeck-1.1.0/src/rundeck/utils.py +35 -0
- python_rundeck-1.1.0/src/rundeck/v1/objects/acl.py +19 -0
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/adhoc.py +3 -20
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/config_management.py +16 -3
- python_rundeck-1.1.0/src/rundeck/v1/objects/executions.py +449 -0
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/jobs.py +112 -43
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/key_storage.py +10 -3
- python_rundeck-1.1.0/src/rundeck/v1/objects/metrics.py +77 -0
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/projects.py +136 -71
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/scheduler.py +15 -7
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/scm.py +5 -0
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/system.py +4 -5
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/users.py +33 -16
- python_rundeck-1.0.1/src/rundeck/const.py +0 -45
- python_rundeck-1.0.1/src/rundeck/v1/objects/executions.py +0 -326
- python_rundeck-1.0.1/src/rundeck/v1/objects/metrics.py +0 -37
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/LICENSE +0 -0
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/__init__.py +0 -0
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/base.py +0 -0
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/exceptions.py +0 -0
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/py.typed +0 -0
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/__init__.py +0 -0
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/__init__.py +0 -0
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/features.py +0 -0
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/plugins.py +0 -0
- {python_rundeck-1.0.1 → python_rundeck-1.1.0}/src/rundeck/v1/objects/tokens.py +0 -0
- {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
|
|
4
|
-
Summary: Python client for the Rundeck API (v14-
|
|
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
|

|
|
44
44
|

|
|
45
45
|
|
|
46
|
-
Python client for the Rundeck API (v14-
|
|
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=
|
|
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=
|
|
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 (
|
|
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.
|
|
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
|
-
|
|
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`
|
|
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
|

|
|
6
6
|

|
|
7
7
|
|
|
8
|
-
Python client for the Rundeck API (v14-
|
|
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=
|
|
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=
|
|
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 (
|
|
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.
|
|
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
|
-
|
|
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`
|
|
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
|
|
4
|
-
description = "Python client for the Rundeck API (v14-
|
|
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
|
-
|
|
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
|
-
) ->
|
|
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.
|
|
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.
|
|
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.
|
|
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)
|