osism 0.20250326.0__py3-none-any.whl → 0.20250407.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/api.py CHANGED
@@ -11,7 +11,7 @@ import pynetbox
11
11
  from starlette.middleware.cors import CORSMiddleware
12
12
 
13
13
  from osism.tasks import reconciler
14
- from osism import settings
14
+ from osism import settings, utils
15
15
  from osism.services.listener import BaremetalEvents
16
16
 
17
17
 
@@ -75,16 +75,13 @@ app.add_middleware(CORSMiddleware)
75
75
  dictConfig(LogConfig().dict())
76
76
  logger = logging.getLogger("api")
77
77
 
78
- nb = None
79
78
  baremetal_events = BaremetalEvents()
80
79
 
81
80
 
82
81
  @app.on_event("startup")
83
82
  async def startup_event():
84
- global nb
85
-
86
83
  if settings.NETBOX_URL and settings.NETBOX_TOKEN:
87
- nb = pynetbox.api(settings.NETBOX_URL, token=settings.NETBOX_TOKEN)
84
+ utils.nb = pynetbox.api(settings.NETBOX_URL, token=settings.NETBOX_TOKEN)
88
85
 
89
86
  if settings.IGNORE_SSL_ERRORS:
90
87
  import requests
@@ -92,7 +89,7 @@ async def startup_event():
92
89
  requests.packages.urllib3.disable_warnings()
93
90
  session = requests.Session()
94
91
  session.verify = False
95
- nb.http_session = session
92
+ utils.nb.http_session = session
96
93
 
97
94
 
98
95
  @app.get("/")
@@ -125,9 +122,7 @@ async def webhook(
125
122
  content_length: int = Header(...),
126
123
  x_hook_signature: str = Header(None),
127
124
  ):
128
- global nb
129
-
130
- if nb:
125
+ if utils.nb:
131
126
  data = webhook_input.data
132
127
  url = data["url"]
133
128
  name = data["name"]
