osism 0.20250219.0__py3-none-any.whl → 0.20250314.0__py3-none-any.whl
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.
- osism/actions/manage_device.py +28 -887
- osism/api.py +18 -0
- osism/commands/netbox.py +38 -327
- osism/services/listener.py +223 -133
- osism/settings.py +2 -3
- osism/tasks/__init__.py +44 -14
- osism/tasks/netbox.py +22 -98
- osism-0.20250314.0.dist-info/AUTHORS +1 -0
- {osism-0.20250219.0.dist-info → osism-0.20250314.0.dist-info}/METADATA +14 -14
- {osism-0.20250219.0.dist-info → osism-0.20250314.0.dist-info}/RECORD +15 -19
- {osism-0.20250219.0.dist-info → osism-0.20250314.0.dist-info}/WHEEL +1 -1
- {osism-0.20250219.0.dist-info → osism-0.20250314.0.dist-info}/entry_points.txt +1 -9
- osism-0.20250314.0.dist-info/pbr.json +1 -0
- osism/actions/check_configuration.py +0 -49
- osism/actions/deploy_configuration.py +0 -92
- osism/actions/diff_configuration.py +0 -59
- osism/actions/generate_configuration.py +0 -137
- osism-0.20250219.0.dist-info/AUTHORS +0 -1
- osism-0.20250219.0.dist-info/pbr.json +0 -1
- {osism-0.20250219.0.dist-info → osism-0.20250314.0.dist-info}/LICENSE +0 -0
- {osism-0.20250219.0.dist-info → osism-0.20250314.0.dist-info}/top_level.txt +0 -0
osism/api.py
CHANGED
@@ -12,6 +12,16 @@ from starlette.middleware.cors import CORSMiddleware
|
|
12
12
|
|
13
13
|
from osism.tasks import reconciler
|
14
14
|
from osism import settings
|
15
|
+
from osism.services.listener import BaremetalEvents
|
16
|
+
|
17
|
+
|
18
|
+
class NotificationBaremetal(BaseModel):
|
19
|
+
priority: str
|
20
|
+
event_type: str
|
21
|
+
timestamp: str
|
22
|
+
publisher_id: str
|
23
|
+
message_id: UUID
|
24
|
+
payload: dict
|
15
25
|
|
16
26
|
|
17
27
|
class WebhookNetboxResponse(BaseModel):
|
@@ -66,6 +76,7 @@ dictConfig(LogConfig().dict())
|
|
66
76
|
logger = logging.getLogger("api")
|
67
77
|
|
68
78
|
nb = None
|
79
|
+
baremetal_events = BaremetalEvents()
|
69
80
|
|
70
81
|
|
71
82
|
@app.on_event("startup")
|
@@ -99,6 +110,13 @@ async def write_sink_events(request: Request):
|
|
99
110
|
data = await request.json()
|
100
111
|
|
101
112
|
|
113
|
+
@app.post("/notifications/baremetal", status_code=204)
|
114
|
+
async def notifications_baremetal(notification: NotificationBaremetal) -> None:
|
115
|
+
|
116
|
+
handler = baremetal_events.get_handler(notification.event_type)
|
117
|
+
handler(notification.payload)
|
118
|
+
|
119
|
+
|
102
120
|
@app.post("/webhook/netbox", response_model=WebhookNetboxResponse, status_code=200)
|
103
121
|
async def webhook(
|
104
122
|
webhook_input: WebhookNetboxData,
|
osism/commands/netbox.py
CHANGED
@@ -1,16 +1,13 @@
|
|
1
1
|
# SPDX-License-Identifier: Apache-2.0
|
2
2
|
|
3
3
|
import argparse
|
4
|
-
from glob import glob
|
5
|
-
from os.path import basename
|
6
4
|
|
7
5
|
from cliff.command import Command
|
8
6
|
from loguru import logger
|
9
7
|
from redis import Redis
|
10
|
-
from tabulate import tabulate
|
11
8
|
|
12
9
|
from osism import settings
|
13
|
-
from osism.tasks import conductor, netbox, reconciler,
|
10
|
+
from osism.tasks import conductor, netbox, reconciler, openstack, handle_task
|
14
11
|
|
15
12
|
|
16
13
|
redis = Redis(host=settings.REDIS_HOST, port=settings.REDIS_PORT, db=settings.REDIS_DB)
|
@@ -77,368 +74,82 @@ class Sync(Command):
|
|
77
74
|
task.wait(timeout=None, interval=0.5)
|
78
75
|
|
79
76
|
|
80
|
-
class Init(Command):
|
81
|
-
def get_parser(self, prog_name):
|
82
|
-
parser = super(Init, self).get_parser(prog_name)
|
83
|
-
parser.add_argument(
|
84
|
-
"arguments", nargs=argparse.REMAINDER, help="Other arguments for Ansible"
|
85
|
-
)
|
86
|
-
parser.add_argument(
|
87
|
-
"--no-wait",
|
88
|
-
default=False,
|
89
|
-
help="Do not wait until the role has been applied",
|
90
|
-
action="store_true",
|
91
|
-
)
|
92
|
-
parser.add_argument(
|
93
|
-
"--format",
|
94
|
-
default="log",
|
95
|
-
help="Output type",
|
96
|
-
const="log",
|
97
|
-
nargs="?",
|
98
|
-
choices=["script", "log"],
|
99
|
-
),
|
100
|
-
return parser
|
101
|
-
|
102
|
-
def take_action(self, parsed_args):
|
103
|
-
arguments = parsed_args.arguments
|
104
|
-
format = parsed_args.format
|
105
|
-
wait = not parsed_args.no_wait
|
106
|
-
|
107
|
-
task = ansible.run.delay("netbox-local", "init", arguments)
|
108
|
-
rc = 0
|
109
|
-
|
110
|
-
if wait:
|
111
|
-
logger.info(f"Task {task.task_id} was prepared for execution.")
|
112
|
-
logger.info(
|
113
|
-
f"It takes a moment until task {task.task_id} has been started and output is visible here."
|
114
|
-
)
|
115
|
-
rc = handle_task(task, wait, format, 300)
|
116
|
-
else:
|
117
|
-
logger.info(
|
118
|
-
f"Task {task.task_id} is running in background. No more output. Check ARA for logs."
|
119
|
-
)
|
120
|
-
|
121
|
-
return rc
|
122
|
-
|
123
|
-
|
124
|
-
class Import(Command):
|
125
|
-
def get_parser(self, prog_name):
|
126
|
-
parser = super(Import, self).get_parser(prog_name)
|
127
|
-
parser.add_argument(
|
128
|
-
"--vendors",
|
129
|
-
help="Vendors from which all available device types are to be imported",
|
130
|
-
required=False,
|
131
|
-
)
|
132
|
-
parser.add_argument(
|
133
|
-
"--library",
|
134
|
-
default=False,
|
135
|
-
help="Do import device types from the device type library",
|
136
|
-
action="store_true",
|
137
|
-
)
|
138
|
-
parser.add_argument(
|
139
|
-
"--no-wait",
|
140
|
-
default=False,
|
141
|
-
help="Do not wait until the role has been applied",
|
142
|
-
action="store_true",
|
143
|
-
)
|
144
|
-
return parser
|
145
|
-
|
146
|
-
def take_action(self, parsed_args):
|
147
|
-
vendors = parsed_args.vendors
|
148
|
-
wait = not parsed_args.no_wait
|
149
|
-
|
150
|
-
task = netbox.import_device_types.delay(vendors, parsed_args.library)
|
151
|
-
|
152
|
-
if wait:
|
153
|
-
logger.info(f"Task {task.task_id} is running. Wait. No more output.")
|
154
|
-
task.wait(timeout=None, interval=0.5)
|
155
|
-
|
156
|
-
|
157
77
|
class Manage(Command):
|
158
78
|
def get_parser(self, prog_name):
|
159
79
|
parser = super(Manage, self).get_parser(prog_name)
|
160
|
-
parser.add_argument(
|
161
|
-
"--type",
|
162
|
-
type=str,
|
163
|
-
help="Type of the resource to manage",
|
164
|
-
required=False,
|
165
|
-
default="rack",
|
166
|
-
)
|
167
|
-
parser.add_argument(
|
168
|
-
"name", nargs="?", type=str, help="Name of the resource to manage"
|
169
|
-
)
|
170
|
-
parser.add_argument(
|
171
|
-
"arguments", nargs=argparse.REMAINDER, help="Other arguments for Ansible"
|
172
|
-
)
|
173
80
|
parser.add_argument(
|
174
81
|
"--no-wait",
|
175
82
|
default=False,
|
176
|
-
help="Do not wait until the
|
83
|
+
help="Do not wait until the management of the netbox has been completed",
|
177
84
|
action="store_true",
|
178
85
|
)
|
179
86
|
parser.add_argument(
|
180
|
-
"--
|
181
|
-
default="log",
|
182
|
-
help="Output type",
|
183
|
-
const="log",
|
184
|
-
nargs="?",
|
185
|
-
choices=["script", "log"],
|
186
|
-
),
|
187
|
-
return parser
|
188
|
-
|
189
|
-
def take_action(self, parsed_args):
|
190
|
-
arguments = parsed_args.arguments
|
191
|
-
format = parsed_args.format
|
192
|
-
name = parsed_args.name
|
193
|
-
type_of_resource = parsed_args.type
|
194
|
-
wait = not parsed_args.no_wait
|
195
|
-
|
196
|
-
rc = 0
|
197
|
-
if not name:
|
198
|
-
logger.info("No name of an object to be managed was given")
|
199
|
-
table = []
|
200
|
-
for playbook_type in ["rack"]:
|
201
|
-
playbooks = glob(
|
202
|
-
f"/opt/configuration/netbox/playbooks/{playbook_type}-*.yml"
|
203
|
-
)
|
204
|
-
for playbook in playbooks:
|
205
|
-
name = basename(playbook)[len(playbook_type) + 1 : -4] # noqa E203
|
206
|
-
table.append([playbook_type, name])
|
207
|
-
|
208
|
-
print(tabulate(table, headers=["Type", "Name"], tablefmt="psql"))
|
209
|
-
else:
|
210
|
-
task = ansible.run.delay(
|
211
|
-
"netbox-local", f"{type_of_resource}-{name}", arguments
|
212
|
-
)
|
213
|
-
|
214
|
-
if wait:
|
215
|
-
logger.info(f"Task {task.task_id} was prepared for execution.")
|
216
|
-
logger.info(
|
217
|
-
f"It takes a moment until task {task.task_id} has been started and output is visible here."
|
218
|
-
)
|
219
|
-
rc = handle_task(task, wait, format, 300)
|
220
|
-
else:
|
221
|
-
logger.info(
|
222
|
-
f"Task {task.task_id} is running in background. No more output. Check ARA for logs."
|
223
|
-
)
|
224
|
-
|
225
|
-
return rc
|
226
|
-
|
227
|
-
|
228
|
-
class Connect(Command):
|
229
|
-
def get_parser(self, prog_name):
|
230
|
-
parser = super(Connect, self).get_parser(prog_name)
|
231
|
-
parser.add_argument(
|
232
|
-
"name",
|
233
|
-
nargs="?",
|
234
|
-
type=str,
|
235
|
-
help="Name of the resource (a collection or a device) to connect",
|
236
|
-
)
|
237
|
-
parser.add_argument(
|
238
|
-
"--collection",
|
239
|
-
type=str,
|
240
|
-
help="Name of the collection to connect",
|
241
|
-
required=False,
|
242
|
-
),
|
243
|
-
parser.add_argument(
|
244
|
-
"--device", type=str, help="Name of the device to connect", required=False
|
245
|
-
)
|
246
|
-
parser.add_argument(
|
247
|
-
"--enforce",
|
87
|
+
"--no-netbox-wait",
|
248
88
|
default=False,
|
249
|
-
help="
|
89
|
+
help="Do not wait for the netbox API to be ready",
|
250
90
|
action="store_true",
|
251
91
|
)
|
252
92
|
parser.add_argument(
|
253
|
-
"--
|
254
|
-
)
|
255
|
-
parser.add_argument(
|
256
|
-
"--type",
|
257
|
-
type=str,
|
258
|
-
default="collection",
|
259
|
-
help="Type of the resource to connection (when not using --collection or --device)",
|
260
|
-
required=False,
|
261
|
-
)
|
262
|
-
return parser
|
263
|
-
|
264
|
-
def take_action(self, parsed_args):
|
265
|
-
name = parsed_args.name
|
266
|
-
collection = parsed_args.device
|
267
|
-
device = parsed_args.device
|
268
|
-
state = parsed_args.state
|
269
|
-
type_of_resource = parsed_args.type
|
270
|
-
enforce = parsed_args.enforce
|
271
|
-
|
272
|
-
task = None
|
273
|
-
|
274
|
-
if name:
|
275
|
-
if type_of_resource == "collection":
|
276
|
-
task = netbox.data.delay(name, "", state)
|
277
|
-
elif type_of_resource == "device":
|
278
|
-
task = netbox.data.delay("", name, state)
|
279
|
-
else:
|
280
|
-
task = netbox.data.delay(collection, device, state)
|
281
|
-
name = f"{collection}-{device}"
|
282
|
-
|
283
|
-
task.wait(timeout=None, interval=0.5)
|
284
|
-
data = task.get()
|
285
|
-
|
286
|
-
for device in data:
|
287
|
-
t = netbox.connect.delay(device, state, data, enforce)
|
288
|
-
logger.info(
|
289
|
-
f"Task {t.task_id} for device {device} is running in background"
|
290
|
-
)
|
291
|
-
logger.info(
|
292
|
-
"Tasks are running in background. No more output. Check Flower for logs."
|
293
|
-
)
|
294
|
-
|
295
|
-
|
296
|
-
class Disable(Command):
|
297
|
-
def get_parser(self, prog_name):
|
298
|
-
parser = super(Disable, self).get_parser(prog_name)
|
299
|
-
parser.add_argument(
|
300
|
-
"name",
|
301
|
-
nargs=1,
|
93
|
+
"--limit",
|
302
94
|
type=str,
|
303
|
-
|
95
|
+
default=None,
|
96
|
+
help="Limit files by prefix",
|
304
97
|
)
|
305
98
|
parser.add_argument(
|
306
|
-
"--
|
99
|
+
"--skipdtl",
|
307
100
|
default=False,
|
308
|
-
help="
|
101
|
+
help="Skip devicetype library",
|
309
102
|
action="store_true",
|
310
103
|
)
|
311
|
-
return parser
|
312
|
-
|
313
|
-
def take_action(self, parsed_args):
|
314
|
-
name = parsed_args.name[0]
|
315
|
-
wait = not parsed_args.no_wait
|
316
|
-
|
317
|
-
task = netbox.disable.delay(name)
|
318
|
-
|
319
|
-
if wait:
|
320
|
-
logger.info(f"Task {task.task_id} is running. Wait. No more output.")
|
321
|
-
task.wait(timeout=None, interval=0.5)
|
322
|
-
|
323
|
-
|
324
|
-
class Generate(Command):
|
325
|
-
def get_parser(self, prog_name):
|
326
|
-
parser = super(Generate, self).get_parser(prog_name)
|
327
104
|
parser.add_argument(
|
328
|
-
"
|
329
|
-
nargs=1,
|
330
|
-
type=str,
|
331
|
-
help="Name of the device for which the configuration is to be generated.",
|
332
|
-
)
|
333
|
-
parser.add_argument(
|
334
|
-
"--no-wait",
|
105
|
+
"--skipmtl",
|
335
106
|
default=False,
|
336
|
-
help="
|
107
|
+
help="Skip moduletype library",
|
337
108
|
action="store_true",
|
338
109
|
)
|
339
110
|
parser.add_argument(
|
340
|
-
"--
|
341
|
-
)
|
342
|
-
return parser
|
343
|
-
|
344
|
-
def take_action(self, parsed_args):
|
345
|
-
name = parsed_args.name[0]
|
346
|
-
template = parsed_args.template
|
347
|
-
wait = not parsed_args.no_wait
|
348
|
-
|
349
|
-
task = netbox.generate.delay(name, template)
|
350
|
-
|
351
|
-
if wait:
|
352
|
-
logger.info(f"Task {task.task_id} is running. Wait. No more output.")
|
353
|
-
task.wait(timeout=None, interval=0.5)
|
354
|
-
|
355
|
-
|
356
|
-
class Deploy(Command):
|
357
|
-
def get_parser(self, prog_name):
|
358
|
-
parser = super(Deploy, self).get_parser(prog_name)
|
359
|
-
parser.add_argument(
|
360
|
-
"name",
|
361
|
-
nargs=1,
|
362
|
-
type=str,
|
363
|
-
help="Name of the device for which the configuration is to be deployed",
|
364
|
-
)
|
365
|
-
parser.add_argument(
|
366
|
-
"arguments", nargs=argparse.REMAINDER, help="Other arguments for Ansible"
|
367
|
-
)
|
368
|
-
parser.add_argument(
|
369
|
-
"--no-wait",
|
111
|
+
"--skipres",
|
370
112
|
default=False,
|
371
|
-
help="
|
113
|
+
help="Skip resources",
|
372
114
|
action="store_true",
|
373
115
|
)
|
374
116
|
return parser
|
375
117
|
|
376
118
|
def take_action(self, parsed_args):
|
377
|
-
name = parsed_args.name[0]
|
378
|
-
# arguments = parsed_args.arguments
|
379
119
|
wait = not parsed_args.no_wait
|
120
|
+
arguments = []
|
380
121
|
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
task.wait(timeout=None, interval=0.5)
|
122
|
+
if parsed_args.no_netbox_wait:
|
123
|
+
arguments.append("--no-wait")
|
124
|
+
else:
|
125
|
+
arguments.append("--wait")
|
386
126
|
|
127
|
+
if parsed_args.limit:
|
128
|
+
arguments.append("--limit {parsed_args.limit}")
|
387
129
|
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
"name",
|
393
|
-
nargs=1,
|
394
|
-
type=str,
|
395
|
-
help="Name of the device for which the configuration is to be checked",
|
396
|
-
)
|
397
|
-
parser.add_argument(
|
398
|
-
"--no-wait",
|
399
|
-
default=False,
|
400
|
-
help="Do not wait until the changes have been made",
|
401
|
-
action="store_true",
|
402
|
-
)
|
403
|
-
return parser
|
130
|
+
if parsed_args.skipdtl:
|
131
|
+
arguments.append("--skipdtl")
|
132
|
+
else:
|
133
|
+
arguments.append("--no-skipdtl")
|
404
134
|
|
405
|
-
|
406
|
-
|
407
|
-
|
135
|
+
if parsed_args.skipmtl:
|
136
|
+
arguments.append("--skipmtl")
|
137
|
+
else:
|
138
|
+
arguments.append("--no-skipmtl")
|
408
139
|
|
409
|
-
|
140
|
+
if parsed_args.skipres:
|
141
|
+
arguments.append("--skipres")
|
142
|
+
else:
|
143
|
+
arguments.append("--no-skipres")
|
410
144
|
|
145
|
+
task_signature = netbox.manage.si(*arguments)
|
146
|
+
task = task_signature.apply_async()
|
411
147
|
if wait:
|
412
|
-
logger.info(
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
class Diff(Command):
|
417
|
-
def get_parser(self, prog_name):
|
418
|
-
parser = super(Diff, self).get_parser(prog_name)
|
419
|
-
parser.add_argument(
|
420
|
-
"name",
|
421
|
-
nargs=1,
|
422
|
-
type=str,
|
423
|
-
help="Name of the device for which the configuration is to be diffed",
|
424
|
-
)
|
425
|
-
parser.add_argument(
|
426
|
-
"--no-wait",
|
427
|
-
default=False,
|
428
|
-
help="Do not wait until the changes have been made",
|
429
|
-
action="store_true",
|
430
|
-
)
|
431
|
-
return parser
|
432
|
-
|
433
|
-
def take_action(self, parsed_args):
|
434
|
-
name = parsed_args.name[0]
|
435
|
-
wait = not parsed_args.no_wait
|
436
|
-
|
437
|
-
task = netbox.diff.delay(name)
|
148
|
+
logger.info(
|
149
|
+
f"It takes a moment until task {task.task_id} (netbox-manager) has been started and output is visible here."
|
150
|
+
)
|
438
151
|
|
439
|
-
|
440
|
-
logger.info(f"Task {task.task_id} is running. Wait. No more output.")
|
441
|
-
task.wait(timeout=None, interval=0.5)
|
152
|
+
return handle_task(task, wait, format="script", timeout=3600)
|
442
153
|
|
443
154
|
|
444
155
|
class Ping(Command):
|