osism 0.20250605.0__py3-none-any.whl → 0.20250621.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.
Files changed (36) hide show
  1. osism/commands/baremetal.py +71 -10
  2. osism/commands/manage.py +25 -1
  3. osism/commands/netbox.py +22 -5
  4. osism/commands/reconciler.py +6 -28
  5. osism/commands/sync.py +48 -1
  6. osism/commands/validate.py +7 -30
  7. osism/commands/wait.py +8 -31
  8. osism/services/listener.py +1 -1
  9. osism/settings.py +13 -2
  10. osism/tasks/__init__.py +8 -40
  11. osism/tasks/conductor/__init__.py +8 -1
  12. osism/tasks/conductor/ironic.py +90 -66
  13. osism/tasks/conductor/netbox.py +267 -6
  14. osism/tasks/conductor/sonic/__init__.py +26 -0
  15. osism/tasks/conductor/sonic/bgp.py +87 -0
  16. osism/tasks/conductor/sonic/cache.py +114 -0
  17. osism/tasks/conductor/sonic/config_generator.py +908 -0
  18. osism/tasks/conductor/sonic/connections.py +389 -0
  19. osism/tasks/conductor/sonic/constants.py +79 -0
  20. osism/tasks/conductor/sonic/device.py +82 -0
  21. osism/tasks/conductor/sonic/exporter.py +226 -0
  22. osism/tasks/conductor/sonic/interface.py +789 -0
  23. osism/tasks/conductor/sonic/sync.py +190 -0
  24. osism/tasks/conductor.py +2 -0
  25. osism/tasks/netbox.py +6 -4
  26. osism/tasks/reconciler.py +4 -5
  27. osism/utils/__init__.py +51 -4
  28. {osism-0.20250605.0.dist-info → osism-0.20250621.0.dist-info}/METADATA +4 -4
  29. {osism-0.20250605.0.dist-info → osism-0.20250621.0.dist-info}/RECORD +35 -25
  30. {osism-0.20250605.0.dist-info → osism-0.20250621.0.dist-info}/entry_points.txt +5 -0
  31. osism-0.20250621.0.dist-info/pbr.json +1 -0
  32. osism-0.20250605.0.dist-info/pbr.json +0 -1
  33. {osism-0.20250605.0.dist-info → osism-0.20250621.0.dist-info}/WHEEL +0 -0
  34. {osism-0.20250605.0.dist-info → osism-0.20250621.0.dist-info}/licenses/AUTHORS +0 -0
  35. {osism-0.20250605.0.dist-info → osism-0.20250621.0.dist-info}/licenses/LICENSE +0 -0
  36. {osism-0.20250605.0.dist-info → osism-0.20250621.0.dist-info}/top_level.txt +0 -0
@@ -2,10 +2,14 @@
2
2
 
3
3
  from cliff.command import Command
4
4
 
5
+ import tempfile
6
+ import os
5
7
  from loguru import logger
6
8
  import openstack
7
9
  from tabulate import tabulate
8
10
  import json
11
+ import yaml
12
+ from openstack.baremetal import configdrive as configdrive_builder
9
13
 
10
14
  from osism.commands import get_cloud_connection
11
15
 
@@ -127,20 +131,35 @@ class BaremetalDeploy(Command):
127
131
  if not node:
128
132
  continue
129
133
 
130
- if node.provision_state in ["available", "deploy failed"]:
134
+ if (
135
+ node.provision_state in ["available", "deploy failed"]
136
+ and not node["maintenance"]
137
+ ):
131
138
  provision_state = "active"
132
139
  elif (
133
140
  node.provision_state == "error"
134
141
  or node.provision_state == "active"
142
+ and not node["maintenance"]
135
143
  and rebuild
136
144
  ):
137
145
  provision_state = "rebuild"
138
146
  else:
139
147
  logger.warning(
140
- f"Node {node.name} ({node.id}) not in supported provision state"
148
+ f"Node {node.name} ({node.id}) not in supported state! Provision state: {node.provision_state}, maintenance mode: {node['maintenance']}"
141
149
  )