@@ -146,7 +141,7 @@ async def webhook(
146
141
  device_type = "interface"
147
142
 
148
143
  device_id = data["device"]["id"]
149
- device = nb.dcim.devices.get(id=device_id)
144
+ device = utils.nb.dcim.devices.get(id=device_id)
150
145
  tags = [str(x) for x in device.tags]
151
146
  custom_fields = device.custom_fields
152
147
 
osism/commands/manage.py CHANGED
@@ -12,7 +12,7 @@ import requests
12
12
  from osism.data import TEMPLATE_IMAGE_CLUSTERAPI, TEMPLATE_IMAGE_OCTAVIA
13
13
  from osism.tasks import openstack, handle_task
14
14
 
15
- SUPPORTED_CLUSTERAPI_K8S_IMAGES = ["1.29", "1.30", "1.31"]
15
+ SUPPORTED_CLUSTERAPI_K8S_IMAGES = ["1.30", "1.31", "1.32"]
16
16
 
17
17
 
18
18
  class ImageClusterapi(Command):
@@ -51,7 +51,7 @@ class ImageClusterapi(Command):
51
51
  parser.add_argument(
52
52
  "--filter",
53
53
  type=str,
54
- help="Filter the version to be managed (e.g. 1.31)",
54
+ help="Filter the version to be managed (e.g. 1.32)",
55
55
  default=None,
56
56
  )
57
57
  return parser
osism/commands/netbox.py CHANGED
@@ -2,36 +2,34 @@
2
2
 
3
3
  from cliff.command import Command
4
4
  from loguru import logger
5
- from redis import Redis
6
5
 
7
- from osism import settings
8
- from osism.tasks import conductor, netbox, reconciler, openstack, handle_task
9
-
10
-
11
- redis = Redis(host=settings.REDIS_HOST, port=settings.REDIS_PORT, db=settings.REDIS_DB)
12
- redis.ping()
6
+ from osism.tasks import conductor, netbox, reconciler, handle_task
13
7
 
14
8
 
15
9
  class Ironic(Command):
16
10
  def get_parser(self, prog_name):
17
11
  parser = super(Ironic, self).get_parser(prog_name)
12
+ parser.add_argument(
13
+ "--no-wait",
14
+ help="Do not wait until the sync has been completed",
15
+ action="store_true",
16
+ )
17
+ parser.add_argument(
18
+ "--force-update",
19
+ help="Force update of baremetal nodes (Used to update non-comparable items like passwords)",
20
+ action="store_true",
21
+ )
18
22
  return parser
19
23
 
20
24
  def take_action(self, parsed_args):
21
- # Get Ironic parameters from the conductor
22
- task = conductor.get_ironic_parameters.delay()
23
- task.wait(timeout=None, interval=0.5)
24
- ironic_parameters = task.get()
25
+ wait = not parsed_args.no_wait
25
26
 
26
- # Add all unregistered systems from the Netbox in Ironic
27
- netbox.get_devices_not_yet_registered_in_ironic.apply_async(
28
- (), link=openstack.baremetal_create_nodes.s(ironic_parameters)
27
+ task = conductor.sync_netbox_with_ironic.delay(
28
+ force_update=parsed_args.force_update
29
29
  )
30
-
31
- # Synchronize the current status in Ironic with the Netbox
32
- # openstack.baremetal_node_list.apply_async((), link=netbox.synchronize_device_state.s())
33
-
34
- # Remove systems from Ironic that are no longer present in the Netbox
30
+ if wait:
31
+ logger.info(f"Task {task.task_id} is running. Wait. No more output.")
32
+ task.wait(timeout=None, interval=0.5)
35
33
 
36
34
 
37
35
  class Sync(Command):
@@ -39,7 +37,6 @@ class Sync(Command):
39
37
  parser = super(Sync, self).get_parser(prog_name)
40
38
  parser.add_argument(
41
39
  "--no-wait",
42
- default=False,
43
40
  help="Do not wait until the sync has been completed",
44
41
  action="store_true",
45
42
  )
osism/commands/wait.py CHANGED
@@ -6,8 +6,7 @@ from celery import Celery
6
6
  from celery.result import AsyncResult
7
7
  from cliff.command import Command
8
8
  from loguru import logger
9
- from redis import Redis
10
- from osism import settings
9
+ from osism import utils
11
10
  from osism.tasks import Config
12
11
 
13
12
 
@@ -119,18 +118,12 @@ class Run(Command):
119
118
  print(f"{task_id} = STARTED")
120
119
 
121
120
  if live:
122
- redis = Redis(
123
- host=settings.REDIS_HOST,
124
- port=settings.REDIS_PORT,
125
- db=settings.REDIS_DB,
126
- socket_keepalive=True,
127
- )
128
- redis.ping()
121
+ utils.redis.ping()
129
122
 
130
123
  last_id = 0
131
124
  while_True = True
132
125
  while while_True:
133
- data = redis.xread(
126
+ data = utils.redis.xread(
134
127
  {str(task_id): last_id}, count=1, block=1000
135
128
  )
136
129
  if data:
@@ -143,7 +136,7 @@ class Run(Command):
143
136
  logger.debug(
144
137
  f"Processing message {last_id} of type {message_type}"
145
138
  )
146
- redis.xdel(str(task_id), last_id)
139
+ utils.redis.xdel(str(task_id), last_id)
147
140
 
148
141
  if message_type == "stdout":
149
142
  print(message_content, end="")
@@ -153,7 +146,7 @@ class Run(Command):
153
146
  message_type == "action"
154
147
  and message_content == "quit"
155
148
  ):
156
- redis.close()
149
+ utils.redis.close()
157
150
  if len(task_ids) == 1:
158
151
  return rc
159
152
  else:
osism/core/enums.py CHANGED
@@ -107,6 +107,7 @@ VALIDATE_PLAYBOOKS = {
107
107
  "ntp": {"environment": "generic", "runtime": "osism-ansible"},
108
108
  "system-encoding": {"environment": "generic", "runtime": "osism-ansible"},
109
109
  "ulimits": {"environment": "generic", "runtime": "osism-ansible"},
110
+ "stress": {"environment": "generic", "runtime": "osism-ansible"},
110
111
  }
111
112
 
112
113
  MAP_ROLE2ROLE = {
@@ -187,7 +188,7 @@ MAP_ROLE2ROLE = {
187
188
  [
188
189
  "common",
189
190
  [
190
- ["loadbalancer", ["opensearch", "mariadb-ng"]],
191
+ ["loadbalancer", ["letsencrypt", "opensearch", "mariadb-ng"]],
191
192
  ["openvswitch", ["ovn"]],
192
193
  "memcached",
193
194
  "redis",
@@ -198,6 +199,19 @@ MAP_ROLE2ROLE = {
198
199
  "collection-kubernetes": [
199
200
  ["kubernetes", ["kubeconfig", ["copy-kubeconfig"]]],
200
201
  ],
202
+ "collection-openstack-core": [
203
+ "horizon",
204
+ [
205
+ "keystone",
206
+ [
207
+ "glance",
208
+ "cinder",
209
+ ["neutron", ["octavia"]],
210
+ "designate",
211
+ ["placement", ["nova"]],
212
+ ],
213
+ ],
214
+ ],
201
215
  "collection-openstack": [
202
216
  "horizon",
203
217
  [
@@ -11,8 +11,7 @@ from loguru import logger
11
11
  import json
12
12
  import requests
13
13
 
14
- from osism import utils
15
- from osism.tasks import netbox, openstack
14
+ from osism.tasks import netbox
16
15
  from osism import settings
17
16
 
18
17
  EXCHANGE_NAME = "ironic"
@@ -40,16 +39,13 @@ class BaremetalEvents:
40
39
  },
41
40
  "maintenance_set": {"end": self.node_maintenance_set_end},
42
41
  "provision_set": {
42
+ "start": self.node_provision_set_start,
43
43
  "end": self.node_provision_set_end,
44
44
  "success": self.node_provision_set_success,
45
45
  },
46
46
  "delete": {"end": self.node_delete_end},
47
47
  "create": {"end": self.node_create_end},
48
48
  },
49
- "port": {
50
- "create": {"end": self.port_create_end},
51
- "update": {"end": self.port_update_end},
52
- },
53
49
  }
54
50
  }
55
51
 
@@ -78,7 +74,7 @@ class BaremetalEvents:
78
74
  logger.info(
79
75
  f"baremetal.node.power_set.end ## {name} ## {object_data['power_state']}"
80
76
  )
81
- netbox.set_state.delay(name, object_data["power_state"], "power")
77
+ netbox.set_power_state.delay(name, object_data["power_state"])
82
78
 
83
79
  def node_power_state_corrected_success(self, payload: dict[Any, Any]) -> None:
84
80
  object_data = self.get_object_data(payload)
@@ -86,7 +82,7 @@ class BaremetalEvents:
86
82
  logger.info(
87
83
  f"baremetal.node.power_state_corrected.success ## {name} ## {object_data['power_state']}"
88
84
  )
89
- netbox.set_state.delay(name, object_data["power_state"], "power")
85
+ netbox.set_power_state.delay(name, object_data["power_state"])
90
86
 
91
87
  def node_maintenance_set_end(self, payload: dict[Any, Any]) -> None:
92
88
  object_data = self.get_object_data(payload)
@@ -94,7 +90,7 @@ class BaremetalEvents:
94
90
  logger.info(
95
91
  f"baremetal.node.maintenance_set.end ## {name} ## {object_data['maintenance']}"
96
92
  )
97
- netbox.set_maintenance.delay(name, object_data["maintenance"])
93
+ netbox.set_maintenance.delay(name, state=object_data["maintenance"])
98
94
 
99
95
  def node_provision_set_success(self, payload: dict[Any, Any]) -> None:
100
96
  # A provision status was successfully set, update it in the netbox
@@ -103,80 +99,37 @@ class BaremetalEvents:
103
99
  logger.info(
104
100
  f"baremetal.node.provision_set.success ## {name} ## {object_data['provision_state']}"
105
101
  )
106
- netbox.set_state.delay(name, object_data["provision_state"], "provision")
102
+ netbox.set_provision_state.delay(name, object_data["provision_state"])
107
103
 
108
- def node_provision_set_end(self, payload: dict[Any, Any]) -> None:
104
+ def node_provision_set_start(self, payload: dict[Any, Any]) -> None:
109
105
  object_data = self.get_object_data(payload)
110
106
  name = object_data["name"]
111
107
  logger.info(
112
- f"baremetal.node.provision_set.end ## {name} ## {object_data['provision_state']}"
113
- )
114
- netbox.set_state.delay(name, object_data["provision_state"], "provision")
115
-
116
- if (
117
- object_data["previous_provision_state"] == "inspect wait"
118
- and object_data["event"] == "done"
119
- ):
120
- netbox.set_state.delay(name, "introspected", "introspection")
121
- openstack.baremetal_set_node_provision_state.delay(name, "provide")
122
-
123
- def port_create_end(self, payload: dict[Any, Any]) -> None:
124
- object_data = self.get_object_data(payload)
125
- name = object_data["name"]
126
- logger.info(f"baremetal.port.create.end ## {object_data['uuid']}")
127
-
128
- mac_address = object_data["address"]
129
- interface_a = utils.nb.dcim.interfaces.get(mac_address=mac_address)
130
- device_a = interface_a.device
131
-
132
- task = openstack.baremetal_get_network_interface_name.delay(
133
- device_a.name, mac_address
134
- )
135
- task.wait(timeout=None, interval=0.5)
136
- network_interface_name = task.get()
137
-
138
- netbox.update_network_interface_name.delay(
139
- object_data["address"], network_interface_name
108
+ f"baremetal.node.provision_set.start ## {name} ## {object_data['provision_state']}"
140
109
  )
110
+ netbox.set_provision_state.delay(name, object_data["provision_state"])
141
111
 
142
- def port_update_end(self, payload: dict[Any, Any]) -> None:
112
+ def node_provision_set_end(self, payload: dict[Any, Any]) -> None:
143
113
  object_data = self.get_object_data(payload)
144
114
  name = object_data["name"]
145
- logger.info(f"baremetal.port.update.end ## {object_data['uuid']}")
146
-
147
- mac_address = object_data["address"]
148
- interface_a = utils.nb.dcim.interfaces.get(mac_address=mac_address)
149
- device_a = interface_a.device
150
-
151
- task = openstack.baremetal_get_network_interface_name.delay(
152
- device_a.name, mac_address
153
- )
154
- task.wait(timeout=None, interval=0.5)
155
- network_interface_name = task.get()
156
-
157
- netbox.update_network_interface_name.delay(
158
- object_data["address"], network_interface_name
115
+ logger.info(
116
+ f"baremetal.node.provision_set.end ## {name} ## {object_data['provision_state']}"
159
117
  )
118
+ netbox.set_provision_state.delay(name, object_data["provision_state"])
160
119
 
161
120
  def node_delete_end(self, payload: dict[Any, Any]) -> None:
162
121
  object_data = self.get_object_data(payload)
163
122
  name = object_data["name"]
164
123
  logger.info(f"baremetal.node.delete.end ## {name}")
165
-
166
- netbox.set_state.delay(name, "unregistered", "ironic")
167
- netbox.set_state.delay(name, None, "provision")
168
- netbox.set_state.delay(name, None, "power")
169
- netbox.set_state.delay(name, None, "introspection")
170
- netbox.set_state.delay(name, None, "deployment")
171
-
172
- # remove internal flavor
173
- openstack.baremetal_delete_internal_flavor.delay(name)
124
+ netbox.set_provision_state.delay(name, None)
125
+ netbox.set_power_state.delay(name, None)
174
126
 
175
127
  def node_create_end(self, payload: dict[Any, Any]) -> None:
176
128
  object_data = self.get_object_data(payload)
177
129
  name = object_data["name"]
178
130
  logger.info(f"baremetal.node.create.end ## {name}")
179
- netbox.set_state.delay(name, "registered", "ironic")
131
+ netbox.set_provision_state.delay(name, object_data["provision_state"])
132
+ netbox.set_power_state.delay(name, object_data["power_state"])
180
133
 
181
134
 
182
135
  class NotificationsDump(ConsumerMixin):
@@ -207,7 +160,17 @@ class NotificationsDump(ConsumerMixin):
207
160
 
208
161
  def on_message(self, body, message):
209
162
  data = json.loads(body["oslo.message"])
210
- # logger.info(data)
163
+ logger.debug(
164
+ data["event_type"]
165
+ + ": "
166
+ + str(
167
+ {
168
+ k: v
169
+ for k, v in data["payload"]["ironic_object.data"].items()
170
+ if k in ["provision_state", "power_state"]
171
+ }
172
+ )
173
+ )
211
174
 
212
175
  if self.osism_api_session:
213
176
  tries = 1
@@ -268,8 +231,6 @@ class NotificationsDump(ConsumerMixin):
268
231
  handler = self.baremetal_events.get_handler(data["event_type"])
269
232
  handler(data["payload"])
270
233
 
271
- logger.info(self.baremetal_events.get_object_data(data["payload"]))
272
-
273
234
 
274
235
  def main():
275
236
  while True:
osism/tasks/__init__.py CHANGED
@@ -5,14 +5,10 @@ import re
5
5
  import subprocess
6
6
  import time
7
7
 
8
- from celery.signals import worker_process_init
9
8
  from loguru import logger
10
- from redis import Redis
11
9
  from pottery import Redlock
12
10
 
13
- from osism import settings
14
-
15
- redis = None
11
+ from osism import utils
16
12
 
17
13
 
18
14
  class Config:
@@ -36,19 +32,6 @@ class Config:
36
32
  }
37
33
 
38
34
 
39
- @worker_process_init.connect
40
- def celery_init_worker(**kwargs):
41
- global redis
42
-
43
- redis = Redis(
44
- host=settings.REDIS_HOST,
45
- port=settings.REDIS_PORT,
46
- db=settings.REDIS_DB,
47
- socket_keepalive=True,
48
- )
49
- redis.ping()
50
-
51
-
52
35
  def run_ansible_in_environment(
53
36
  request_id,
54
37
  worker,
@@ -88,7 +71,7 @@ def run_ansible_in_environment(
88
71
 
89
72
  # NOTE: This is a first step to make Ansible Vault usable via OSISM workers.
90
73
  # It's not ready in that form yet.
91
- ansible_vault_password = redis.get("ansible_vault_password")
74
+ ansible_vault_password = utils.redis.get("ansible_vault_password")
92
75
  if ansible_vault_password:
93
76
  env["VAULT"] = "/ansible-vault.py"
94
77
 
@@ -96,7 +79,7 @@ def run_ansible_in_environment(
96
79
  if locking:
97
80
  lock = Redlock(
98
81
  key=f"lock-ansible-{environment}-{role}",
99
- masters={redis},
82
+ masters={utils.redis},
100
83
  auto_release_time=auto_release_time,
101
84
  )
102
85
 
@@ -178,14 +161,14 @@ def run_ansible_in_environment(
178
161
  while p.poll() is None:
179
162
  line = p.stdout.readline().decode("utf-8")
180
163
  if publish:
181
- redis.xadd(request_id, {"type": "stdout", "content": line})
164
+ utils.redis.xadd(request_id, {"type": "stdout", "content": line})
182
165
  result += line
183
166
 
184
167
  rc = p.wait(timeout=60)
185
168
 
186
169
  if publish:
187
- redis.xadd(request_id, {"type": "rc", "content": rc})
188
- redis.xadd(request_id, {"type": "action", "content": "quit"})
170
+ utils.redis.xadd(request_id, {"type": "rc", "content": rc})
171
+ utils.redis.xadd(request_id, {"type": "action", "content": "quit"})
189
172
 
190
173
  if locking:
191
174
  lock.release()
@@ -209,7 +192,7 @@ def run_command(
209
192
  if locking:
210
193
  lock = Redlock(
211
194
  key=f"lock-{command}",
212
- masters={redis},
195
+ masters={utils.redis},
213
196
  auto_release_time=auto_release_time,
214
197
  )
215
198
 
@@ -222,14 +205,14 @@ def run_command(
222
205
  while p.poll() is None:
223
206
  line = p.stdout.readline().decode("utf-8")
224
207
  if publish:
225
- redis.xadd(request_id, {"type": "stdout", "content": line})
208
+ utils.redis.xadd(request_id, {"type": "stdout", "content": line})
226
209
  result += line
227
210
 
228
211
  rc = p.wait(timeout=60)
229
212
 
230
213
  if publish:
231
- redis.xadd(request_id, {"type": "rc", "content": rc})
232
- redis.xadd(request_id, {"type": "action", "content": "quit"})
214
+ utils.redis.xadd(request_id, {"type": "rc", "content": rc})
215
+ utils.redis.xadd(request_id, {"type": "action", "content": "quit"})
233
216
 
234
217
  if locking:
235
218
  lock.release()
@@ -238,23 +221,12 @@ def run_command(
238
221
 
239
222
 
240
223
  def handle_task(t, wait=True, format="log", timeout=3600):
241
- global redis
242
-
243
- if not redis:
244
- redis = Redis(
245
- host=settings.REDIS_HOST,
246
- port=settings.REDIS_PORT,
247
- db=settings.REDIS_DB,
248
- socket_keepalive=True,
249
- )
250
- redis.ping()
251
-
252
224
  rc = 0
253
225
  if wait:
254
226
  stoptime = time.time() + timeout
255
227
  last_id = 0
256
228
  while time.time() < stoptime:
257
- data = redis.xread(
229
+ data = utils.redis.xread(
258
230
  {str(t.task_id): last_id}, count=1, block=(timeout * 1000)
259
231
  )
260
232
  if data:
@@ -266,7 +238,7 @@ def handle_task(t, wait=True, format="log", timeout=3600):
266
238
  message_content = message[b"content"].decode()
267
239
 
268
240
  logger.debug(f"Processing message {last_id} of type {message_type}")
269
- redis.xdel(str(t.task_id), last_id)
241
+ utils.redis.xdel(str(t.task_id), last_id)
270
242
 
271
243
  if message_type == "stdout":
272
244
  print(message_content, end="", flush=True)
@@ -279,7 +251,7 @@ def handle_task(t, wait=True, format="log", timeout=3600):
279
251
  elif message_type == "rc":
280
252
  rc = int(message_content)
281
253
  elif message_type == "action" and message_content == "quit":
282
- redis.close()
254
+ utils.redis.close()
283
255
  return rc
284
256
  else:
285
257
  logger.info(