osism 0.20250312.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/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, ansible, openstack, handle_task
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 changes have been made",
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
- "--format",
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="Ignore the current transition of a device",
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
- "--state", type=str, help="State to use", default=None, required=False
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
- help="Name of the device to check for unused interfaces",
95
+ default=None,
96
+ help="Limit files by prefix",
304
97
  )
305
98
  parser.add_argument(
306
- "--no-wait",
99
+ "--skipdtl",
307
100
  default=False,
308
- help="Do not wait until the changes have been made",
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
- "name",
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="Do not wait until the changes have been made",
107
+ help="Skip moduletype library",
337
108
  action="store_true",
338
109
  )
339
110
  parser.add_argument(
340
- "--template", type=str, help="Name of the template to use", required=False
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="Do not wait until the changes have been made",
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
- task = netbox.deploy.delay(name)
382
-
383
- if wait:
384
- logger.info(f"Task {task.task_id} is running. Wait. No more output.")
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
- class Check(Command):
389
- def get_parser(self, prog_name):
390
- parser = super(Check, self).get_parser(prog_name)
391
- parser.add_argument(
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
- def take_action(self, parsed_args):
406
- name = parsed_args.name[0]
407
- wait = not parsed_args.no_wait
135
+ if parsed_args.skipmtl:
136
+ arguments.append("--skipmtl")
137
+ else:
138
+ arguments.append("--no-skipmtl")
408
139
 
409
- task = netbox.check.delay(name)
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(f"Task {task.task_id} is running. Wait. No more output.")
413
- task.wait(timeout=None, interval=0.5)
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
- if wait:
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):
@@ -40,7 +40,6 @@ class BaremetalEvents:
40
40
  },
41
41
  "maintenance_set": {"end": self.node_maintenance_set_end},
42
42
  "provision_set": {
43
- "start": self.node_provision_set_start,
44
43
  "end": self.node_provision_set_end,
45
44
  "success": self.node_provision_set_success,
46
45
  },
@@ -97,28 +96,6 @@ class BaremetalEvents:
97
96
  )
98
97
  netbox.set_maintenance.delay(name, object_data["maintenance"])
99
98
 
100
- def node_provision_set_start(self, payload: dict[Any, Any]) -> None:
101
- object_data = self.get_object_data(payload)
102
- name = object_data["name"]
103
- logger.info(
104
- f"baremetal.node.provision_set.start ## {name} ## {object_data['provision_state']}"
105
- )
106
-
107
- if object_data["event"] == "inspect":
108
- # system should be in state a
109
- netbox.connect.delay(name, "a")
110
-
111
- if object_data["provision_state"] == "cleaning":
112
- # system should be in state b
113
- netbox.connect.delay(name, "b")
114
-
115
- if object_data["provision_state"] == "available":
116
- # system should be in state c
117
- netbox.connect.delay(name, "c")
118
-
119
- if object_data["target_provision_state"] == "active":
120
- pass
121
-
122
99
  def node_provision_set_success(self, payload: dict[Any, Any]) -> None:
123
100
  # A provision status was successfully set, update it in the netbox
124
101
  object_data = self.get_object_data(payload)
@@ -128,10 +105,6 @@ class BaremetalEvents:
128
105
  )
129
106
  netbox.set_state.delay(name, object_data["provision_state"], "provision")
130
107
 
131
- if object_data["provision_state"] == "manageable":
132
- # system should be in state c
133
- netbox.connect.delay(name, "c")
134
-
135
108
  def node_provision_set_end(self, payload: dict[Any, Any]) -> None:
136
109
  object_data = self.get_object_data(payload)
137
110
  name = object_data["name"]
@@ -147,16 +120,6 @@ class BaremetalEvents:
147
120
  netbox.set_state.delay(name, "introspected", "introspection")
148
121
  openstack.baremetal_set_node_provision_state.delay(name, "provide")
149
122
 
