python-rundeck 0.2.0__tar.gz → 1.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 (29) hide show
  1. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/PKG-INFO +170 -130
  2. python_rundeck-1.0.0/README.md +460 -0
  3. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/pyproject.toml +1 -1
  4. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/base.py +5 -3
  5. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/executions.py +2 -3
  6. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/jobs.py +24 -6
  7. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/key_storage.py +33 -12
  8. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/system.py +6 -0
  9. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/users.py +5 -4
  10. python_rundeck-0.2.0/README.md +0 -420
  11. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/LICENSE +0 -0
  12. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/__init__.py +0 -0
  13. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/client.py +0 -0
  14. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/config.py +0 -0
  15. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/const.py +0 -0
  16. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/exceptions.py +0 -0
  17. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/py.typed +0 -0
  18. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/__init__.py +0 -0
  19. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/__init__.py +0 -0
  20. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/adhoc.py +0 -0
  21. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/config_management.py +0 -0
  22. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/features.py +0 -0
  23. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/metrics.py +0 -0
  24. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/plugins.py +0 -0
  25. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/projects.py +0 -0
  26. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/scheduler.py +0 -0
  27. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/scm.py +0 -0
  28. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/tokens.py +0 -0
  29. {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/webhooks.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-rundeck
3
- Version: 0.2.0
3
+ Version: 1.0.0
4
4
  Summary: Python client for the Rundeck API (v14-v56).
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -38,110 +38,148 @@ Description-Content-Type: text/markdown
38
38
 
39
39
  python-rundeck
40
40
  ===============
41
+ ![PyPI Version](https://img.shields.io/pypi/v/python-rundeck)
42
+ ![Python Versions](https://img.shields.io/pypi/pyversions/python-rundeck)
43
+ ![License](https://img.shields.io/pypi/l/python-rundeck)
44
+ ![Downloads](https://static.pepy.tech/badge/python-rundeck)
41
45
 
42
- Client Python pour l’API Rundeck (v14v56), 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).
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).
43
47
 
44
- Sommaire
48
+ Contents
45
49
  --------
46
50
  - Installation
47
- - Démarrage rapide
51
+ - Quick start
48
52
  - Configuration
49
- - Ressources disponibles
50
- - Exemples par ressource
51
- - Gestion des erreurs
52
- - Développement et tests
53
+ - Available resources
54
+ - Return types policy
55
+ - Examples by resource
56
+ - Error handling
57
+ - Development and testing
53
58
 
54
59
  Installation
55
60
  ------------
56
- Prerequis : Python 3.11+. Le projet utilise Poetry.
61
+ Prerequisites: Python 3.11+. Install from PyPI.
57
62
 
58
63
  ```bash
59
- poetry install
60
- # ou en editable avec pip
61
- pip install -e .
64
+ pip install python-rundeck
62
65
  ```
63
66
 
64
- Démarrage rapide
65
- ----------------
67
+ Quick start
68
+ -----------
66
69
  ```python
67
70
  from rundeck.client import Rundeck
68
71
 
69
72
  rd = Rundeck(url="https://rundeck.example.com", token="MY_TOKEN", api_version=56)
70
- # Auth par mot de passe (session cookie) si pas de token
73
+ # Password auth (session cookie) if no token
71
74
  rd = Rundeck(url="https://rundeck.example.com", username="admin", password="admin", api_version=56)
72
75
 
73
- # Lister les projets
76
+ # List projects
74
77
  projects = rd.projects.list()
75
78
  for p in projects:
76
79
  print(p.name)
77
80
 
78
- # Récupérer un projet et lancer un job
81
+ # Get a project and run a job
79
82
  project = rd.projects.get("demo")
80
83
  jobs = project.jobs.list()
81
- execu = jobs[0].run()
84
+ # Use as_execution=True to receive an Execution object.
85
+ execu = jobs[0].run(as_execution=True)
82
86
  print(execu.id)
83
87
  ```
84
88
 
85
89
  Configuration
86
90
  -------------
87
- La configuration suit un modèle en cascade (args > env > fichiers > défauts) via `RundeckConfig`.
88
-
89
- Paramètres principaux :
90
- - `url` : URL Rundeck (ex. `https://rundeck.example.com`)
91
- - `token` : Token API (en-tête `X-Rundeck-Auth-Token`)
92
- - `username` / `password` : Authentification par session (j_security_check) si aucun token n'est fourni.
93
- - `api_version` : Version d’API (ex. `56`)
94
- - `timeout` : Timeout des requêtes (float, secondes)
95
- - `ssl_verify` : Vérification TLS (bool ou chemin CA)
96
-
97
- Fichiers de config : si besoin, passez `config_files` ou `Rundeck.from_config(config_section=...)`.
98
- Variables d'env utiles (config client) :
99
- - `RUNDECK_URL` : URL de base
100
- - `RUNDECK_TOKEN` : token API (en-tête `X-Rundeck-Auth-Token`)
101
- - `RUNDECK_USERNAME` / `RUNDECK_PASSWORD` : auth session (si pas de token)
102
- - `RUNDECK_API_VERSION` : version d'API (ex: 56)
103
- - `RUNDECK_TIMEOUT` : timeout des requêtes (secondes)
104
- - `RUNDECK_SSL_VERIFY` : vérification TLS (bool ou chemin CA)
105
- - `RUNDECK_USER_AGENT` : User-Agent HTTP
106
-
107
- Ressources disponibles
108
- ----------------------
109
- - `projects` (`ProjectManager`) : CRUD projets, export/import de jobs, config projet, archive (export/import).
110
- - `jobs` (`JobManager`) : liste, get, suppressions, actions bulk, exécution.
111
- - `executions` (`ExecutionManager`) : liste/filtre, running, get/delete, query avancée.
112
- - `tokens` (`TokenManager`) : liste, get, create, delete.
113
- - `users` (`UserManager`) : opérations utilisateurs (selon implémentation courante).
114
- - `metrics` (`MetricsManager`) : endpoints `/metrics` (list/data/healthcheck/ping).
115
- - `plugins` (`PluginManager`) : liste des plugins installés (`/plugin/list`).
116
- - `webhooks` (`WebhookEventManager` + `ProjectWebhookManager`) : gestion des webhooks projet et envoi via token.
117
- - `key_storage` (`StorageKeyManager`) : gestion du stockage des clés `/storage/keys`.
118
- - `adhoc` (`AdhocManager`, via `project.adhoc`) : exécution de commandes/scripts AdHoc.
119
- - `system` (`SystemManager`) : info système, exécutions enable/disable, logstorage, ACL.
120
- - `config_management` (`ConfigManagementManager`) : configuration globale `/config`.
121
- - `scm` (via `project.scm` et `job.scm`) : plugins import/export, setup, enable/disable, statut, actions (commit/import/export...).
122
-
123
- Exemples par ressource (complets)
124
- ---------------------------------
125
- Projets
91
+ Configuration follows a cascading model (args > env > files > defaults) via `RundeckConfig`.
92
+
93
+ Main parameters:
94
+ - `url`: Rundeck URL (e.g. `https://rundeck.example.com`)
95
+ - `token`: API token (header `X-Rundeck-Auth-Token`)
96
+ - `username` / `password`: Session authentication (j_security_check) if no token is provided.
97
+ - `api_version`: API version (e.g. `56`)
98
+ - `timeout`: Request timeout (float, seconds)
99
+ - `ssl_verify`: TLS verification (bool or CA path)
100
+
101
+ Config files: if needed, pass `config_files` or `Rundeck.from_config(config_section=...)`.
102
+ Useful env vars (client config):
103
+ - `RUNDECK_URL`: Base URL
104
+ - `RUNDECK_TOKEN`: API token (header `X-Rundeck-Auth-Token`)
105
+ - `RUNDECK_USERNAME` / `RUNDECK_PASSWORD`: Session auth (if no token)
106
+ - `RUNDECK_API_VERSION`: API version (e.g. 56)
107
+ - `RUNDECK_TIMEOUT`: Request timeout (seconds)
108
+ - `RUNDECK_SSL_VERIFY`: TLS verification (bool or CA path)
109
+ - `RUNDECK_USER_AGENT`: HTTP User-Agent
110
+
111
+ Available resources
112
+ -------------------
113
+ - `projects` (`ProjectManager`): CRUD projects, job export/import, project config, archive (export/import).
114
+ - `jobs` (`JobManager`): list, get, deletions, bulk actions, execution.
115
+ - `executions` (`ExecutionManager`): list/filter, running, get/delete, advanced query.
116
+ - `tokens` (`TokenManager`): list, get, create, delete.
117
+ - `users` (`UserManager`): user operations (per current implementation).
118
+ - `metrics` (`MetricsManager`): `/metrics` endpoints (list/data/healthcheck/ping).
119
+ - `plugins` (`PluginManager`): list installed plugins (`/plugin/list`).
120
+ - `webhooks` (`WebhookEventManager` + `ProjectWebhookManager`): project webhook management and sending via token.
121
+ - `key_storage` (`StorageKeyManager`): key storage management `/storage/keys`.
122
+ - `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`.
125
+ - `scm` (via `project.scm` and `job.scm`): import/export plugins, setup, enable/disable, status, actions (commit/import/export...).
126
+
127
+ Return types policy
128
+ -------------------
129
+ - Resource managers use `list/get/create/update` to return objects (`RundeckObject`).
130
+ - Factory managers return the created resource object for actions that create it
131
+ (e.g., `project.adhoc` returns `Execution`).
132
+ - Utility managers return raw API responses (dict/str/bytes).
133
+ - `delete(...)` returns `None`.
134
+ - Object methods return raw API responses and update the object in place when needed.
135
+ - Explicit flags are used when an object return is requested (e.g., `as_execution=True`).
136
+
137
+ Resource managers:
138
+ - `projects`, `jobs`, `executions`, `tokens`, `users`, `plugins`, `features`, `key_storage`, `system.acl`, `project.webhooks`.
139
+
140
+ Factory managers:
141
+ - `adhoc` (via `project.adhoc`).
142
+ Returns `Execution` objects (execution factory).
143
+
144
+ Utility managers:
145
+ - `system`, `config_management`, `metrics`, `scheduler`, `webhooks` (event send).
146
+ - `scm` (via `project.scm` and `job.scm`), and project sub-managers like
147
+ `project.config`, `project.resources`, `project.sources`, `project.readme`,
148
+ `project.archive`, `project.acl`.
149
+
150
+ Note: `project.webhooks.create(...)` returns the raw API response (e.g., `{"msg": "Saved webhook"}`)
151
+ because the Rundeck API does not return the created webhook object.
152
+
153
+ Example:
154
+ ```python
155
+ job = rd.jobs.get("job-id") # -> Job (object)
156
+ resp = job.run() # -> dict (raw API response)
157
+ execu = job.run(as_execution=True) # -> Execution (object)
158
+ execution.refresh() # updates in place, returns None
159
+ ```
160
+
161
+ Examples by resource (complete)
162
+ -------------------------------
163
+ Projects
126
164
  ```python
127
- # CRUD projet
165
+ # CRUD project
128
166
  p = rd.projects.create("demo")
129
167
  p = rd.projects.get("demo")
130
168
  rd.projects.delete("demo")
131
169
  projects = rd.projects.list()
132
170
 
133
- # Export / import de jobs d'un projet (via le manager de jobs)
171
+ # Export / import jobs from a project (via job manager)
134
172
  project.jobs.export(format="json", idlist="id1,id2", groupPath="group/sub")
135
173
  project.jobs.import_jobs(content=open("jobs.json").read(), format="json", dupeOption="update", uuidOption="remove")
136
174
 
137
- # Export / import du projet (archive ZIP)
175
+ # Project export / import (ZIP archive)
138
176
  archive = project.archive
139
- resp = archive.export(export_all=False, export_webhooks=True) # Response brute (zip)
177
+ resp = archive.export(export_all=False, export_webhooks=True) # Raw response (zip)
140
178
  token_info = archive.export_async(exportAll=True)
141
179
  status = archive.export_status(token_info.get("token", ""))
142
180
  zip_resp = archive.export_download(token_info.get("token", ""))
143
181
 
144
- # Import d'archive (synchrone ou async)
182
+ # Archive import (sync or async)
145
183
  archive.import_archive(
146
184
  content=open("project-export.zip", "rb").read(),
147
185
  jobUuidOption="preserve",
@@ -151,16 +189,16 @@ archive.import_archive(
151
189
  archive.import_archive(content=open("project-export.zip", "rb").read(), async_import=True)
152
190
  archive.import_status()
153
191
 
154
- # Readme / MOTD du projet
155
- project.readme.get_readme() # texte par défaut
192
+ # Project README / MOTD
193
+ project.readme.get_readme() # default text
156
194
  project.readme.get_readme(accept="application/json")
157
- project.readme.update_readme("Nouveau contenu", content_type="text/plain")
195
+ project.readme.update_readme("New content", content_type="text/plain")
158
196
  project.readme.delete_readme()
159
197
  project.readme.get_motd()
160
- project.readme.update_motd("Message du jour", content_type="text/plain")
198
+ project.readme.update_motd("Message of the day", content_type="text/plain")
161
199
  project.readme.delete_motd()
162
200
 
163
- # Config projet (clé/valeur)
201
+ # Project config (key/value)
164
202
  conf = p.config.get()
165
203
  p.config.keys.get("project.label")
166
204
  p.config.keys.set("project.label", "Demo")
@@ -168,27 +206,27 @@ p.config.keys.update({"project.description": "Sample"})
168
206
  p.config.replace({"project.label": "Demo", "project.description": "Sample"})
169
207
  p.config.keys.delete("project.label")
170
208
 
171
- # SCM import/export (sur un projet)
172
- scm_import = project.scm.import_ # ou getattr(project.scm, "import")
209
+ # SCM import/export (on a project)
210
+ scm_import = project.scm.import_ # or getattr(project.scm, "import")
173
211
  scm_export = project.scm.export
174
212
 
175
- # Découverte des plugins
213
+ # Plugin discovery
176
214
  scm_import.plugins.list()
177
215
  scm_export.plugins.list()
178
216
 
179
- # Champs d'entrée pour un plugin et setup (plugin_type explicite)
217
+ # Input fields for a plugin and setup (explicit plugin_type)
180
218
  fields = scm_import.plugins.input_fields("git-import")
181
219
  scm_import.config.setup("git-import", {"url": "ssh://git@example.com/repo.git", "dir": "/tmp/repo"})
182
220
 
183
- # Activer/désactiver un plugin
221
+ # Enable/disable a plugin
184
222
  scm_import.config.enable("git-import")
185
223
  scm_export.config.disable("custom-export")
186
224
 
187
- # Statut/config SCM
225
+ # SCM status/config
188
226
  import_status = scm_import.actions.status()
189
227
  export_conf = scm_export.config.get()
190
228
 
191
- # Actions SCM côté projet (ex: commit/pull/push selon plugin)
229
+ # Project-side SCM actions (e.g., commit/pull/push depending on plugin)
192
230
  action_fields = scm_export.actions.input_fields("commit")
193
231
  scm_export.actions.perform(
194
232
  "commit",
@@ -201,14 +239,14 @@ scm_export.actions.perform(
201
239
 
202
240
  Jobs
203
241
  ```python
204
- # Lister les jobs d’un projet
242
+ # List jobs for a project
205
243
  jobs = rd.jobs.list(project="demo", groupPath="ops")
206
244
 
207
- # Depuis un projet parenté
245
+ # From a parent project
208
246
  project = rd.projects.get("demo")
209
247
  jobs = project.jobs.list()
210
248
 
211
- # Accès direct à un job
249
+ # Direct access to a job
212
250
  job = rd.jobs.get("job-id")
213
251
  job.delete()
214
252
  job.definition(format="yaml")
@@ -223,7 +261,7 @@ tags = job.tags()
223
261
  workflow = job.workflow()
224
262
  forecast = job.forecast(time="2024-05-01T10:00:00Z", max=5)
225
263
 
226
- # Exporter/importer des jobs via le manager (paramètre project ou parent)
264
+ # Export/import jobs via manager (project parameter or parent)
227
265
  rd.jobs.export(project="demo", format="xml", idlist="id1,id2", groupPath="group")
228
266
  rd.jobs.import_jobs(
229
267
  project="demo",
@@ -231,30 +269,30 @@ rd.jobs.import_jobs(
231
269
  fileformat="xml",
232
270
  dupeOption="update",
233
271
  )
234
- # Ou via un projet parenté
272
+ # Or via a parent project
235
273
  project.jobs.export(format="json")
236
274
  project.jobs.import_jobs(content=open("jobs.json", "rb").read(), fileformat="json")
237
275
 
238
- 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")(...)`.
276
+ Note: import remains exposed as `import_jobs(...)` (the Python keyword prevents a direct call to `.import`). If you prefer the alias, use `getattr(rd.jobs, "import")(...)`.
239
277
 
240
- # Exécuter et récupérer l'exécution
241
- execution = job.run(argString="-option value")
278
+ # Run and get the execution
279
+ execution = job.run(as_execution=True, argString="-option value")
242
280
 
243
- # Actions bulk
281
+ # Bulk actions
244
282
  rd.jobs.bulk.enable_execution(["id1", "id2"])
245
283
  rd.jobs.bulk.disable_execution(["id1", "id2"])
246
284
  rd.jobs.bulk.delete(["id1", "id2"])
247
285
  rd.jobs.bulk.enable_schedule(["id1", "id2"])
248
286
  rd.jobs.bulk.disable_schedule(["id1", "id2"])
249
287
 
250
- # Upload de fichiers d'option et fichiers uploadés
288
+ # Upload option files and uploaded files
251
289
  job.upload_option_file("csvfile", open("data.csv", "rb").read(), file_name="data.csv")
252
290
  job.list_uploaded_files(max=20)
253
291
  rd.jobs.get_uploaded_file_info("file-id")
254
292
 
255
- # SCM import/export sur un job
293
+ # SCM import/export on a job
256
294
  job_scm_export = job.scm.export
257
- job_scm_import = job.scm.import_ # ou getattr(job.scm, "import")
295
+ job_scm_import = job.scm.import_ # or getattr(job.scm, "import")
258
296
 
259
297
  job_scm_export.status()
260
298
  job_scm_export.diff()
@@ -264,7 +302,7 @@ job_scm_import.status()
264
302
  job_scm_import.input_fields("pull")
265
303
  job_scm_import.perform("pull", input_values={"message": "Update from repo"})
266
304
 
267
- # Ressources d'un projet
305
+ # Project resources
268
306
  resources = project.resources.list(format="json", groupPath="ops")
269
307
  node = project.resources.get("node1")
270
308
  sources = project.sources.list()
@@ -278,18 +316,18 @@ project.acl.update("policy.aclpolicy", content="...yaml...")
278
316
  project.acl.delete("policy.aclpolicy")
279
317
  ```
280
318
 
281
- Exécutions
319
+ Executions
282
320
  ```python
283
- # Liste simple ou paginée
321
+ # Simple or paginated list
284
322
  execs = rd.executions.list(project="demo", status="running", max=50, offset=0)
285
- running = rd.executions.running(project="demo") # ou "*" pour tous
323
+ running = rd.executions.running(project="demo") # or "*" for all
286
324
 
287
- # Détails / suppression
325
+ # Details / deletion
288
326
  e = rd.executions.get("123")
289
327
  rd.executions.delete("123")
290
328
  rd.executions.bulk_delete(["123", "124"])
291
329
 
292
- # Requête avancée (query)
330
+ # Advanced query
293
331
  advanced = rd.executions.query(
294
332
  project="demo",
295
333
  statusFilter="failed",
@@ -299,12 +337,12 @@ advanced = rd.executions.query(
299
337
  max=100,
300
338
  )
301
339
 
302
- # Méthodes sur Execution
340
+ # Execution methods
303
341
  e.abort(asUser="admin")
304
342
  output = e.get_output(offset=0, maxlines=100)
305
343
  state = e.get_state()
306
344
  is_running = e.is_running()
307
- e.refresh() # recharge les données
345
+ e.refresh() # reload data
308
346
  ```
309
347
 
310
348
  Tokens
@@ -316,20 +354,20 @@ new_token = rd.tokens.create(user="alice", roles=["admin"], duration="90d", name
316
354
  rd.tokens.delete(new_token.id)
317
355
  ```
318
356
 
319
- Utilisateurs
357
+ Users
320
358
  ```python
321
359
  users = rd.users.list()
322
360
  me = rd.users.get_current()
323
361
  u = rd.users.get("bob")
324
362
  roles = rd.users.current_roles()
325
363
 
326
- # Mise à jour via manager ou objet
364
+ # Update via manager or object
327
365
  u = rd.users.update("bob", firstName="Bob", lastName="Builder", email="bob@example.com")
328
- u.roles() # via l'objet
329
- u.update(email="new@example.com") # met à jour et rafraîchit l'objet
366
+ u.roles() # via the object
367
+ u.update(email="new@example.com") # updates and refreshes the object
330
368
  ```
331
369
 
332
- Système
370
+ System
333
371
  ```python
334
372
  system = rd.system
335
373
  info = system.info()
@@ -339,7 +377,7 @@ system.logstorage.info()
339
377
  system.logstorage.incomplete(max=50, offset=0)
340
378
  system.logstorage.incomplete_resume()
341
379
 
342
- # Mode exécution (sous-manager)
380
+ # Execution mode (sub-manager)
343
381
  system.executions.enable()
344
382
  system.executions.disable()
345
383
  system.executions.status()
@@ -356,7 +394,7 @@ rd.scheduler.takeover(all_servers=True)
356
394
  rd.scheduler.takeover(server_uuid="uuid-123", project="demo", job_id="job-1")
357
395
  ```
358
396
 
359
- Métriques
397
+ Metrics
360
398
  ```python
361
399
  metrics = rd.metrics
362
400
  metrics.list()
@@ -364,16 +402,16 @@ metrics.data()
364
402
  metrics.healthcheck()
365
403
  metrics.ping()
366
404
 
367
- # Plugins installés
405
+ # Installed plugins
368
406
  plugins = rd.plugins.list()
369
407
  for plugin in plugins:
370
408
  print(plugin.name, plugin.service)
371
409
 
372
- # Détail d'un plugin
410
+ # Plugin details
373
411
  first = plugins[0]
374
412
  detail = rd.plugins.detail(first.service, first.name)
375
413
 
376
- # Webhooks projet et envoi
414
+ # Project webhooks and send
377
415
  project = rd.projects.get("demo")
378
416
  wh = project.webhooks
379
417
  wh.create(
@@ -393,27 +431,28 @@ wh.delete(first_hook.id)
393
431
 
394
432
  # Key storage (/storage/keys)
395
433
  ks = rd.key_storage
396
- # Créer un secret (password)
434
+ # Create a secret (password)
397
435
  ks.create("integration/secret1", content="s3cr3t", content_type="application/x-rundeck-data-password")
398
- resources = ks.list() # liste racine
399
- meta = ks.get_metadata("integration/secret1")
436
+ resources = ks.list() # root listing
437
+ meta = ks.get("integration/secret1")
438
+ content = meta.content() # raw bytes
400
439
  ks.delete("integration/secret1")
401
440
 
402
441
  # AdHoc commands/scripts
403
442
  project = rd.projects.get("demo")
404
443
  exec1 = project.adhoc.run_command("echo 'hello world'")
405
444
  exec2 = project.adhoc.run_script("echo 'from script'")
406
- # exec2.id pour suivre l'exécution
407
- # Mode stub (sans refresh immédiat) puis refresh manuel
445
+ # exec2.id to track execution
446
+ # Stub mode (no immediate refresh) then manual refresh
408
447
  exec_stub = project.adhoc.run_command("echo stub", refresh=False)
409
- exec_stub.refresh() # charge l'objet complet
448
+ exec_stub.refresh() # load the full object
410
449
  # Script via multipart (upload)
411
450
  exec3 = project.adhoc.run_script(
412
451
  script_file=("hello.sh", "echo multipart", "text/plain"),
413
452
  refresh=False,
414
453
  )
415
454
 
416
- # Features système
455
+ # System features
417
456
  features = rd.features.list()
418
457
  if features:
419
458
  first = features[0]
@@ -421,7 +460,7 @@ if features:
421
460
  print(first.name, status.enabled)
422
461
  ```
423
462
 
424
- Configuration globale `/config`
463
+ Global configuration `/config`
425
464
  ```python
426
465
  cfg = rd.config_management
427
466
  all_configs = cfg.list()
@@ -433,27 +472,28 @@ cfg.restart()
433
472
 
434
473
  Pagination
435
474
  ----------
436
- Les managers héritent de `RundeckObjectManager.iter(...)` (offset/max). Exemple :
475
+ Managers inherit `RundeckObjectManager.iter(...)` (offset/max). Example:
437
476
  ```python
438
477
  for job in rd.jobs.iter(project="demo", page_size=100):
439
478
  print(job.id)
440
479
  ```
441
480
 
442
- Gestion des erreurs
443
- -------------------
444
- 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.
445
-
446
- Développement et tests
447
- ----------------------
448
- - Formatage/Lint : `black src/rundeck tests/`, `ruff check src/rundeck tests/`
449
- - Typage : `mypy src/rundeck/`
450
- - Tests : `pytest`
451
- - 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`.
452
-
453
- Structure du code
454
- -----------------
455
- - `src/rundeck/base.py` : objets/manager génériques, helpers `_build_path`, pagination, CRUD.
456
- - `src/rundeck/client.py` : client HTTP, méthodes `http_get/post/put/delete/list`.
457
- - `src/rundeck/v1/objects/` : managers et objets métiers (projects, jobs, executions, system, tokens, users, config_management).
458
- - 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.
481
+ Error handling
482
+ --------------
483
+ HTTP errors go through `raise_for_status` and raise dedicated exceptions (e.g., `RundeckAuthenticationError`, `RundeckNotFoundError`, `RundeckValidationError`, `RundeckConflictError`, `RundeckServerError`). Handle them with a `try/except` block around client calls.
484
+
485
+ Development and testing
486
+ -----------------------
487
+ - Development setup (contributors): clone the repo and run `poetry install`.
488
+ - Formatting/Lint: `black src/rundeck tests/`, `ruff check src/rundeck tests/`
489
+ - Typing: `mypy src/rundeck/`
490
+ - 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`.
492
+
493
+ Code structure
494
+ --------------
495
+ - `src/rundeck/base.py`: generic objects/managers, `_build_path` helpers, pagination, CRUD.
496
+ - `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.
459
499