osism 0.20250525.0__py3-none-any.whl → 0.20250530.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.
@@ -0,0 +1,237 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ from cliff.command import Command
4
+
5
+ from loguru import logger
6
+ import openstack
7
+ from tabulate import tabulate
8
+ import json
9
+
10
+ from osism.commands import get_cloud_connection
11
+
12
+
13
+ class BaremetalList(Command):
14
+ def get_parser(self, prog_name):
15
+ parser = super(BaremetalList, self).get_parser(prog_name)
16
+ parser.add_argument(
17
+ "--provision-state",
18
+ default=None,
19
+ choices=["enroll", "managable", "available", "active", "error"],
20
+ type=str,
21
+ help="Only list nodes with the given provision state",
22
+ )
23
+ parser.add_argument(
24
+ "--maintenance",
25
+ default=False,
26
+ action="store_true",
27
+ help="Only list baremetal nodes in maintenance mode",
28
+ )
29
+ return parser
30
+
31
+ def take_action(self, parsed_args):
32
+ provision_state = parsed_args.provision_state
33
+ maintenance = parsed_args.maintenance
34
+
35
+ conn = get_cloud_connection()
36
+
37
+ query = {}
38
+ if provision_state:
39
+ query.update(dict(provision_state=provision_state))
40
+ if maintenance:
41
+ query.update(dict(maintenance=maintenance))
42
+
43
+ baremetal = conn.baremetal.nodes(**query)
44
+
45
+ result = [
46
+ [
47
+ b["name"],
48
+ b["power_state"],
49
+ b["provision_state"],
50
+ b["maintenance"],
51
+ ]
52
+ for b in baremetal
53
+ ]
54
+
55
+ print(
56
+ tabulate(
57
+ result,
58
+ headers=[
59
+ "Name",
60
+ "Power State",
61
+ "Provision State",
62
+ "Maintenance",
63
+ ],
64
+ tablefmt="psql",
65
+ )
66
+ )
67
+
68
+
69
+ class BaremetalDeploy(Command):
70
+ def get_parser(self, prog_name):
71
+ parser = super(BaremetalDeploy, self).get_parser(prog_name)
72
+
73
+ parser_exc_group = parser.add_mutually_exclusive_group(required=True)
74
+ parser_exc_group.add_argument(
75
+ "--all",
76
+ default=False,
77
+ help="Deploy all baremetal nodes in provision state available",
78
+ action="store_true",
79
+ )
80
+ parser_exc_group.add_argument(
81
+ "--name",
82
+ default=[],
83
+ help="Deploy given baremetal node when in provision state available. May be specified multiple times",
84
+ action="append",
85
+ )
86
+ parser.add_argument(
87
+ "--rebuild",
88
+ default=False,
89
+ help="Rebuild given nodes in active state",
90
+ action="store_true",
91
+ )
92
+ parser.add_argument(
93
+ "--yes-i-really-really-mean-it",
94
+ default=False,
95
+ help="Specify this in connection with '--rebuild --all' to actually rebuild all nodes",
96
+ action="store_true",
97
+ )
98
+ return parser
99
+
100
+ def take_action(self, parsed_args):
101
+ all_nodes = parsed_args.all
102
+ names = parsed_args.name
103
+ rebuild = parsed_args.rebuild
104
+ yes_i_really_really_mean_it = parsed_args.yes_i_really_really_mean_it
105
+
106
+ if all_nodes and rebuild and not yes_i_really_really_mean_it:
107
+ logger.error(
108
+ "Please confirm that you wish to rebuild all nodes by specifying '--yes-i-really-really-mean-it'"
109
+ )
110
+ return
111
+
112
+ conn = get_cloud_connection()
113
+
114
+ if all_nodes:
115
+ deploy_nodes = list(conn.baremetal.nodes(details=True))
116
+ else:
117
+ deploy_nodes = [
118
+ conn.baremetal.find_node(name, ignore_missing=True, details=True)
119
+ for name in names
120
+ ]
121
+
122
+ for node_idx, node in enumerate(deploy_nodes):
123
+ if not node:
124
+ logger.warning(f"Could not find node {names[node_idx]}")
125
+ continue
126
+
127
+ if node.provision_state in ["available", "deploy failed"]:
128
+ provision_state = "active"
129
+ elif (
130
+ node.provision_state == "error"
131
+ or node.provision_state == "active"
132
+ and rebuild
133
+ ):
134
+ provision_state = "rebuild"
135
+ else:
136
+ logger.warning(
137
+ f"Node {node.name} ({node.id}) not in supported provision state"
138
+ )
139
+ continue
140
+
141
+ try:
142
+ conn.baremetal.validate_node(
143
+ node.id, required=("boot", "deploy", "power")
144
+ )
145
+ except openstack.exceptions.ValidationException:
146
+ logger.warning(f"Node {node.name} ({node.id}) could not be validated")
147
+ continue
148
+ try:
149
+ config_drive = {"meta_data": {}}
150
+ if (
151
+ "netplan_parameters" in node.extra
152
+ and node.extra["netplan_parameters"]
153
+ ):
154
+ config_drive["meta_data"].update(
155
+ {
156
+ "netplan_parameters": json.loads(
157
+ node.extra["netplan_parameters"]
158
+ )
159
+ }
160
+ )
161
+ if "frr_parameters" in node.extra and node.extra["frr_parameters"]:
162
+ config_drive["meta_data"].update(
163
+ {"frr_parameters": json.loads(node.extra["frr_parameters"])}
164
+ )
165
+ conn.baremetal.set_node_provision_state(
166
+ node.id, provision_state, config_drive=config_drive
167
+ )
168
+ except Exception as exc:
169
+ logger.warning(
170
+ f"Node {node.name} ({node.id}) could not be moved to active state: {exc}"
171
+ )
172
+ continue
173
+
174
+
175
+ class BaremetalUndeploy(Command):
176
+ def get_parser(self, prog_name):
177
+ parser = super(BaremetalUndeploy, self).get_parser(prog_name)
178
+
179
+ parser_exc_group = parser.add_mutually_exclusive_group(required=True)
180
+ parser_exc_group.add_argument(
181
+ "--all",
182
+ default=False,
183
+ help="Undeploy all baremetal nodes",
184
+ action="store_true",
185
+ )
186
+ parser_exc_group.add_argument(
187
+ "--name",
188
+ default=[],
189
+ help="Undeploy given baremetal node. May be specified multiple times",
190
+ action="append",
191
+ )
192
+ parser.add_argument(
193
+ "--yes-i-really-really-mean-it",
194
+ default=False,
195
+ help="Specify this to actually undeploy all nodes",
196
+ action="store_true",
197
+ )
198
+ return parser
199
+
200
+ def take_action(self, parsed_args):
201
+ all_nodes = parsed_args.all
202
+ names = parsed_args.name
203
+ yes_i_really_really_mean_it = parsed_args.yes_i_really_really_mean_it
204
+
205
+ if all_nodes and not yes_i_really_really_mean_it:
206
+ logger.error(
207
+ "Please confirm that you wish to undeploy all nodes by specifying '--yes-i-really-really-mean-it'"
208
+ )
209
+ return
210
+
211
+ conn = get_cloud_connection()
212
+
213
+ if all_nodes:
214
+ deploy_nodes = list(conn.baremetal.nodes())
215
+ else:
216
+ deploy_nodes = [
217
+ conn.baremetal.find_node(name, ignore_missing=True, details=False)
218
+ for name in names
219
+ ]
220
+
221
+ for node_idx, node in enumerate(deploy_nodes):
222
+ if not node:
223
+ logger.warning(f"Could not find node {names[node_idx]}")
224
+ continue
225
+
226
+ if node.provision_state in ["active", "deploy failed", "error"]:
227
+ try:
228
+ conn.baremetal.set_node_provision_state(node.id, "undeploy")
229
+ except Exception as exc:
230
+ logger.warning(
231
+ f"Node {node.name} ({node.id}) could not be moved to available state: {exc}"
232
+ )
233
+ continue
234
+ else:
235
+ logger.warning(
236
+ f"Node {node.name} ({node.id}) not in supported provision state"
237
+ )
osism/commands/netbox.py CHANGED
@@ -106,7 +106,7 @@ class Manage(Command):
106
106
 