150
- elif object_data["previous_provision_state"] == "wait call-back":
151
- pass
152
-
153
- elif (
154
- object_data["previous_provision_state"] == "cleaning"
155
- and object_data["provision_state"] == "available"
156
- ): # noqa
157
- # system should be in state c
158
- netbox.connect.delay(name, "c")
159
-
160
123
  def port_create_end(self, payload: dict[Any, Any]) -> None:
161
124
  object_data = self.get_object_data(payload)
162
125
  name = object_data["name"]
@@ -206,9 +169,6 @@ class BaremetalEvents:
206
169
  netbox.set_state.delay(name, None, "introspection")
207
170
  netbox.set_state.delay(name, None, "deployment")
208
171
 
209
- # system should be in state a
210
- netbox.connect.delay(name, "a")
211
-
212
172
  # remove internal flavor
213
173
  openstack.baremetal_delete_internal_flavor.delay(name)
214
174
 
osism/settings.py CHANGED
@@ -27,9 +27,6 @@ NETBOX_URL = os.getenv("NETBOX_API")
27
27
  NETBOX_TOKEN = os.getenv("NETBOX_TOKEN", read_secret("NETBOX_TOKEN"))
28
28
  IGNORE_SSL_ERRORS = os.getenv("IGNORE_SSL_ERRORS", "True") == "True"
29
29
 
30
- BASE_PATH = os.getenv("BASE_PATH", "/devicetype-library/device-types/")
31
- VENDORS = os.getenv("VENDORS", "").split()
32
-
33
30
  # 43200 seconds = 12 hours
34
31
  GATHER_FACTS_SCHEDULE = float(os.getenv("GATHER_FACTS_SCHEDULE", "43200.0"))
35
32
  INVENTORY_RECONCILER_SCHEDULE = float(
osism/tasks/__init__.py CHANGED
@@ -160,20 +160,6 @@ def run_ansible_in_environment(
160
160
  env=env,
161
161
  )
162
162
 
163
- # execute local netbox playbooks
164
- elif worker == "osism-ansible" and environment == "netbox-local":
165
- if locking:
166
- lock.acquire()
167
-
168
- command = f"/run-{environment}.sh {role} {joined_arguments}"
169
- logger.info(f"RUN {command}")
170
- p = subprocess.Popen(
171
- command,
172
- stdout=subprocess.PIPE,
173
- stderr=subprocess.STDOUT,
174
- shell=True,
175
- )
176
-
177
163
  # execute all other roles
178
164
  else:
179
165
  if locking:
@@ -207,6 +193,50 @@ def run_ansible_in_environment(
207
193
  return result
208
194
 
209
195
 
196
+ def run_command(
197
+ request_id,
198
+ command,
199
+ env,
200
+ *arguments,
201
+ publish=True,
202
+ locking=False,
203
+ auto_release_time=3600,
204
+ ):
205
+ result = ""
206
+ command_env = os.environ.copy()
207
+ command_env.update(env)
208
+
209
+ if locking:
210
+ lock = Redlock(
211
+ key=f"lock-{command}",
212
+ masters={redis},
213
+ auto_release_time=auto_release_time,
214
+ )
215
+
216
+ p = subprocess.Popen(
217
+ [command] + list(arguments),
218
+ env=command_env,
219
+ stdout=subprocess.PIPE,
220
+ stderr=subprocess.STDOUT,
221
+ )
222
+ while p.poll() is None:
223
+ line = p.stdout.readline().decode("utf-8")
224
+ if publish:
225
+ redis.xadd(request_id, {"type": "stdout", "content": line})
226
+ result += line
227
+
228
+ rc = p.wait(timeout=60)
229
+
230
+ if publish:
231
+ redis.xadd(request_id, {"type": "rc", "content": rc})
232
+ redis.xadd(request_id, {"type": "action", "content": "quit"})
233
+
234
+ if locking:
235
+ lock.release()
236
+
237
+ return result
238
+
239
+
210
240
  def handle_task(t, wait=True, format="log", timeout=3600):
211
241
  global redis
212
242