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.
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/PKG-INFO +170 -130
- python_rundeck-1.0.0/README.md +460 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/pyproject.toml +1 -1
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/base.py +5 -3
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/executions.py +2 -3
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/jobs.py +24 -6
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/key_storage.py +33 -12
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/system.py +6 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/users.py +5 -4
- python_rundeck-0.2.0/README.md +0 -420
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/LICENSE +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/__init__.py +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/client.py +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/config.py +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/const.py +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/exceptions.py +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/py.typed +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/__init__.py +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/__init__.py +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/adhoc.py +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/config_management.py +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/features.py +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/metrics.py +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/plugins.py +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/projects.py +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/scheduler.py +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/scm.py +0 -0
- {python_rundeck-0.2.0 → python_rundeck-1.0.0}/src/rundeck/v1/objects/tokens.py +0 -0
- {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.
|
|
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
|
+

|
|
42
|
+

|
|
43
|
+

|
|
44
|
+

|
|
41
45
|
|
|
42
|
-
|
|
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
|
-
|
|
48
|
+
Contents
|
|
45
49
|
--------
|
|
46
50
|
- Installation
|
|
47
|
-
-
|
|
51
|
+
- Quick start
|
|
48
52
|
- Configuration
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
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
|
-
|
|
61
|
+
Prerequisites: Python 3.11+. Install from PyPI.
|
|
57
62
|
|
|
58
63
|
```bash
|
|
59
|
-
|
|
60
|
-
# ou en editable avec pip
|
|
61
|
-
pip install -e .
|
|
64
|
+
pip install python-rundeck
|
|
62
65
|
```
|
|
63
66
|
|
|
64
|
-
|
|
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
|
-
#
|
|
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
|
-
#
|
|
76
|
+
# List projects
|
|
74
77
|
projects = rd.projects.list()
|
|
75
78
|
for p in projects:
|
|
76
79
|
print(p.name)
|
|
77
80
|
|
|
78
|
-
#
|
|
81
|
+
# Get a project and run a job
|
|
79
82
|
project = rd.projects.get("demo")
|
|
80
83
|
jobs = project.jobs.list()
|
|
81
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
- `url
|
|
91
|
-
- `token
|
|
92
|
-
- `username` / `password
|
|
93
|
-
- `api_version
|
|
94
|
-
- `timeout
|
|
95
|
-
- `ssl_verify
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
- `RUNDECK_URL
|
|
100
|
-
- `RUNDECK_TOKEN
|
|
101
|
-
- `RUNDECK_USERNAME` / `RUNDECK_PASSWORD
|
|
102
|
-
- `RUNDECK_API_VERSION
|
|
103
|
-
- `RUNDECK_TIMEOUT
|
|
104
|
-
- `RUNDECK_SSL_VERIFY
|
|
105
|
-
- `RUNDECK_USER_AGENT
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
- `projects` (`ProjectManager`)
|
|
110
|
-
- `jobs` (`JobManager`)
|
|
111
|
-
- `executions` (`ExecutionManager`)
|
|
112
|
-
- `tokens` (`TokenManager`)
|
|
113
|
-
- `users` (`UserManager`)
|
|
114
|
-
- `metrics` (`MetricsManager`)
|
|
115
|
-
- `plugins` (`PluginManager`)
|
|
116
|
-
- `webhooks` (`WebhookEventManager` + `ProjectWebhookManager`)
|
|
117
|
-
- `key_storage` (`StorageKeyManager`)
|
|
118
|
-
- `adhoc` (`AdhocManager`, via `project.adhoc`)
|
|
119
|
-
- `system` (`SystemManager`)
|
|
120
|
-
- `config_management` (`ConfigManagementManager`)
|
|
121
|
-
- `scm` (via `project.scm`
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
|
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
|
|
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
|
-
#
|
|
175
|
+
# Project export / import (ZIP archive)
|
|
138
176
|
archive = project.archive
|
|
139
|
-
resp = archive.export(export_all=False, export_webhooks=True) #
|
|
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
|
-
#
|
|
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
|
-
#
|
|
155
|
-
project.readme.get_readme() #
|
|
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("
|
|
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
|
|
198
|
+
project.readme.update_motd("Message of the day", content_type="text/plain")
|
|
161
199
|
project.readme.delete_motd()
|
|
162
200
|
|
|
163
|
-
#
|
|
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 (
|
|
172
|
-
scm_import = 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
|
-
#
|
|
213
|
+
# Plugin discovery
|
|
176
214
|
scm_import.plugins.list()
|
|
177
215
|
scm_export.plugins.list()
|
|
178
216
|
|
|
179
|
-
#
|
|
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
|
-
#
|
|
221
|
+
# Enable/disable a plugin
|
|
184
222
|
scm_import.config.enable("git-import")
|
|
185
223
|
scm_export.config.disable("custom-export")
|
|
186
224
|
|
|
187
|
-
#
|
|
225
|
+
# SCM status/config
|
|
188
226
|
import_status = scm_import.actions.status()
|
|
189
227
|
export_conf = scm_export.config.get()
|
|
190
228
|
|
|
191
|
-
#
|
|
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
|
-
#
|
|
242
|
+
# List jobs for a project
|
|
205
243
|
jobs = rd.jobs.list(project="demo", groupPath="ops")
|
|
206
244
|
|
|
207
|
-
#
|
|
245
|
+
# From a parent project
|
|
208
246
|
project = rd.projects.get("demo")
|
|
209
247
|
jobs = project.jobs.list()
|
|
210
248
|
|
|
211
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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:
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
|
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
|
|
293
|
+
# SCM import/export on a job
|
|
256
294
|
job_scm_export = job.scm.export
|
|
257
|
-
job_scm_import = 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
|
-
#
|
|
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
|
-
|
|
319
|
+
Executions
|
|
282
320
|
```python
|
|
283
|
-
#
|
|
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") #
|
|
323
|
+
running = rd.executions.running(project="demo") # or "*" for all
|
|
286
324
|
|
|
287
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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() #
|
|
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
|
-
|
|
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
|
-
#
|
|
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
|
|
329
|
-
u.update(email="new@example.com") #
|
|
366
|
+
u.roles() # via the object
|
|
367
|
+
u.update(email="new@example.com") # updates and refreshes the object
|
|
330
368
|
```
|
|
331
369
|
|
|
332
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
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
|
-
#
|
|
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
|
-
#
|
|
410
|
+
# Plugin details
|
|
373
411
|
first = plugins[0]
|
|
374
412
|
detail = rd.plugins.detail(first.service, first.name)
|
|
375
413
|
|
|
376
|
-
#
|
|
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
|
-
#
|
|
434
|
+
# Create a secret (password)
|
|
397
435
|
ks.create("integration/secret1", content="s3cr3t", content_type="application/x-rundeck-data-password")
|
|
398
|
-
resources = ks.list() #
|
|
399
|
-
meta = ks.
|
|
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
|
|
407
|
-
#
|
|
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() #
|
|
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
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
-
|
|
449
|
-
-
|
|
450
|
-
-
|
|
451
|
-
- Tests
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
- `src/rundeck/
|
|
457
|
-
- `src/rundeck/
|
|
458
|
-
-
|
|
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
|
|