107
107
  def take_action(self, parsed_args):
108
108
  wait = not parsed_args.no_wait
109
- arguments = []
109
+ arguments = ["run"]
110
110
 
111
111
  if parsed_args.no_netbox_wait:
112
112
  arguments.append("--no-wait")
osism/tasks/conductor.py CHANGED
@@ -10,6 +10,7 @@ import jinja2
10
10
  from loguru import logger
11
11
  from pottery import Redlock
12
12
  import yaml
13
+ import json
13
14
 
14
15
  from osism import settings
15
16
  from osism import utils
@@ -305,6 +306,27 @@ def sync_ironic(self, force_update=False):
305
306
  )
306
307
  )
307
308
  node_attributes.update({"resource_class": device.name})
309
+ # NOTE: Write metadata used for provisioning into 'extra' field, so that it is available during node deploy without querying the netbox again
310
+ if "extra" not in node_attributes:
311
+ node_attributes["extra"] = {}
312
+ if (
313
+ "netplan_parameters" in device.custom_fields
314
+ and device.custom_fields["netplan_parameters"]
315
+ ):
316
+ node_attributes["extra"].update(
317
+ {
318
+ "netplan_parameters": json.dumps(
319
+ device.custom_fields["netplan_parameters"]
320
+ )
321
+ }
322
+ )
323
+ if (
324
+ "frr_parameters" in device.custom_fields
325
+ and device.custom_fields["frr_parameters"]
326
+ ):
327
+ node_attributes["extra"].update(
328
+ {"frr_parameters": json.dumps(device.custom_fields["frr_parameters"])}
329
+ )
308
330
  ports_attributes = [
309
331
  dict(address=interface.mac_address)
310
332
  for interface in node_interfaces
osism/tasks/netbox.py CHANGED
@@ -151,6 +151,11 @@ def get_interfaces_by_device(self, device_name):
151
151
  return utils.nb.dcim.interfaces.filter(device=device_name)
152
152
 
153
153
 
154
+ @app.task(bind=True, name="osism.tasks.netbox.get_addresses_by_device_and_interface")
155
+ def get_addresses_by_device_and_interface(self, device_name, interface_name):
156
+ return utils.nb.dcim.addresses.filter(device=device_name, interface=interface_name)
157
+
158
+
154
159
  @app.task(bind=True, name="osism.tasks.netbox.manage")
155
160
  def manage(self, *arguments, publish=True, locking=False, auto_release_time=3600):
156
161
  netbox_manager_env = {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: osism
3
- Version: 0.20250525.0
3
+ Version: 0.20250530.0
4
4
  Summary: OSISM manager interface
5
5
  Home-page: https://github.com/osism/python-osism
6
6
  Author: OSISM GmbH
@@ -48,7 +48,7 @@ Requires-Dist: prompt-toolkit==3.0.51
48
48
  Requires-Dist: pynetbox==7.5.0
49
49
  Requires-Dist: pytest-testinfra==10.2.2
50
50
  Requires-Dist: python-dateutil==2.9.0.post0
51
- Requires-Dist: setuptools==80.8.0
51
+ Requires-Dist: setuptools==80.9.0
52
52
  Requires-Dist: sqlmodel==0.0.24
53
53
  Requires-Dist: sushy==5.6.0
54
54
  Requires-Dist: tabulate==0.9.0
@@ -6,6 +6,7 @@ osism/settings.py,sha256=mkvbxVQ64ZD7Ypk-bRePHn0gZ5j6Lcu2a578eLU0gQs,1309
6
6
  osism/actions/__init__.py,sha256=bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E,38
7
7
  osism/commands/__init__.py,sha256=Ag4wX_DCgXRdoLn6t069jqb3DdRylsX2nyYkiyCx4uk,456
8
8
  osism/commands/apply.py,sha256=mH3-NctgevVzP_1IW92FQeiYMCPB49K5hXbxmTY2vnA,16795
9
+ osism/commands/baremetal.py,sha256=EDLorDkt3iUblIZb-Fn6fonnMewVEOyrLBTlfxuQ2tc,8043
9
10
  osism/commands/compose.py,sha256=iqzG7mS9E1VWaLNN6yQowjOqiHn3BMdj-yfXb3Dc4Ok,1200
10
11
  osism/commands/compute.py,sha256=cgqXWJa5wAvn-7e3FWCgX6hie_aK0yrKRkcNzjLXwDY,25799
11
12
  osism/commands/configuration.py,sha256=sPe8b0dVKFRbr30xoeVdAnHbGwCwgUh0xa_Vzv5pSQQ,954
@@ -14,7 +15,7 @@ osism/commands/container.py,sha256=Fku2GaCM3Idq_FxExUtNqjrEM0XYjpVvXmueSVO8S_c,1
14
15
  osism/commands/get.py,sha256=ryytjtXWmlMV0NucP5tGkMZu0nIlC4xVtjRk4iMZ06c,8967
15
16
  osism/commands/log.py,sha256=2IpYuosC7FZwwLvM8HmKSU1NRNIelVVYzqjjVMCrOJk,4072
16
17
  osism/commands/manage.py,sha256=WxUZEhylZj2IhydAe3BAr3S5ED6opG243skfSq5q41s,11971
17
- osism/commands/netbox.py,sha256=70GjyPYSVH6dOYwEx1vuF5y9CtEE4vOiH_UNSYuqpjc,6646
18
+ osism/commands/netbox.py,sha256=PagHlAwEyzKzhrqi4nikkD8sjnVqAzzbDt8PVkl2j9k,6651
18
19
  osism/commands/noset.py,sha256=7zDFuFMyNpo7DUOKcNiYV8nodtdMOYFp5LDPcuJhlZ8,1481
19
20
  osism/commands/reconciler.py,sha256=xOyPzQj66xwjdQd2ysCTHX2yBvmMVMppUDZTas6voXc,2882
20
21
  osism/commands/server.py,sha256=avmoOv5rjOi-fN2A-27cPwOtiy2Q2j6UFtCh3QrfWAI,7512
@@ -38,18 +39,18 @@ osism/services/listener.py,sha256=eEamlQsJqCuU9K2QFmk3yM9LAJZEanVcTLtGMsNCKjs,97
38
39
  osism/tasks/__init__.py,sha256=ZEu_KYsapTYp0etr-rLqie_NT_LndHDDpx53xITru5Y,8691
39
40
  osism/tasks/ansible.py,sha256=_2zrHwynwwEv9nDnX-LbNCzcwy9dTUGo_yyutt34HyQ,1346
40
41
  osism/tasks/ceph.py,sha256=eIQkah3Kj4INtOkF9kTjHbXJ3_J2lg48EWJKfHc-UYw,615
41
- osism/tasks/conductor.py,sha256=nUaP9lQyfqKbtt--uDVbyiJMbmNx_vI7lYqYzSbLH4E,19599
42
+ osism/tasks/conductor.py,sha256=okLlmuSsJpmu6zQOR_dXX0LMQI1xFBlHRm76qB6txRk,20502
42
43
  osism/tasks/kolla.py,sha256=wJQpWn_01iWLkr7l7T7RNrQGfRgsgmYi4WQlTmNGvew,618
43
44
  osism/tasks/kubernetes.py,sha256=VzXq_VrYU_CLm4cOruqnE3Kq2ydfO9glZ3p0bp3OYoc,625
44
- osism/tasks/netbox.py,sha256=QVOLiTH2Su237YAS0QfXbQ86E-OA1JzrFDfyi9JBmvk,5658
45
+ osism/tasks/netbox.py,sha256=Dq2hg2yiv_dHV-zygJgy9T1ZhTSE32_a34fhfURUfTA,5912
45
46
  osism/tasks/openstack.py,sha256=g15tCll5vP1pC6ysxRCTZxplsdGmXbxaCH3k1Qdv5Xg,6367
46
47
  osism/tasks/reconciler.py,sha256=tnZEZZpveBCK4vHZkHE6wDcHfJAlsPcSjIVxB5ItSFM,1981
47
48
  osism/utils/__init__.py,sha256=_Y4qchR5yyI_JKhBWd_jcsvDLYZjxO0c3iMA_VRQl58,4304
48
- osism-0.20250525.0.dist-info/licenses/AUTHORS,sha256=EKFIR9F27AvoEXp1cA6FkGbjEOFt4Rcbipr5RJc7jSs,64
49
- osism-0.20250525.0.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
50
- osism-0.20250525.0.dist-info/METADATA,sha256=fLU5Yf-qJPuZHU_QTKcNWqzKUjISG7yOVM9qKonpO2A,2903
51
- osism-0.20250525.0.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
52
- osism-0.20250525.0.dist-info/entry_points.txt,sha256=NR2buBhAPM7jc94gdtM_-kEwSIBz0l9x0nUg3fElybc,3051
53
- osism-0.20250525.0.dist-info/pbr.json,sha256=xuXy9_UHMyU8zzNeRX1aaXpOYUbOci-0c7GrNIbGlmE,47
54
- osism-0.20250525.0.dist-info/top_level.txt,sha256=8L8dsI9hcaGHsdnR4k_LN9EM78EhwrXRFHyAryPXZtY,6
55
- osism-0.20250525.0.dist-info/RECORD,,
49
+ osism-0.20250530.0.dist-info/licenses/AUTHORS,sha256=EKFIR9F27AvoEXp1cA6FkGbjEOFt4Rcbipr5RJc7jSs,64
50
+ osism-0.20250530.0.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
51
+ osism-0.20250530.0.dist-info/METADATA,sha256=p5ZH0PS7XC8iz2s-FFeGy10nd93NDinuBAS-YXCmPu4,2903
52
+ osism-0.20250530.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
53
+ osism-0.20250530.0.dist-info/entry_points.txt,sha256=cTxzUWJff6JKe1Jv-iMMKayIiC26S1_Fph3k5faiQvw,3252
54
+ osism-0.20250530.0.dist-info/pbr.json,sha256=3Gdc4g_dd2jHbkHZk28onO59wzLpSeDVrRWZwOrw3Wk,47
55
+ osism-0.20250530.0.dist-info/top_level.txt,sha256=8L8dsI9hcaGHsdnR4k_LN9EM78EhwrXRFHyAryPXZtY,6
56
+ osism-0.20250530.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -26,6 +26,9 @@ log ansible = osism.commands.log:Ansible
26
26
  log container = osism.commands.log:Container
27
27
  log file = osism.commands.log:File
28
28
  log opensearch = osism.commands.log:Opensearch
29
+ manage baremetal deploy = osism.commands.baremetal:BaremetalDeploy
30
+ manage baremetal list = osism.commands.baremetal:BaremetalList
31
+ manage baremetal undeploy = osism.commands.baremetal:BaremetalUndeploy
29
32
  manage compute disable = osism.commands.compute:ComputeDisable
30
33
  manage compute enable = osism.commands.compute:ComputeEnable
31
34
  manage compute evacuate = osism.commands.compute:ComputeEvacuate
@@ -0,0 +1 @@
1
+ {"git_version": "424407f", "is_release": false}
@@ -1 +0,0 @@
1
- {"git_version": "3c67308", "is_release": false}