osism 0.20250312.0__py3-none-any.whl → 0.20250326.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,40 +1,17 @@
1
1
  # SPDX-License-Identifier: Apache-2.0
2
2
 
3
- import argparse
4
- from glob import glob
5
- from os.path import basename
6
-
7
3
  from cliff.command import Command
8
4
  from loguru import logger
9
5
  from redis import Redis
10
- from tabulate import tabulate
11
6
 
12
7
  from osism import settings
13
- from osism.tasks import conductor, netbox, reconciler, ansible, openstack, handle_task
8
+ from osism.tasks import conductor, netbox, reconciler, openstack, handle_task
14
9
 
15
10
 
16
11
  redis = Redis(host=settings.REDIS_HOST, port=settings.REDIS_PORT, db=settings.REDIS_DB)
17
12
  redis.ping()
18
13
 
19
14
 
20
- class Run(Command):
21
- def get_parser(self, prog_name):
22
- parser = super(Run, self).get_parser(prog_name)
23
- parser.add_argument(
24
- "arguments", nargs=argparse.REMAINDER, help="Other arguments for Ansible"
25
- )
26
- parser.add_argument(
27
- "--no-wait",
28
- default=False,
29
- help="Do not wait until the role has been applied",
30
- action="store_true",
31
- )
32
- return parser
33
-
34
- def take_action(self, parsed_args):
35
- pass
36
-
37
-
38
15
  class Ironic(Command):
39
16
  def get_parser(self, prog_name):
40
17
  parser = super(Ironic, self).get_parser(prog_name)
@@ -77,368 +54,93 @@ class Sync(Command):
77
54
  task.wait(timeout=None, interval=0.5)
78
55
 
79
56
 
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
57
  class Manage(Command):
158
58
  def get_parser(self, prog_name):
159
59
  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
60
  parser.add_argument(
174
61
  "--no-wait",
175
62
  default=False,
176
- help="Do not wait until the changes have been made",
63
+ help="Do not wait until the management of the netbox has been completed",
177
64
  action="store_true",
178
65
  )
179
66
  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",
67
+ "--no-netbox-wait",
248
68
  default=False,
249
- help="Ignore the current transition of a device",
69
+ help="Do not wait for the netbox API to be ready",
250
70
  action="store_true",
251
71
  )
252
72
  parser.add_argument(
253
- "--state", type=str, help="State to use", default=None, required=False
254
- )
255
- parser.add_argument(
256
- "--type",
73
+ "--parallel",
257
74
  type=str,
258
- default="collection",
259
- help="Type of the resource to connection (when not using --collection or --device)",
260
- required=False,
75
+ default=None,
76
+ help="Process up to n files in parallel",
261
77
  )
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
78
  parser.add_argument(
300
- "name",
301
- nargs=1,
79
+ "--limit",
302
80
  type=str,
303
- help="Name of the device to check for unused interfaces",
81
+ default=None,
82
+ help="Limit files by prefix",
304
83
  )
305
84
  parser.add_argument(
306
- "--no-wait",
85
+ "--skipdtl",
307
86
  default=False,
308
- help="Do not wait until the changes have been made",
87
+ help="Skip devicetype library",
309
88
  action="store_true",
310
89
  )
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
- 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
90
  parser.add_argument(
334
- "--no-wait",
91
+ "--skipmtl",
335
92
  default=False,
336
- help="Do not wait until the changes have been made",
93
+ help="Skip moduletype library",
337
94
  action="store_true",
338
95
  )
339
96
  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",
97
+ "--skipres",
370
98
  default=False,
371
- help="Do not wait until the changes have been made",
99
+ help="Skip resources",
372
100
  action="store_true",
373
101
  )
374
102
  return parser
375
103
 
376
104
  def take_action(self, parsed_args):
377
- name = parsed_args.name[0]
378
- # arguments = parsed_args.arguments
379
105
  wait = not parsed_args.no_wait
106
+ arguments = []
380
107
 
381
- task = netbox.deploy.delay(name)
108
+ if parsed_args.no_netbox_wait:
109
+ arguments.append("--no-wait")
110
+ else:
111
+ arguments.append("--wait")
382
112
 
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)
113
+ if parsed_args.parallel:
114
+ arguments.append("--parallel")
115
+ arguments.append(parsed_args.parallel)
386
116
 
117
+ if parsed_args.limit:
118
+ arguments.append("--limit")
119
+ arguments.append(parsed_args.limit)
387
120
 
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
121
+ if parsed_args.skipdtl:
122
+ arguments.append("--skipdtl")
123
+ else:
124
+ arguments.append("--no-skipdtl")
404
125
 
405
- def take_action(self, parsed_args):
406
- name = parsed_args.name[0]
407
- wait = not parsed_args.no_wait
126
+ if parsed_args.skipmtl:
127
+ arguments.append("--skipmtl")
128
+ else:
129
+ arguments.append("--no-skipmtl")
408
130
 
409
- task = netbox.check.delay(name)
131
+ if parsed_args.skipres:
132
+ arguments.append("--skipres")
133
+ else:
134
+ arguments.append("--no-skipres")
410
135
 
136
+ task_signature = netbox.manage.si(*arguments)
137
+ task = task_signature.apply_async()
411
138
  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)
139
+ logger.info(
140
+ f"It takes a moment until task {task.task_id} (netbox-manager) has been started and output is visible here."
141
+ )
438
142
 
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)
143
+ return handle_task(task, wait, format="script", timeout=3600)
442
144
 
443
145
 
444
146
  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
 
osism/tasks/ansible.py CHANGED
@@ -1,25 +1,10 @@
1
1
  # SPDX-License-Identifier: Apache-2.0
2
2
 
3
- import functools
4
- from threading import RLock
5
-
6
3
  from celery import Celery
7
- import kombu.utils
8
4
 
9
5
  from osism import settings
10
6
  from osism.tasks import Config, run_ansible_in_environment
11
7
 
12
- # https://github.com/celery/kombu/issues/1804
13
- if not getattr(kombu.utils.cached_property, "lock", None):
14
- setattr(
15
- kombu.utils.cached_property,
16
- "lock",
17
- functools.cached_property(lambda _: RLock()),
18
- )
19
- # Must call __set_name__ here since this cached property is not defined in the context of a class
20
- # Refer to https://docs.python.org/3/reference/datamodel.html#object.__set_name__
21
- kombu.utils.cached_property.lock.__set_name__(kombu.utils.cached_property, "lock")
22
-
23
8
  app = Celery("ansible")
24
9
  app.config_from_object(Config)
25
10