142
150
  continue
143
151
 
152
+ # NOTE: Ironic removes "instance_info" on undeploy. It was saved to "extra" during sync and needs to be refreshed here.
153
+ if (
154
+ "instance_info" in node
155
+ and not node["instance_info"]
156
+ and "instance_info" in node["extra"]
157
+ and node["extra"]["instance_info"]
158
+ ):
159
+ node = conn.baremetal.update_node(
160
+ node, instance_info=json.loads(node.extra["instance_info"])
161
+ )
162
+
144
163
  try:
145
164
  conn.baremetal.validate_node(
146
165
  node.id, required=("boot", "deploy", "power")
@@ -148,23 +167,60 @@ class BaremetalDeploy(Command):
148
167
  except openstack.exceptions.ValidationException:
149
168
  logger.warning(f"Node {node.name} ({node.id}) could not be validated")
150
169
  continue
170
+ # NOTE: Prepare osism config drive
151
171
  try:
152
- config_drive = {"meta_data": {}}
172
+ playbook = []
173
+ play = {
174
+ "name": "Run bootstrap - part 2",
175
+ "hosts": "localhost",
176
+ "connection": "local",
177
+ "gather_facts": True,
178
+ "vars": {},
179
+ "roles": [
180
+ "osism.commons.hostname",
181
+ "osism.commons.hosts",
182
+ ],
183
+ }
184
+ play["vars"].update(
185
+ {"hostname_name": node.name, "hosts_type": "template"}
186
+ )
153
187
  if (
154
188
  "netplan_parameters" in node.extra
155
189
  and node.extra["netplan_parameters"]
156
190
  ):
157
- config_drive["meta_data"].update(
191
+ play["vars"].update(
158
192
  {
159
- "netplan_parameters": json.loads(
160
- node.extra["netplan_parameters"]
161
- )
193
+ "network_allow_service_restart": True,
162
194
  }
163
195
  )
196
+ play["vars"].update(json.loads(node.extra["netplan_parameters"]))
197
+ play["roles"].append("osism.commons.network")
164
198
  if "frr_parameters" in node.extra and node.extra["frr_parameters"]:
165
- config_drive["meta_data"].update(
166
- {"frr_parameters": json.loads(node.extra["frr_parameters"])}
199
+ play["vars"].update(
200
+ {
201
+ "frr_dummy_interface": "loopback0",
202
+ }
167
203
  )
204
+ play["vars"].update(json.loads(node.extra["frr_parameters"]))
205
+ play["roles"].append("osism.services.frr")
206
+ playbook.append(play)
207
+ with tempfile.TemporaryDirectory() as tmp_dir:
208
+ with open(os.path.join(tmp_dir, "playbook.yml"), "w") as file:
209
+ yaml.dump(
210
+ playbook,
211
+ file,
212
+ default_flow_style=False,
213
+ explicit_start=True,
214
+ indent=2,
215
+ sort_keys=False,
216
+ )
217
+ config_drive = configdrive_builder.pack(tmp_dir)
218
+ except Exception as exc:
219
+ logger.warning(
220
+ f"Failed to build config drive for {node.name} ({node.id}): {exc}"
221
+ )
222
+ continue
223
+ try:
168
224
  conn.baremetal.set_node_provision_state(
169
225
  node.id, provision_state, config_drive=config_drive
170
226
  )
@@ -231,12 +287,17 @@ class BaremetalUndeploy(Command):
231
287
 
232
288
  if node.provision_state in ["active", "deploy failed", "error"]:
233
289
  try:
234
- conn.baremetal.set_node_provision_state(node.id, "undeploy")
290
+ node = conn.baremetal.set_node_provision_state(node.id, "undeploy")
235
291
  except Exception as exc:
236
292
  logger.warning(
237
293
  f"Node {node.name} ({node.id}) could not be moved to available state: {exc}"
238
294
  )
239
295
  continue
296
+ # NOTE: Ironic removes "instance_info" on undeploy. It was saved to "extra" during sync and needs to be refreshed here.
297
+ if "instance_info" in node["extra"]:
298
+ node = conn.baremetal.update_node(
299
+ node, instance_info=json.loads(node.extra["instance_info"])
300
+ )
240
301
  else:
241
302
  logger.warning(
242
303
  f"Node {node.name} ({node.id}) not in supported provision state"
osism/commands/manage.py CHANGED
@@ -10,7 +10,7 @@ from loguru import logger
10
10
  import requests
11
11
 
12
12
  from osism.data import TEMPLATE_IMAGE_CLUSTERAPI, TEMPLATE_IMAGE_OCTAVIA
13
- from osism.tasks import openstack, handle_task
13
+ from osism.tasks import openstack, ansible, handle_task
14
14
 
15
15
  SUPPORTED_CLUSTERAPI_K8S_IMAGES = ["1.31", "1.32", "1.33"]
16
16
 
@@ -360,3 +360,27 @@ class Flavors(Command):
360
360
  )
361
361
 
362
362
  return handle_task(task, wait, format="script", timeout=3600)
363
+
364
+
365
+ class Dnsmasq(Command):
366
+ def get_parser(self, prog_name):
367
+ parser = super(Dnsmasq, self).get_parser(prog_name)
368
+ parser.add_argument(
369
+ "--no-wait",
370
+ default=False,
371
+ help="Do not wait until dnsmasq has been applied",
372
+ action="store_true",
373
+ )
374
+ return parser
375
+
376
+ def take_action(self, parsed_args):
377
+ wait = not parsed_args.no_wait
378
+
379
+ task_signature = ansible.run.si("infrastructure", "dnsmasq", [])
380
+ task = task_signature.apply_async()
381
+ if wait:
382
+ logger.info(
383
+ f"It takes a moment until task {task.task_id} (dnsmasq) has been started and output is visible here."
384
+ )
385
+
386
+ return handle_task(task, wait, format="log", timeout=300)
osism/commands/netbox.py CHANGED
@@ -8,6 +8,7 @@ from loguru import logger
8
8
  import yaml
9
9
 
10
10
  from osism.tasks import conductor, netbox, handle_task
11
+ from osism import utils
11
12
 
12
13
 
13
14
  class Ironic(Command):
@@ -18,6 +19,12 @@ class Ironic(Command):
18
19
  help="Do not wait until the sync has been completed",
19
20
  action="store_true",
20
21
  )
22
+ parser.add_argument(
23
+ "--task-timeout",
24
+ default=os.environ.get("OSISM_TASK_TIMEOUT", 300),
25
+ type=int,
26
+ help="Timeout for a scheduled task that has not been executed yet",
27
+ )
21
28
  parser.add_argument(
22
29
  "--force-update",
23
30
  help="Force update of baremetal nodes (Used to update non-comparable items like passwords)",
@@ -27,13 +34,23 @@ class Ironic(Command):
27
34
 
28
35
  def take_action(self, parsed_args):
29
36
  wait = not parsed_args.no_wait
37
+ task_timeout = parsed_args.task_timeout
30
38
 
31
39
  task = conductor.sync_ironic.delay(force_update=parsed_args.force_update)
32
40
  if wait:
33
41
  logger.info(
34
- f"Task {task.task_id} (sync ironic) is running. Wait. No more output."
42
+ f"Task {task.task_id} (sync ironic) is running in background. Output comming soon."
43
+ )
44
+ try:
45
+ return utils.fetch_task_output(task.id, timeout=task_timeout)
46
+ except TimeoutError:
47
+ logger.error(
48
+ f"Timeout while waiting for further output of task {task.task_id} (sync ironic)"
49
+ )
50
+ else:
51
+ logger.info(
52
+ f"Task {task.task_id} (sync ironic) is running in background. No more output."
35
53
  )
36
- task.wait(timeout=None, interval=0.5)
37
54
 
38
55
 
39
56
  class Sync(Command):
@@ -63,13 +80,13 @@ class Manage(Command):
63
80
  parser.add_argument(
64
81
  "--no-wait",
65
82
  default=False,
66
- help="Do not wait until the management of the netbox has been completed",
83
+ help="Do not wait until the management of the NetBox has been completed",
67
84
  action="store_true",
68
85
  )
69
86
  parser.add_argument(
70
87
  "--no-netbox-wait",
71
88
  default=False,
72
- help="Do not wait for the netbox API to be ready",
89
+ help="Do not wait for the NetBox API to be ready",
73
90
  action="store_true",
74
91
  )
75
92
  parser.add_argument(
@@ -195,7 +212,7 @@ class Console(Command):
195
212
  url = os.environ.get("NETBOX_API", None)
196
213
 
197
214
  if not token or not url:
198
- logger.error("Netbox integration not configured.")
215
+ logger.error("NetBox integration not configured.")
199
216
  return
200
217
 
201
218
  subprocess.call(
@@ -2,13 +2,12 @@
2
2
 
3
3
  import os
4
4
  import subprocess
5
- import time
6
5
 
7
6
  from cliff.command import Command
8
7
  from loguru import logger
9
8
 
10
9
  from osism.tasks import reconciler
11
- from osism.utils import redis
10
+ from osism import utils
12
11
 
13
12
 
14
13
  class Run(Command):
@@ -50,33 +49,12 @@ class Sync(Command):
50
49
  logger.info(
51
50
  f"Task {t.task_id} (sync inventory) is running in background. Output coming soon."
52
51
  )
53
- rc = 0
54
- stoptime = time.time() + task_timeout
55
- last_id = 0
56
- while time.time() < stoptime:
57
- data = redis.xread(
58
- {str(t.task_id): last_id}, count=1, block=(300 * 1000)
52
+ try:
53
+ return utils.fetch_task_output(t.id, timeout=task_timeout)
54
+ except TimeoutError:
55
+ logger.error(
56
+ f"Timeout while waiting for further output of task {t.task_id} (sync inventory)"
59
57
  )
60
- if data:
61
- stoptime = time.time() + task_timeout
62
- messages = data[0]
63
- for message_id, message in messages[1]:
64
- last_id = message_id.decode()
65
- message_type = message[b"type"].decode()
66
- message_content = message[b"content"].decode()
67
-
68
- logger.debug(
69
- f"Processing message {last_id} of type {message_type}"
70
- )
71
- redis.xdel(str(t.task_id), last_id)
72
-
73
- if message_type == "stdout":
74
- print(message_content, end="")
75
- elif message_type == "rc":
76
- rc = int(message_content)
77
- elif message_type == "action" and message_content == "quit":
78
- redis.close()
79
- return rc
80
58
  else:
81
59
  logger.info(
82
60
  f"Task {t.task_id} (sync inventory) is running in background. No more output."
osism/commands/sync.py CHANGED
@@ -1,8 +1,9 @@
1
1
  # SPDX-License-Identifier: Apache-2.0
2
2
 
3
3
  from cliff.command import Command
4
+ from loguru import logger
4
5
 
5
- from osism.tasks import ansible, handle_task
6
+ from osism.tasks import ansible, conductor, handle_task
6
7
 
7
8
 
8
9
  class Facts(Command):
@@ -17,3 +18,49 @@ class Facts(Command):
17
18
  )
18
19
  rc = handle_task(t)
19
20
  return rc
21
+
22
+
23
+ class Sonic(Command):
24
+ def get_parser(self, prog_name):
25
+ parser = super(Sonic, self).get_parser(prog_name)
26
+ parser.add_argument(
27
+ "device",
28
+ nargs="?",
29
+ help="Optional device name to sync configuration for a specific device",
30
+ )
31
+ parser.add_argument(
32
+ "--no-wait",
33
+ default=False,
34
+ help="Do not wait until the sync has been completed",
35
+ action="store_true",
36
+ )
37
+ parser.add_argument(
38
+ "--diff",
39
+ default=True,
40
+ help="Show configuration diff when changes are detected (default: True)",
41
+ action="store_true",
42
+ )
43
+ parser.add_argument(
44
+ "--no-diff",
45
+ dest="diff",
46
+ help="Do not show configuration diff",
47
+ action="store_false",
48
+ )
49
+ return parser
50
+
51
+ def take_action(self, parsed_args):
52
+ wait = not parsed_args.no_wait
53
+ device_name = parsed_args.device
54
+ show_diff = parsed_args.diff
55
+
56
+ task = conductor.sync_sonic.delay(device_name, show_diff)
57
+
58
+ if device_name:
59
+ logger.info(
60
+ f"Task {task.task_id} (sync sonic for device {device_name}) started"
61
+ )
62
+ else:
63
+ logger.info(f"Task {task.task_id} (sync sonic) started")
64
+
65
+ rc = handle_task(task, wait=wait)
66
+ return rc
@@ -1,14 +1,13 @@
1
1
  # SPDX-License-Identifier: Apache-2.0
2
2
 
3
3
  import argparse
4
- import time
5
4
 
6
5
  from cliff.command import Command
7
6
  from loguru import logger
8
7
 
9
8
  from osism.core.enums import VALIDATE_PLAYBOOKS
10
9
  from osism.tasks import ansible, ceph, kolla
11
- from osism.utils import redis
10
+ from osism import utils
12
11
 
13
12
 
14
13
  class Run(Command):
@@ -53,35 +52,13 @@ class Run(Command):
53
52
  return parser
54
53
 
55
54
  def _handle_task(self, t, wait, format, timeout, playbook):
56
- rc = 0
57
55
  if wait:
58
- stoptime = time.time() + timeout
59
- last_id = 0
60
- while time.time() < stoptime:
61
- data = redis.xread(
62
- {str(t.task_id): last_id}, count=1, block=(timeout * 1000)
56
+ try:
57
+ return utils.fetch_task_output(t.id, timeout=timeout)
58
+ except TimeoutError:
59
+ logger.error(
60
+ f"Timeout while waiting for further output of task {t.task_id} (sync inventory)"
63
61
  )
64
- if data:
65
- stoptime = time.time() + timeout
66
- messages = data[0]
67
- for message_id, message in messages[1]:
68
- last_id = message_id.decode()
69
- message_type = message[b"type"].decode()
70
- message_content = message[b"content"].decode()
71
-
72
- logger.debug(
73
- f"Processing message {last_id} of type {message_type}"
74
- )
75
- redis.xdel(str(t.task_id), message_id)
76
-
77
- if message_type == "stdout":
78
- print(message_content, end="")
79
- elif message_type == "rc":
80
- rc = int(message_content)
81
- elif message_type == "action" and message_content == "quit":
82
- redis.close()
83
- return rc
84
-
85
62
  else:
86
63
  if format == "log":
87
64
  logger.info(
@@ -90,7 +67,7 @@ class Run(Command):
90
67
  elif format == "script":
91
68
  print(f"{t.task_id}")
92
69
 
93
- return rc
70
+ return 0
94
71
 
95
72
  def take_action(self, parsed_args):
96
73
  arguments = parsed_args.arguments
osism/commands/wait.py CHANGED
@@ -119,38 +119,15 @@ class Run(Command):
119
119
 
120
120
  if live:
121
121
  utils.redis.ping()
122
-
123
- last_id = 0
124
- while_True = True
125
- while while_True:
126
- data = utils.redis.xread(
127
- {str(task_id): last_id}, count=1, block=1000
122
+ try:
123
+ rc = utils.fetch_task_output(task_id)
124
+ except TimeoutError:
125
+ logger.error(
126
+ f"Timeout while waiting for further output of task {task_id}"
128
127
  )
129
- if data:
130
- messages = data[0]
131
- for message_id, message in messages[1]:
132
- last_id = message_id.decode()
133
- message_type = message[b"type"].decode()
134
- message_content = message[b"content"].decode()
135
-
136
- logger.debug(
137
- f"Processing message {last_id} of type {message_type}"
138
- )
139
- utils.redis.xdel(str(task_id), last_id)
140
-
141
- if message_type == "stdout":
142
- print(message_content, end="")
143
- elif message_type == "rc":
144
- rc = int(message_content)
145
- elif (
146
- message_type == "action"
147
- and message_content == "quit"
148
- ):
149
- utils.redis.close()
150
- if len(task_ids) == 1:
151
- return rc
152
- else:
153
- while_True = False
128
+
129
+ if len(task_ids) == 1:
130
+ return rc
154
131
  else:
155
132
  tmp_task_ids.insert(0, task_id)
156
133
 
@@ -93,7 +93,7 @@ class BaremetalEvents:
93
93
  netbox.set_maintenance.delay(name, state=object_data["maintenance"])
94
94
 
95
95
  def node_provision_set_success(self, payload: dict[Any, Any]) -> None:
96
- # A provision status was successfully set, update it in the netbox
96
+ # A provision status was successfully set, update it in the NetBox
97
97
  object_data = self.get_object_data(payload)
98
98
  name = object_data["name"]
99
99
  logger.info(
osism/settings.py CHANGED
@@ -35,11 +35,22 @@ INVENTORY_RECONCILER_SCHEDULE = float(
35
35
 
36
36
  OSISM_API_URL = os.getenv("OSISM_API_URL", None)
37
37
 
38
- NETBOX_FILTER_CONDUCTOR = os.getenv(
39
- "NETBOX_FILTER_CONDUCTOR",
38
+ NETBOX_FILTER_CONDUCTOR_IRONIC = os.getenv(
39
+ "NETBOX_FILTER_CONDUCTOR_IRONIC",
40
40
  "[{'state': 'active', 'tag': ['managed-by-ironic']}]",
41
41
  )
42
42
 
43
+ NETBOX_FILTER_CONDUCTOR_SONIC = os.getenv(
44
+ "NETBOX_FILTER_CONDUCTOR_SONIC",
45
+ "[{'state': 'active', 'tag': ['managed-by-metalbox']}]",
46
+ )
47
+
48
+ # SONiC export configuration
49
+ SONIC_EXPORT_DIR = os.getenv("SONIC_EXPORT_DIR", "/etc/sonic/export")
50
+ SONIC_EXPORT_PREFIX = os.getenv("SONIC_EXPORT_PREFIX", "osism_")
51
+ SONIC_EXPORT_SUFFIX = os.getenv("SONIC_EXPORT_SUFFIX", "_config_db.json")
52
+ SONIC_EXPORT_IDENTIFIER = os.getenv("SONIC_EXPORT_IDENTIFIER", "serial-number")
53
+
43
54
  NETBOX_SECONDARIES = (
44
55
  os.getenv("NETBOX_SECONDARIES", read_secret("NETBOX_SECONDARIES")) or "[]"
45
56
  )
osism/tasks/__init__.py CHANGED
@@ -4,7 +4,6 @@ import logging
4
4
  import os
5
5
  import re
6
6
  import subprocess
7
- import time
8
7
 
9
8
  from loguru import logger
10
9
  from pottery import Redlock
@@ -163,14 +162,13 @@ def run_ansible_in_environment(
163
162
  while p.poll() is None:
164
163
  line = p.stdout.readline().decode("utf-8")
165
164
  if publish:
166
- utils.redis.xadd(request_id, {"type": "stdout", "content": line})
165
+ utils.push_task_output(request_id, line)
167
166
  result += line
168
167
 
169
168
  rc = p.wait(timeout=60)
170
169
 
171
170
  if publish:
172
- utils.redis.xadd(request_id, {"type": "rc", "content": rc})
173
- utils.redis.xadd(request_id, {"type": "action", "content": "quit"})
171
+ utils.finish_task_output(request_id, rc=rc)
174
172
 
175
173
  if locking:
176
174
  lock.release()
@@ -212,14 +210,13 @@ def run_command(
212
210
  while p.poll() is None:
213
211
  line = p.stdout.readline().decode("utf-8")
214
212
  if publish:
215
- utils.redis.xadd(request_id, {"type": "stdout", "content": line})
213
+ utils.push_task_output(request_id, line)
216
214
  result += line
217
215
 
218
216
  rc = p.wait(timeout=60)
219
217
 
220
218
  if publish:
221
- utils.redis.xadd(request_id, {"type": "rc", "content": rc})
222
- utils.redis.xadd(request_id, {"type": "action", "content": "quit"})
219
+ utils.finish_task_output(request_id, rc=rc)
223
220
 
224
221
  if locking:
225
222
  lock.release()
@@ -228,39 +225,10 @@ def run_command(
228
225
 
229
226
 
230
227
  def handle_task(t, wait=True, format="log", timeout=3600):
231
- rc = 0
232
228
  if wait:
233
- stoptime = time.time() + timeout
234
- last_id = 0
235
- while time.time() < stoptime:
236
- data = utils.redis.xread(
237
- {str(t.task_id): last_id}, count=1, block=(timeout * 1000)
238
- )
239
- if data:
240
- stoptime = time.time() + timeout
241
- messages = data[0]
242
- for message_id, message in messages[1]:
243
- last_id = message_id.decode()
244
- message_type = message[b"type"].decode()
245
- message_content = message[b"content"].decode()
246
-
247
- logger.debug(f"Processing message {last_id} of type {message_type}")
248
- utils.redis.xdel(str(t.task_id), last_id)
249
-
250
- if message_type == "stdout":
251
- print(message_content, end="", flush=True)
252
- if "PLAY RECAP" in message_content:
253
- logger.info(
254
- "Play has been completed. There may now be a delay until "
255
- "all logs have been written."
256
- )
257
- logger.info("Please wait and do not abort execution.")
258
- elif message_type == "rc":
259
- rc = int(message_content)
260
- elif message_type == "action" and message_content == "quit":
261
- utils.redis.close()
262
- return rc
263
- else:
229
+ try:
230
+ return utils.fetch_task_output(t.id, timeout=timeout)
231
+ except TimeoutError:
264
232
  logger.info(
265
233
  f"There has been no output from the task {t.task_id} for {timeout} second(s)."
266
234
  )
@@ -284,4 +252,4 @@ def handle_task(t, wait=True, format="log", timeout=3600):
284
252
  elif format == "script":
285
253
  print(f"{t.task_id}")
286
254
 
287
- return rc
255
+ return 0
@@ -8,6 +8,7 @@ from loguru import logger
8
8
  from osism.tasks import Config
9
9
  from osism.tasks.conductor.config import get_configuration
10
10
  from osism.tasks.conductor.ironic import sync_ironic as _sync_ironic
11
+ from osism.tasks.conductor.sonic import sync_sonic as _sync_sonic
11
12
 
12
13
 
13
14
  # App configuration
@@ -43,7 +44,12 @@ def sync_netbox(self, force_update=False):
43
44
 
44
45
  @app.task(bind=True, name="osism.tasks.conductor.sync_ironic")
45
46
  def sync_ironic(self, force_update=False):
46
- _sync_ironic(get_ironic_parameters, force_update)
47
+ _sync_ironic(self.request.id, get_ironic_parameters, force_update)
48
+
49
+
50
+ @app.task(bind=True, name="osism.tasks.conductor.sync_sonic")
51
+ def sync_sonic(self, device_name=None, show_diff=True):
52
+ return _sync_sonic(device_name, self.request.id, show_diff)
47
53
 
48
54
 
49
55
  __all__ = [
@@ -51,4 +57,5 @@ __all__ = [
51
57
  "get_ironic_parameters",
52
58
  "sync_netbox",
53
59
  "sync_ironic",
60
+ "sync_sonic",
54
61
  ]