osism 0.20250219.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/actions/manage_device.py +28 -887
- osism/api.py +18 -0
- osism/commands/netbox.py +38 -327
- osism/services/listener.py +223 -133
- osism/settings.py +2 -3
- osism/tasks/__init__.py +44 -14
- osism/tasks/netbox.py +22 -98
- osism-0.20250314.0.dist-info/AUTHORS +1 -0
- {osism-0.20250219.0.dist-info → osism-0.20250314.0.dist-info}/METADATA +14 -14
- {osism-0.20250219.0.dist-info → osism-0.20250314.0.dist-info}/RECORD +15 -19
- {osism-0.20250219.0.dist-info → osism-0.20250314.0.dist-info}/WHEEL +1 -1
- {osism-0.20250219.0.dist-info → osism-0.20250314.0.dist-info}/entry_points.txt +1 -9
- osism-0.20250314.0.dist-info/pbr.json +1 -0
- osism/actions/check_configuration.py +0 -49
- osism/actions/deploy_configuration.py +0 -92
- osism/actions/diff_configuration.py +0 -59
- osism/actions/generate_configuration.py +0 -137
- osism-0.20250219.0.dist-info/AUTHORS +0 -1
- osism-0.20250219.0.dist-info/pbr.json +0 -1
- {osism-0.20250219.0.dist-info → osism-0.20250314.0.dist-info}/LICENSE +0 -0
- {osism-0.20250219.0.dist-info → osism-0.20250314.0.dist-info}/top_level.txt +0 -0
osism/services/listener.py
CHANGED
@@ -2,14 +2,18 @@
|
|
2
2
|
|
3
3
|
import os
|
4
4
|
import time
|
5
|
+
from collections.abc import Callable
|
6
|
+
from typing import Any
|
5
7
|
|
6
8
|
from kombu import Connection, Exchange, Queue
|
7
9
|
from kombu.mixins import ConsumerMixin
|
8
10
|
from loguru import logger
|
9
11
|
import json
|
12
|
+
import requests
|
10
13
|
|
11
14
|
from osism import utils
|
12
15
|
from osism.tasks import netbox, openstack
|
16
|
+
from osism import settings
|
13
17
|
|
14
18
|
EXCHANGE_NAME = "ironic"
|
15
19
|
ROUTING_KEY = "ironic_versioned_notifications.info"
|
@@ -17,168 +21,254 @@ QUEUE_NAME = "osism-listener-ironic"
|
|
17
21
|
BROKER_URI = os.getenv("BROKER_URI")
|
18
22
|
|
19
23
|
|
20
|
-
class
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
24
|
+
class BaremetalEvents:
|
25
|
+
# References:
|
26
|
+
#
|
27
|
+
# * https://docs.openstack.org/ironic/latest/admin/notifications.html#available-notifications
|
28
|
+
# * https://docs.openstack.org/ironic/latest/user/states.html
|
29
|
+
# * https://docs.openstack.org/ironic/latest/_images/states.svg
|
30
|
+
|
31
|
+
def __init__(self) -> None:
|
32
|
+
self._handler: dict[
|
33
|
+
str, dict[str, dict[str, dict[str, Callable[[dict[Any, Any]], None]]]]
|
34
|
+
] = {
|
35
|
+
"baremetal": {
|
36
|
+
"node": {
|
37
|
+
"power_set": {"end": self.node_power_set_end},
|
38
|
+
"power_state_corrected": {
|
39
|
+
"success": self.node_power_state_corrected_success
|
40
|
+
},
|
41
|
+
"maintenance_set": {"end": self.node_maintenance_set_end},
|
42
|
+
"provision_set": {
|
43
|
+
"end": self.node_provision_set_end,
|
44
|
+
"success": self.node_provision_set_success,
|
45
|
+
},
|
46
|
+
"delete": {"end": self.node_delete_end},
|
47
|
+
"create": {"end": self.node_create_end},
|
48
|
+
},
|
49
|
+
"port": {
|
50
|
+
"create": {"end": self.port_create_end},
|
51
|
+
"update": {"end": self.port_update_end},
|
52
|
+
},
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
def get_object_data(self, payload: dict[Any, Any]) -> Any:
|
57
|
+
return payload["ironic_object.data"]
|
58
|
+
|
59
|
+
def get_handler(self, event_type: str) -> Callable[[dict[Any, Any]], None]:
|
60
|
+
event_type_keys = event_type.split(".")
|
61
|
+
try:
|
62
|
+
handler = self._handler[event_type_keys[0]][event_type_keys[1]][
|
63
|
+
event_type_keys[2]
|
64
|
+
][event_type_keys[3]]
|
65
|
+
except KeyError:
|
36
66
|
|
37
|
-
|
38
|
-
|
39
|
-
|
67
|
+
def default_handler(payload: dict[Any, Any]) -> None:
|
68
|
+
object_data = self.get_object_data(payload)
|
69
|
+
name = object_data["name"]
|
70
|
+
logger.info(event_type + f" ## {name}")
|
40
71
|
|
41
|
-
|
42
|
-
|
43
|
-
object_data = payload["ironic_object.data"]
|
72
|
+
handler = default_handler
|
73
|
+
return handler
|
44
74
|
|
75
|
+
def node_power_set_end(self, payload: dict[Any, Any]) -> None:
|
76
|
+
object_data = self.get_object_data(payload)
|
45
77
|
name = object_data["name"]
|
78
|
+
logger.info(
|
79
|
+
f"baremetal.node.power_set.end ## {name} ## {object_data['power_state']}"
|
80
|
+
)
|
81
|
+
netbox.set_state.delay(name, object_data["power_state"], "power")
|
46
82
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
83
|
+
def node_power_state_corrected_success(self, payload: dict[Any, Any]) -> None:
|
84
|
+
object_data = self.get_object_data(payload)
|
85
|
+
name = object_data["name"]
|
86
|
+
logger.info(
|
87
|
+
f"baremetal.node.power_state_corrected.success ## {name} ## {object_data['power_state']}"
|
88
|
+
)
|
89
|
+
netbox.set_state.delay(name, object_data["power_state"], "power")
|
52
90
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
91
|
+
def node_maintenance_set_end(self, payload: dict[Any, Any]) -> None:
|
92
|
+
object_data = self.get_object_data(payload)
|
93
|
+
name = object_data["name"]
|
94
|
+
logger.info(
|
95
|
+
f"baremetal.node.maintenance_set.end ## {name} ## {object_data['maintenance']}"
|
96
|
+
)
|
97
|
+
netbox.set_maintenance.delay(name, object_data["maintenance"])
|
58
98
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
99
|
+
def node_provision_set_success(self, payload: dict[Any, Any]) -> None:
|
100
|
+
# A provision status was successfully set, update it in the netbox
|
101
|
+
object_data = self.get_object_data(payload)
|
102
|
+
name = object_data["name"]
|
103
|
+
logger.info(
|
104
|
+
f"baremetal.node.provision_set.success ## {name} ## {object_data['provision_state']}"
|
105
|
+
)
|
106
|
+
netbox.set_state.delay(name, object_data["provision_state"], "provision")
|
64
107
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
108
|
+
def node_provision_set_end(self, payload: dict[Any, Any]) -> None:
|
109
|
+
object_data = self.get_object_data(payload)
|
110
|
+
name = object_data["name"]
|
111
|
+
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")
|
70
115
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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")
|
75
122
|
|
76
|
-
|
77
|
-
|
78
|
-
|
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']}")
|
79
127
|
|
80
|
-
|
81
|
-
|
82
|
-
|
128
|
+
mac_address = object_data["address"]
|
129
|
+
interface_a = utils.nb.dcim.interfaces.get(mac_address=mac_address)
|
130
|
+
device_a = interface_a.device
|
83
131
|
|
84
|
-
|
85
|
-
|
86
|
-
|
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()
|
87
137
|
|
88
|
-
|
89
|
-
|
138
|
+
netbox.update_network_interface_name.delay(
|
139
|
+
object_data["address"], network_interface_name
|
140
|
+
)
|
90
141
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
)
|
96
|
-
netbox.set_state.delay(name, object_data["provision_state"], "provision")
|
142
|
+
def port_update_end(self, payload: dict[Any, Any]) -> None:
|
143
|
+
object_data = self.get_object_data(payload)
|
144
|
+
name = object_data["name"]
|
145
|
+
logger.info(f"baremetal.port.update.end ## {object_data['uuid']}")
|
97
146
|
|
98
|
-
|
99
|
-
|
100
|
-
|
147
|
+
mac_address = object_data["address"]
|
148
|
+
interface_a = utils.nb.dcim.interfaces.get(mac_address=mac_address)
|
149
|
+
device_a = interface_a.device
|
101
150
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
if (
|
109
|
-
object_data["previous_provision_state"] == "inspect wait"
|
110
|
-
and object_data["event"] == "done"
|
111
|
-
):
|
112
|
-
netbox.set_state.delay(name, "introspected", "introspection")
|
113
|
-
openstack.baremetal_set_node_provision_state.delay(name, "provide")
|
114
|
-
|
115
|
-
elif object_data["previous_provision_state"] == "wait call-back":
|
116
|
-
pass
|
117
|
-
|
118
|
-
elif (
|
119
|
-
object_data["previous_provision_state"] == "cleaning"
|
120
|
-
and object_data["provision_state"] == "available"
|
121
|
-
): # noqa
|
122
|
-
# system should be in state c
|
123
|
-
netbox.connect.delay(name, "c")
|
124
|
-
|
125
|
-
elif event_type == "baremetal.port.create.end":
|
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()
|
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()
|
137
156
|
|
138
|
-
|
139
|
-
|
140
|
-
|
157
|
+
netbox.update_network_interface_name.delay(
|
158
|
+
object_data["address"], network_interface_name
|
159
|
+
)
|
141
160
|
|
142
|
-
|
143
|
-
|
161
|
+
def node_delete_end(self, payload: dict[Any, Any]) -> None:
|
162
|
+
object_data = self.get_object_data(payload)
|
163
|
+
name = object_data["name"]
|
164
|
+
logger.info(f"baremetal.node.delete.end ## {name}")
|
144
165
|
|
145
|
-
|
146
|
-
|
147
|
-
|
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")
|
148
171
|
|
149
|
-
|
150
|
-
|
151
|
-
)
|
152
|
-
task.wait(timeout=None, interval=0.5)
|
153
|
-
network_interface_name = task.get()
|
172
|
+
# remove internal flavor
|
173
|
+
openstack.baremetal_delete_internal_flavor.delay(name)
|
154
174
|
|
155
|
-
|
156
|
-
|
157
|
-
|
175
|
+
def node_create_end(self, payload: dict[Any, Any]) -> None:
|
176
|
+
object_data = self.get_object_data(payload)
|
177
|
+
name = object_data["name"]
|
178
|
+
logger.info(f"baremetal.node.create.end ## {name}")
|
179
|
+
netbox.set_state.delay(name, "registered", "ironic")
|
158
180
|
|
159
|
-
elif event_type == "baremetal.node.delete.end":
|
160
|
-
logger.info(f"baremetal.node.delete.end ## {name}")
|
161
181
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
182
|
+
class NotificationsDump(ConsumerMixin):
|
183
|
+
def __init__(self, connection):
|
184
|
+
self.connection = connection
|
185
|
+
self.baremetal_events = BaremetalEvents()
|
186
|
+
self.osism_api_session: None | requests.Session = None
|
187
|
+
self.osism_baremetal_api_url: None | str = None
|
188
|
+
if settings.OSISM_API_URL:
|
189
|
+
logger.info("Setting up OSISM API")
|
190
|
+
self.osism_api_session = requests.Session()
|
191
|
+
self.osism_baremetal_api_url = (
|
192
|
+
settings.OSISM_API_URL.rstrip("/") + "/notifications/baremetal"
|
193
|
+
)
|
194
|
+
return
|
167
195
|
|
168
|
-
|
169
|
-
|
196
|
+
def get_consumers(self, consumer, channel):
|
197
|
+
exchange = Exchange(EXCHANGE_NAME, type="topic", durable=False)
|
198
|
+
queue = Queue(
|
199
|
+
QUEUE_NAME,
|
200
|
+
exchange,
|
201
|
+
routing_key=ROUTING_KEY,
|
202
|
+
durable=False,
|
203
|
+
auto_delete=True,
|
204
|
+
no_ack=True,
|
205
|
+
)
|
206
|
+
return [consumer(queue, callbacks=[self.on_message])]
|
170
207
|
|
171
|
-
|
172
|
-
|
208
|
+
def on_message(self, body, message):
|
209
|
+
data = json.loads(body["oslo.message"])
|
210
|
+
# logger.info(data)
|
173
211
|
|
174
|
-
|
175
|
-
|
176
|
-
|
212
|
+
if self.osism_api_session:
|
213
|
+
tries = 1
|
214
|
+
max_tries = 3
|
215
|
+
while tries <= max_tries:
|
216
|
+
logger.info(
|
217
|
+
f"Trying to deliver notification to {self.osism_baremetal_api_url} (Try: {tries}/{max_tries})\n"
|
218
|
+
)
|
219
|
+
try:
|
220
|
+
response = self.osism_api_session.post(
|
221
|
+
self.osism_baremetal_api_url,
|
222
|
+
timeout=5,
|
223
|
+
json=dict(
|
224
|
+
priority=data["priority"],
|
225
|
+
event_type=data["event_type"],
|
226
|
+
timestamp=data["timestamp"],
|
227
|
+
publisher_id=data["publisher_id"],
|
228
|
+
message_id=data["message_id"],
|
229
|
+
payload=data["payload"],
|
230
|
+
),
|
231
|
+
)
|
232
|
+
if response.status_code == 204:
|
233
|
+
logger.info(
|
234
|
+
f"Successfully delivered notification to {self.osism_baremetal_api_url} (Try: {tries}/{max_tries})"
|
235
|
+
)
|
236
|
+
break
|
237
|
+
else:
|
238
|
+
response.raise_for_status()
|
239
|
+
except requests.ConnectionError:
|
240
|
+
logger.error(f"Error connecting to {self.osism_baremetal_api_url}")
|
241
|
+
except requests.Timeout:
|
242
|
+
logger.error(
|
243
|
+
f"Timeout reached while connecting to {self.osism_baremetal_api_url}"
|
244
|
+
)
|
245
|
+
except requests.HTTPError as e:
|
246
|
+
logger.error(
|
247
|
+
f"Received HTTP status code {e.response.status_code} while connecting to {self.osism_baremetal_api_url}"
|
248
|
+
)
|
249
|
+
if e.response.status_code <= 500:
|
250
|
+
logger.error(
|
251
|
+
f"Received HTTP status code {e.response.status_code} indicates a client side error, giving up early"
|
252
|
+
)
|
253
|
+
break
|
254
|
+
|
255
|
+
logger.error(
|
256
|
+
f"Failed to deliver notification to {self.osism_baremetal_api_url} ({tries}/{max_tries})"
|
257
|
+
)
|
258
|
+
tries += 1
|
259
|
+
if tries > max_tries:
|
260
|
+
logger.error(
|
261
|
+
f"Giving up delivering notification to {self.osism_baremetal_api_url} with data:\n"
|
262
|
+
+ json.dumps(data)
|
263
|
+
)
|
264
|
+
else:
|
265
|
+
time.sleep(pow(3, tries - 1))
|
177
266
|
|
178
267
|
else:
|
179
|
-
|
268
|
+
handler = self.baremetal_events.get_handler(data["event_type"])
|
269
|
+
handler(data["payload"])
|
180
270
|
|
181
|
-
logger.info(
|
271
|
+
logger.info(self.baremetal_events.get_object_data(data["payload"]))
|
182
272
|
|
183
273
|
|
184
274
|
def main():
|
osism/settings.py
CHANGED
@@ -27,11 +27,10 @@ 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(
|
36
33
|
os.getenv("INVENTORY_RECONCILER_SCHEDULE", "600.0")
|
37
34
|
)
|
35
|
+
|
36
|
+
OSISM_API_URL = os.getenv("OSISM_API_URL", None)
|
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/netbox.py
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
# SPDX-License-Identifier: Apache-2.0
|
2
2
|
|
3
|
-
import os
|
4
|
-
import subprocess
|
5
|
-
|
6
3
|
from celery import Celery
|
7
4
|
from celery.signals import worker_process_init
|
8
5
|
import json
|
@@ -10,15 +7,8 @@ import pynetbox
|
|
10
7
|
from redis import Redis
|
11
8
|
|
12
9
|
from osism import settings
|
13
|
-
from osism.actions import
|
14
|
-
|
15
|
-
deploy_configuration,
|
16
|
-
diff_configuration,
|
17
|
-
generate_configuration,
|
18
|
-
manage_device,
|
19
|
-
manage_interface,
|
20
|
-
)
|
21
|
-
from osism.tasks import Config, openstack
|
10
|
+
from osism.actions import manage_device, manage_interface
|
11
|
+
from osism.tasks import Config, openstack, run_command
|
22
12
|
|
23
13
|
app = Celery("netbox")
|
24
14
|
app.config_from_object(Config)
|
@@ -73,35 +63,6 @@ def update_network_interface_name(self, mac_address, network_interface_name):
|
|
73
63
|
manage_interface.update_network_interface_name(mac_address, network_interface_name)
|
74
64
|
|
75
65
|
|
76
|
-
@app.task(bind=True, name="osism.tasks.netbox.import_device_types")
|
77
|
-
def import_device_types(self, vendors, library=False):
|
78
|
-
global redis
|
79
|
-
|
80
|
-
if library:
|
81
|
-
env = {**os.environ, "BASE_PATH": "/devicetype-library/device-types/"}
|
82
|
-
else:
|
83
|
-
env = {**os.environ, "BASE_PATH": "/netbox/device-types/"}
|
84
|
-
|
85
|
-
if vendors:
|
86
|
-
p = subprocess.Popen(
|
87
|
-
f"python3 /import/main.py --vendors {vendors}",
|
88
|
-
shell=True,
|
89
|
-
stdout=subprocess.PIPE,
|
90
|
-
stderr=subprocess.STDOUT,
|
91
|
-
env=env,
|
92
|
-
)
|
93
|
-
else:
|
94
|
-
p = subprocess.Popen(
|
95
|
-
"python3 /import/main.py",
|
96
|
-
shell=True,
|
97
|
-
stdout=subprocess.PIPE,
|
98
|
-
stderr=subprocess.STDOUT,
|
99
|
-
env=env,
|
100
|
-
)
|
101
|
-
|
102
|
-
p.communicate()
|
103
|
-
|
104
|
-
|
105
66
|
@app.task(bind=True, name="osism.tasks.netbox.synchronize_device_state")
|
106
67
|
def synchronize_device_state(self, data):
|
107
68
|
"""Synchronize the state of Ironic with Netbox"""
|
@@ -123,23 +84,6 @@ def states(self, data):
|
|
123
84
|
return result
|
124
85
|
|
125
86
|
|
126
|
-
@app.task(bind=True, name="osism.tasks.netbox.transitions")
|
127
|
-
def transitions(self, data):
|
128
|
-
result = manage_device.get_transitions(data.keys())
|
129
|
-
return result
|
130
|
-
|
131
|
-
|
132
|
-
@app.task(bind=True, name="osism.tasks.netbox.data")
|
133
|
-
def data(self, collection, device, state):
|
134
|
-
result = manage_device.load_data_from_filesystem(collection, device, state)
|
135
|
-
return result
|
136
|
-
|
137
|
-
|
138
|
-
@app.task(bind=True, name="osism.tasks.netbox.connect")
|
139
|
-
def connect(self, device=None, state=None, data={}, enforce=False):
|
140
|
-
manage_device.run(device, state, data, enforce)
|
141
|
-
|
142
|
-
|
143
87
|
@app.task(bind=True, name="osism.tasks.netbox.set_state")
|
144
88
|
def set_state(self, device=None, state=None, state_type=None):
|
145
89
|
manage_device.set_state(device, state, state_type)
|
@@ -150,47 +94,7 @@ def set_maintenance(self, device=None, state=None):
|
|
150
94
|
manage_device.set_maintenance(device, state)
|
151
95
|
|
152
96
|
|
153
|
-
@app.task(bind=True, name="osism.tasks.netbox.disable")
|
154
|
-
def disable(self, name):
|
155
|
-
global nb
|
156
|
-
|
157
|
-
for interface in nb.dcim.interfaces.filter(device=name):
|
158
|
-
if str(interface.type) in ["Virtual"]:
|
159
|
-
continue
|
160
|
-
|
161
|
-
if "Port-Channel" in interface.name:
|
162
|
-
continue
|
163
|
-
|
164
|
-
if not interface.connected_endpoint and interface.enabled:
|
165
|
-
interface.enabled = False
|
166
|
-
interface.save()
|
167
|
-
|
168
|
-
# FIXME: only enable devices that are not disabled by configuration
|
169
|
-
if interface.connected_endpoint and not interface.enabled:
|
170
|
-
interface.enabled = True
|
171
|
-
interface.save()
|
172
|
-
|
173
|
-
|
174
|
-
@app.task(bind=True, name="osism.tasks.netbox.generate")
|
175
|
-
def generate(self, name, template=None):
|
176
|
-
generate_configuration.for_device(name, template)
|
177
|
-
|
178
|
-
|
179
|
-
@app.task(bind=True, name="osism.tasks.netbox.deploy")
|
180
|
-
def deploy(self, name):
|
181
|
-
deploy_configuration.for_device(name)
|
182
|
-
|
183
|
-
|
184
|
-
@app.task(bind=True, name="osism.tasks.netbox.check")
|
185
|
-
def check(self, name):
|
186
|
-
check_configuration.for_device(name)
|
187
|
-
|
188
|
-
|
189
97
|
@app.task(bind=True, name="osism.tasks.netbox.diff")
|
190
|
-
def diff(self, name):
|
191
|
-
diff_configuration.for_device(name)
|
192
|
-
|
193
|
-
|
194
98
|
@app.task(bind=True, name="osism.tasks.netbox.get_devices_not_yet_registered_in_ironic")
|
195
99
|
def get_devices_not_yet_registered_in_ironic(
|
196
100
|
self, status="active", tags=["managed-by-ironic"], ironic_enabled=True
|
@@ -238,6 +142,26 @@ def get_devices_that_should_have_an_allocation_in_ironic(self):
|
|
238
142
|
return result
|
239
143
|
|
240
144
|
|
145
|
+
@app.task(bind=True, name="osism.tasks.netbox.manage")
|
146
|
+
def manage(self, *arguments, publish=True, locking=False, auto_release_time=3600):
|
147
|
+
netbox_manager_env = {
|
148
|
+
"NETBOX_MANAGER_URL": str(settings.NETBOX_URL),
|
149
|
+
"NETBOX_MANAGER_TOKEN": str(settings.NETBOX_TOKEN),
|
150
|
+
"NETBOX_MANAGER_IGNORE_SSL_ERRORS": str(settings.IGNORE_SSL_ERRORS),
|
151
|
+
"NETBOX_MANAGER_VERBOSE": "true",
|
152
|
+
}
|
153
|
+
|
154
|
+
return run_command(
|
155
|
+
self.request.id,
|
156
|
+
"/usr/local/bin/netbox-manager",
|
157
|
+
netbox_manager_env,
|
158
|
+
*arguments,
|
159
|
+
publish=publish,
|
160
|
+
locking=locking,
|
161
|
+
auto_release_time=auto_release_time
|
162
|
+
)
|
163
|
+
|
164
|
+
|
241
165
|
@app.task(bind=True, name="osism.tasks.netbox.ping")
|
242
166
|
def ping(self):
|
243
167
|
global nb
|
@@ -0,0 +1 @@
|
|
1
|
+
janhorstmann <horstmann@osism.tech>
|