python-rundeck 0.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-0.1.0/LICENSE +21 -0
- python_rundeck-0.1.0/PKG-INFO +454 -0
- python_rundeck-0.1.0/README.md +420 -0
- python_rundeck-0.1.0/pyproject.toml +70 -0
- python_rundeck-0.1.0/src/rundeck/__init__.py +39 -0
- python_rundeck-0.1.0/src/rundeck/base.py +231 -0
- python_rundeck-0.1.0/src/rundeck/client.py +341 -0
- python_rundeck-0.1.0/src/rundeck/config.py +166 -0
- python_rundeck-0.1.0/src/rundeck/const.py +45 -0
- python_rundeck-0.1.0/src/rundeck/exceptions.py +164 -0
- python_rundeck-0.1.0/src/rundeck/py.typed +1 -0
- python_rundeck-0.1.0/src/rundeck/v1/__init__.py +1 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/__init__.py +1 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/adhoc.py +93 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/config_management.py +51 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/executions.py +327 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/features.py +44 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/jobs.py +329 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/key_storage.py +79 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/metrics.py +37 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/plugins.py +38 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/projects.py +421 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/scheduler.py +50 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/scm.py +229 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/system.py +140 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/tokens.py +102 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/users.py +137 -0
- python_rundeck-0.1.0/src/rundeck/v1/objects/webhooks.py +104 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Pascal Seckinger
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-rundeck
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for the Rundeck API (v14-v56).
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: rundeck,api,client
|
|
8
|
+
Author: Pascal Seckinger
|
|
9
|
+
Author-email: pascal.seckinger@protonmail.com
|
|
10
|
+
Requires-Python: >=3.11
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
20
|
+
Classifier: Topic :: System :: Systems Administration
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: bandit (>=1.7.9,<2.0.0) ; extra == "dev"
|
|
24
|
+
Requires-Dist: black (>=25.11.0,<26.0.0) ; extra == "dev"
|
|
25
|
+
Requires-Dist: flake8 (>=7.0.0,<8.0.0) ; extra == "dev"
|
|
26
|
+
Requires-Dist: isort (>=7.0.0,<8.0.0) ; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest (>=9.0.2,<10.0.0) ; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-cov (>=5.0.0,<6.0.0) ; extra == "dev"
|
|
29
|
+
Requires-Dist: requests (>=2.32.5,<3.0.0)
|
|
30
|
+
Requires-Dist: ruff (>=0.7.0,<1.0.0) ; extra == "dev"
|
|
31
|
+
Requires-Dist: safety (>=3.2.0,<4.0.0) ; extra == "dev"
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
python-rundeck
|
|
35
|
+
===============
|
|
36
|
+
|
|
37
|
+
Client Python pour l’API Rundeck (v14–v56), inspiré de l’architecture de python-gitlab. Fournit des managers typés pour les ressources clés (projects, jobs, executions, tokens, users, système, configuration) et SCM (import/export).
|
|
38
|
+
|
|
39
|
+
Sommaire
|
|
40
|
+
--------
|
|
41
|
+
- Installation
|
|
42
|
+
- Démarrage rapide
|
|
43
|
+
- Configuration
|
|
44
|
+
- Ressources disponibles
|
|
45
|
+
- Exemples par ressource
|
|
46
|
+
- Gestion des erreurs
|
|
47
|
+
- Développement et tests
|
|
48
|
+
|
|
49
|
+
Installation
|
|
50
|
+
------------
|
|
51
|
+
Prerequis : Python 3.11+. Le projet utilise Poetry.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
poetry install
|
|
55
|
+
# ou en editable avec pip
|
|
56
|
+
pip install -e .
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Démarrage rapide
|
|
60
|
+
----------------
|
|
61
|
+
```python
|
|
62
|
+
from rundeck.client import Rundeck
|
|
63
|
+
|
|
64
|
+
rd = Rundeck(url="https://rundeck.example.com", token="MY_TOKEN", api_version=56)
|
|
65
|
+
# Auth par mot de passe (session cookie) si pas de token
|
|
66
|
+
rd = Rundeck(url="https://rundeck.example.com", username="admin", password="admin", api_version=56)
|
|
67
|
+
|
|
68
|
+
# Lister les projets
|
|
69
|
+
projects = rd.projects.list()
|
|
70
|
+
for p in projects:
|
|
71
|
+
print(p.name)
|
|
72
|
+
|
|
73
|
+
# Récupérer un projet et lancer un job
|
|
74
|
+
project = rd.projects.get("demo")
|
|
75
|
+
jobs = project.jobs.list()
|
|
76
|
+
execu = jobs[0].run()
|
|
77
|
+
print(execu.id)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Configuration
|
|
81
|
+
-------------
|
|
82
|
+
La configuration suit un modèle en cascade (args > env > fichiers > défauts) via `RundeckConfig`.
|
|
83
|
+
|
|
84
|
+
Paramètres principaux :
|
|
85
|
+
- `url` : URL Rundeck (ex. `https://rundeck.example.com`)
|
|
86
|
+
- `token` : Token API (en-tête `X-Rundeck-Auth-Token`)
|
|
87
|
+
- `username` / `password` : Authentification par session (j_security_check) si aucun token n'est fourni.
|
|
88
|
+
- `api_version` : Version d’API (ex. `56`)
|
|
89
|
+
- `timeout` : Timeout des requêtes (float, secondes)
|
|
90
|
+
- `ssl_verify` : Vérification TLS (bool ou chemin CA)
|
|
91
|
+
|
|
92
|
+
Fichiers de config : si besoin, passez `config_files` ou `Rundeck.from_config(config_section=...)`.
|
|
93
|
+
Variables d'env utiles (config client) :
|
|
94
|
+
- `RUNDECK_URL` : URL de base
|
|
95
|
+
- `RUNDECK_TOKEN` : token API (en-tête `X-Rundeck-Auth-Token`)
|
|
96
|
+
- `RUNDECK_USERNAME` / `RUNDECK_PASSWORD` : auth session (si pas de token)
|
|
97
|
+
- `RUNDECK_API_VERSION` : version d'API (ex: 56)
|
|
98
|
+
- `RUNDECK_TIMEOUT` : timeout des requêtes (secondes)
|
|
99
|
+
- `RUNDECK_SSL_VERIFY` : vérification TLS (bool ou chemin CA)
|
|
100
|
+
- `RUNDECK_USER_AGENT` : User-Agent HTTP
|
|
101
|
+
|
|
102
|
+
Ressources disponibles
|
|
103
|
+
----------------------
|
|
104
|
+
- `projects` (`ProjectManager`) : CRUD projets, export/import de jobs, config projet, archive (export/import).
|
|
105
|
+
- `jobs` (`JobManager`) : liste, get, suppressions, actions bulk, exécution.
|
|
106
|
+
- `executions` (`ExecutionManager`) : liste/filtre, running, get/delete, query avancée.
|
|
107
|
+
- `tokens` (`TokenManager`) : liste, get, create, delete.
|
|
108
|
+
- `users` (`UserManager`) : opérations utilisateurs (selon implémentation courante).
|
|
109
|
+
- `metrics` (`MetricsManager`) : endpoints `/metrics` (list/data/healthcheck/ping).
|
|
110
|
+
- `plugins` (`PluginManager`) : liste des plugins installés (`/plugin/list`).
|
|
111
|
+
- `webhooks` (`WebhookEventManager` + `ProjectWebhookManager`) : gestion des webhooks projet et envoi via token.
|
|
112
|
+
- `key_storage` (`StorageKeyManager`) : gestion du stockage des clés `/storage/keys`.
|
|
113
|
+
- `adhoc` (`AdhocManager`, via `project.adhoc`) : exécution de commandes/scripts AdHoc.
|
|
114
|
+
- `system` (`SystemManager`) : info système, exécutions enable/disable, logstorage, ACL.
|
|
115
|
+
- `config_management` (`ConfigManagementManager`) : configuration globale `/config`.
|
|
116
|
+
- `scm` (via `project.scm` et `job.scm`) : plugins import/export, setup, enable/disable, statut, actions (commit/import/export...).
|
|
117
|
+
|
|
118
|
+
Exemples par ressource (complets)
|
|
119
|
+
---------------------------------
|
|
120
|
+
Projets
|
|
121
|
+
```python
|
|
122
|
+
# CRUD projet
|
|
123
|
+
p = rd.projects.create("demo")
|
|
124
|
+
p = rd.projects.get("demo")
|
|
125
|
+
rd.projects.delete("demo")
|
|
126
|
+
projects = rd.projects.list()
|
|
127
|
+
|
|
128
|
+
# Export / import de jobs d'un projet (via le manager de jobs)
|
|
129
|
+
project.jobs.export(format="json", idlist="id1,id2", groupPath="group/sub")
|
|
130
|
+
project.jobs.import_jobs(content=open("jobs.json").read(), format="json", dupeOption="update", uuidOption="remove")
|
|
131
|
+
|
|
132
|
+
# Export / import du projet (archive ZIP)
|
|
133
|
+
archive = project.archive
|
|
134
|
+
resp = archive.export(export_all=False, export_webhooks=True) # Response brute (zip)
|
|
135
|
+
token_info = archive.export_async(exportAll=True)
|
|
136
|
+
status = archive.export_status(token_info.get("token", ""))
|
|
137
|
+
zip_resp = archive.export_download(token_info.get("token", ""))
|
|
138
|
+
|
|
139
|
+
# Import d'archive (synchrone ou async)
|
|
140
|
+
archive.import_archive(
|
|
141
|
+
content=open("project-export.zip", "rb").read(),
|
|
142
|
+
jobUuidOption="preserve",
|
|
143
|
+
importExecutions=True,
|
|
144
|
+
importConfig=True,
|
|
145
|
+
)
|
|
146
|
+
archive.import_archive(content=open("project-export.zip", "rb").read(), async_import=True)
|
|
147
|
+
archive.import_status()
|
|
148
|
+
|
|
149
|
+
# Readme / MOTD du projet
|
|
150
|
+
project.readme.get_readme() # texte par défaut
|
|
151
|
+
project.readme.get_readme(accept="application/json")
|
|
152
|
+
project.readme.update_readme("Nouveau contenu", content_type="text/plain")
|
|
153
|
+
project.readme.delete_readme()
|
|
154
|
+
project.readme.get_motd()
|
|
155
|
+
project.readme.update_motd("Message du jour", content_type="text/plain")
|
|
156
|
+
project.readme.delete_motd()
|
|
157
|
+
|
|
158
|
+
# Config projet (clé/valeur)
|
|
159
|
+
conf = p.config.get()
|
|
160
|
+
p.config.keys.get("project.label")
|
|
161
|
+
p.config.keys.set("project.label", "Demo")
|
|
162
|
+
p.config.keys.update({"project.description": "Sample"})
|
|
163
|
+
p.config.replace({"project.label": "Demo", "project.description": "Sample"})
|
|
164
|
+
p.config.keys.delete("project.label")
|
|
165
|
+
|
|
166
|
+
# SCM import/export (sur un projet)
|
|
167
|
+
scm_import = project.scm.import_ # ou getattr(project.scm, "import")
|
|
168
|
+
scm_export = project.scm.export
|
|
169
|
+
|
|
170
|
+
# Découverte des plugins
|
|
171
|
+
scm_import.plugins.list()
|
|
172
|
+
scm_export.plugins.list()
|
|
173
|
+
|
|
174
|
+
# Champs d'entrée pour un plugin et setup (plugin_type explicite)
|
|
175
|
+
fields = scm_import.plugins.input_fields("git-import")
|
|
176
|
+
scm_import.config.setup("git-import", {"url": "ssh://git@example.com/repo.git", "dir": "/tmp/repo"})
|
|
177
|
+
|
|
178
|
+
# Activer/désactiver un plugin
|
|
179
|
+
scm_import.config.enable("git-import")
|
|
180
|
+
scm_export.config.disable("custom-export")
|
|
181
|
+
|
|
182
|
+
# Statut/config SCM
|
|
183
|
+
import_status = scm_import.actions.status()
|
|
184
|
+
export_conf = scm_export.config.get()
|
|
185
|
+
|
|
186
|
+
# Actions SCM côté projet (ex: commit/pull/push selon plugin)
|
|
187
|
+
action_fields = scm_export.actions.input_fields("commit")
|
|
188
|
+
scm_export.actions.perform(
|
|
189
|
+
"commit",
|
|
190
|
+
input_values={"message": "Sync jobs"},
|
|
191
|
+
jobs=["job-1"],
|
|
192
|
+
items=["path/job-1.yaml"],
|
|
193
|
+
deleted=["obsolete/path.yaml"],
|
|
194
|
+
)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Jobs
|
|
198
|
+
```python
|
|
199
|
+
# Lister les jobs d’un projet
|
|
200
|
+
jobs = rd.jobs.list(project="demo", groupPath="ops")
|
|
201
|
+
|
|
202
|
+
# Depuis un projet parenté
|
|
203
|
+
project = rd.projects.get("demo")
|
|
204
|
+
jobs = project.jobs.list()
|
|
205
|
+
|
|
206
|
+
# Accès direct à un job
|
|
207
|
+
job = rd.jobs.get("job-id")
|
|
208
|
+
job.delete()
|
|
209
|
+
job.definition(format="yaml")
|
|
210
|
+
job.retry("exec-id", argString="-opt val")
|
|
211
|
+
job.enable_execution()
|
|
212
|
+
job.disable_execution()
|
|
213
|
+
job.enable_schedule()
|
|
214
|
+
job.disable_schedule()
|
|
215
|
+
info = job.info()
|
|
216
|
+
meta = job.meta(meta="name,description")
|
|
217
|
+
tags = job.tags()
|
|
218
|
+
workflow = job.workflow()
|
|
219
|
+
forecast = job.forecast(time="2024-05-01T10:00:00Z", max=5)
|
|
220
|
+
|
|
221
|
+
# Exporter/importer des jobs via le manager (paramètre project ou parent)
|
|
222
|
+
rd.jobs.export(project="demo", format="xml", idlist="id1,id2", groupPath="group")
|
|
223
|
+
rd.jobs.import_jobs(
|
|
224
|
+
project="demo",
|
|
225
|
+
content=open("jobs.xml", "rb").read(),
|
|
226
|
+
fileformat="xml",
|
|
227
|
+
dupeOption="update",
|
|
228
|
+
)
|
|
229
|
+
# Ou via un projet parenté
|
|
230
|
+
project.jobs.export(format="json")
|
|
231
|
+
project.jobs.import_jobs(content=open("jobs.json", "rb").read(), fileformat="json")
|
|
232
|
+
|
|
233
|
+
Note: l'import reste exposé sous le nom `import_jobs(...)` (le mot-clé Python empêche un appel direct à `.import`). Si vous préférez l'alias, utilisez `getattr(rd.jobs, "import")(...)`.
|
|
234
|
+
|
|
235
|
+
# Exécuter et récupérer l'exécution
|
|
236
|
+
execution = job.run(argString="-option value")
|
|
237
|
+
|
|
238
|
+
# Actions bulk
|
|
239
|
+
rd.jobs.bulk.enable_execution(["id1", "id2"])
|
|
240
|
+
rd.jobs.bulk.disable_execution(["id1", "id2"])
|
|
241
|
+
rd.jobs.bulk.delete(["id1", "id2"])
|
|
242
|
+
rd.jobs.bulk.enable_schedule(["id1", "id2"])
|
|
243
|
+
rd.jobs.bulk.disable_schedule(["id1", "id2"])
|
|
244
|
+
|
|
245
|
+
# Upload de fichiers d'option et fichiers uploadés
|
|
246
|
+
job.upload_option_file("csvfile", open("data.csv", "rb").read(), file_name="data.csv")
|
|
247
|
+
job.list_uploaded_files(max=20)
|
|
248
|
+
rd.jobs.get_uploaded_file_info("file-id")
|
|
249
|
+
|
|
250
|
+
# SCM import/export sur un job
|
|
251
|
+
job_scm_export = job.scm.export
|
|
252
|
+
job_scm_import = job.scm.import_ # ou getattr(job.scm, "import")
|
|
253
|
+
|
|
254
|
+
job_scm_export.status()
|
|
255
|
+
job_scm_export.diff()
|
|
256
|
+
job_scm_export.perform("commit", input_values={"message": "Sync job"})
|
|
257
|
+
|
|
258
|
+
job_scm_import.status()
|
|
259
|
+
job_scm_import.input_fields("pull")
|
|
260
|
+
job_scm_import.perform("pull", input_values={"message": "Update from repo"})
|
|
261
|
+
|
|
262
|
+
# Ressources d'un projet
|
|
263
|
+
resources = project.resources.list(format="json", groupPath="ops")
|
|
264
|
+
node = project.resources.get("node1")
|
|
265
|
+
sources = project.sources.list()
|
|
266
|
+
source_details = project.sources.get(1)
|
|
267
|
+
project.sources.list_resources(1, accept="application/json")
|
|
268
|
+
project.sources.update_resources(1, content="{}", content_type="application/json")
|
|
269
|
+
project.acl.list()
|
|
270
|
+
project.acl.get("policy.aclpolicy")
|
|
271
|
+
project.acl.create("policy.aclpolicy", content="...yaml...")
|
|
272
|
+
project.acl.update("policy.aclpolicy", content="...yaml...")
|
|
273
|
+
project.acl.delete("policy.aclpolicy")
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Exécutions
|
|
277
|
+
```python
|
|
278
|
+
# Liste simple ou paginée
|
|
279
|
+
execs = rd.executions.list(project="demo", status="running", max=50, offset=0)
|
|
280
|
+
running = rd.executions.running(project="demo") # ou "*" pour tous
|
|
281
|
+
|
|
282
|
+
# Détails / suppression
|
|
283
|
+
e = rd.executions.get("123")
|
|
284
|
+
rd.executions.delete("123")
|
|
285
|
+
rd.executions.bulk_delete(["123", "124"])
|
|
286
|
+
|
|
287
|
+
# Requête avancée (query)
|
|
288
|
+
advanced = rd.executions.query(
|
|
289
|
+
project="demo",
|
|
290
|
+
statusFilter="failed",
|
|
291
|
+
userFilter="alice",
|
|
292
|
+
jobIdListFilter=["id1", "id2"],
|
|
293
|
+
groupPath="ops",
|
|
294
|
+
max=100,
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
# Méthodes sur Execution
|
|
298
|
+
e.abort(asUser="admin")
|
|
299
|
+
output = e.get_output(offset=0, maxlines=100)
|
|
300
|
+
state = e.get_state()
|
|
301
|
+
is_running = e.is_running()
|
|
302
|
+
e.refresh() # recharge les données
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Tokens
|
|
306
|
+
```python
|
|
307
|
+
tokens = rd.tokens.list()
|
|
308
|
+
user_tokens = rd.tokens.list(user="alice")
|
|
309
|
+
t = rd.tokens.get("tok-1")
|
|
310
|
+
new_token = rd.tokens.create(user="alice", roles=["admin"], duration="90d", name="cli")
|
|
311
|
+
rd.tokens.delete(new_token.id)
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Utilisateurs
|
|
315
|
+
```python
|
|
316
|
+
users = rd.users.list()
|
|
317
|
+
me = rd.users.get_current()
|
|
318
|
+
u = rd.users.get("bob")
|
|
319
|
+
roles = rd.users.current_roles()
|
|
320
|
+
|
|
321
|
+
# Mise à jour via manager ou objet
|
|
322
|
+
u = rd.users.update("bob", firstName="Bob", lastName="Builder", email="bob@example.com")
|
|
323
|
+
u.roles() # via l'objet
|
|
324
|
+
u.update(email="new@example.com") # met à jour et rafraîchit l'objet
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Système
|
|
328
|
+
```python
|
|
329
|
+
system = rd.system
|
|
330
|
+
info = system.info()
|
|
331
|
+
|
|
332
|
+
# Log storage
|
|
333
|
+
system.logstorage.info()
|
|
334
|
+
system.logstorage.incomplete(max=50, offset=0)
|
|
335
|
+
system.logstorage.incomplete_resume()
|
|
336
|
+
|
|
337
|
+
# Mode exécution (sous-manager)
|
|
338
|
+
system.executions.enable()
|
|
339
|
+
system.executions.disable()
|
|
340
|
+
system.executions.status()
|
|
341
|
+
|
|
342
|
+
# ACL
|
|
343
|
+
system.acl.list()
|
|
344
|
+
system.acl.get("policy.aclpolicy")
|
|
345
|
+
system.acl.create("policy.aclpolicy", content="...yaml...")
|
|
346
|
+
system.acl.update("policy.aclpolicy", content="...yaml...")
|
|
347
|
+
system.acl.delete("policy.aclpolicy")
|
|
348
|
+
|
|
349
|
+
# Scheduler takeover (cluster)
|
|
350
|
+
rd.scheduler.takeover(all_servers=True)
|
|
351
|
+
rd.scheduler.takeover(server_uuid="uuid-123", project="demo", job_id="job-1")
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
Métriques
|
|
355
|
+
```python
|
|
356
|
+
metrics = rd.metrics
|
|
357
|
+
metrics.list()
|
|
358
|
+
metrics.data()
|
|
359
|
+
metrics.healthcheck()
|
|
360
|
+
metrics.ping()
|
|
361
|
+
|
|
362
|
+
# Plugins installés
|
|
363
|
+
plugins = rd.plugins.list()
|
|
364
|
+
for plugin in plugins:
|
|
365
|
+
print(plugin.name, plugin.service)
|
|
366
|
+
|
|
367
|
+
# Détail d'un plugin
|
|
368
|
+
first = plugins[0]
|
|
369
|
+
detail = rd.plugins.detail(first.service, first.name)
|
|
370
|
+
|
|
371
|
+
# Webhooks projet et envoi
|
|
372
|
+
project = rd.projects.get("demo")
|
|
373
|
+
wh = project.webhooks
|
|
374
|
+
wh.create(
|
|
375
|
+
project=project.id,
|
|
376
|
+
name="hook1",
|
|
377
|
+
user="admin",
|
|
378
|
+
roles="admin",
|
|
379
|
+
eventPlugin="log-webhook-event",
|
|
380
|
+
config={},
|
|
381
|
+
enabled=True,
|
|
382
|
+
)
|
|
383
|
+
hooks = wh.list()
|
|
384
|
+
first_hook = hooks[0]
|
|
385
|
+
wh.update(first_hook.id, name="hook1-updated")
|
|
386
|
+
rd.webhooks.send(first_hook.authToken, json={"hello": "world"})
|
|
387
|
+
wh.delete(first_hook.id)
|
|
388
|
+
|
|
389
|
+
# Key storage (/storage/keys)
|
|
390
|
+
ks = rd.key_storage
|
|
391
|
+
# Créer un secret (password)
|
|
392
|
+
ks.create("integration/secret1", content="s3cr3t", content_type="application/x-rundeck-data-password")
|
|
393
|
+
resources = ks.list() # liste racine
|
|
394
|
+
meta = ks.get_metadata("integration/secret1")
|
|
395
|
+
ks.delete("integration/secret1")
|
|
396
|
+
|
|
397
|
+
# AdHoc commands/scripts
|
|
398
|
+
project = rd.projects.get("demo")
|
|
399
|
+
exec1 = project.adhoc.run_command("echo 'hello world'")
|
|
400
|
+
exec2 = project.adhoc.run_script("echo 'from script'")
|
|
401
|
+
# exec2.id pour suivre l'exécution
|
|
402
|
+
# Mode stub (sans refresh immédiat) puis refresh manuel
|
|
403
|
+
exec_stub = project.adhoc.run_command("echo stub", refresh=False)
|
|
404
|
+
exec_stub.refresh() # charge l'objet complet
|
|
405
|
+
# Script via multipart (upload)
|
|
406
|
+
exec3 = project.adhoc.run_script(
|
|
407
|
+
script_file=("hello.sh", "echo multipart", "text/plain"),
|
|
408
|
+
refresh=False,
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
# Features système
|
|
412
|
+
features = rd.features.list()
|
|
413
|
+
if features:
|
|
414
|
+
first = features[0]
|
|
415
|
+
status = rd.features.get(first.name)
|
|
416
|
+
print(first.name, status.enabled)
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
Configuration globale `/config`
|
|
420
|
+
```python
|
|
421
|
+
cfg = rd.config_management
|
|
422
|
+
all_configs = cfg.list()
|
|
423
|
+
cfg.save([{"key": "ui.banner", "value": "Hello"}])
|
|
424
|
+
cfg.delete("ui.banner", strata="default")
|
|
425
|
+
cfg.refresh()
|
|
426
|
+
cfg.restart()
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Pagination
|
|
430
|
+
----------
|
|
431
|
+
Les managers héritent de `RundeckObjectManager.iter(...)` (offset/max). Exemple :
|
|
432
|
+
```python
|
|
433
|
+
for job in rd.jobs.iter(project="demo", page_size=100):
|
|
434
|
+
print(job.id)
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Gestion des erreurs
|
|
438
|
+
-------------------
|
|
439
|
+
Les erreurs HTTP passent par `raise_for_status` et lèvent des exceptions dédiées (ex. `RundeckAuthenticationError`, `RundeckNotFoundError`, `RundeckValidationError`, `RundeckConflictError`, `RundeckServerError`). Gérez-les avec un bloc `try/except` autour des appels client.
|
|
440
|
+
|
|
441
|
+
Développement et tests
|
|
442
|
+
----------------------
|
|
443
|
+
- Formatage/Lint : `black src/rundeck tests/`, `ruff check src/rundeck tests/`
|
|
444
|
+
- Typage : `mypy src/rundeck/`
|
|
445
|
+
- Tests : `pytest`
|
|
446
|
+
- Tests d'intégration locaux : `scripts/run-integration.sh` (démarre docker compose à la racine, exporte par défaut `RUNDECK_URL=http://localhost:4440`, `RUNDECK_TOKEN=adminToken`, `RUNDECK_API_VERSION=56`, attend le healthcheck, lance `poetry run pytest -m integration`). Vous pouvez surcharger les variables d'environnement avant l'appel. Ajoutez `KEEP_STACK=1` pour ne pas arrêter l'instance après les tests. Script de teardown dédié : `scripts/stop-integration.sh`.
|
|
447
|
+
|
|
448
|
+
Structure du code
|
|
449
|
+
-----------------
|
|
450
|
+
- `src/rundeck/base.py` : objets/manager génériques, helpers `_build_path`, pagination, CRUD.
|
|
451
|
+
- `src/rundeck/client.py` : client HTTP, méthodes `http_get/post/put/delete/list`.
|
|
452
|
+
- `src/rundeck/v1/objects/` : managers et objets métiers (projects, jobs, executions, system, tokens, users, config_management).
|
|
453
|
+
- Schéma managers/objets : on applique le pattern manager → objet partout où l’API expose une ressource identifiable (jobs, projects, users, tokens, executions, etc.). Pour les endpoints purement globaux ou utilitaires sans ressource (ex. `/system` et ses sous-domaines, `/config`, `/metrics`), on utilise des sous-managers dédiés plutôt que de forcer un objet artificiel.
|
|
454
|
+
|