Skip to content

Commit 121615f

Browse files
authored
Allow osism to update multiple netbox instances (#1300)
Add a parameter to the osism command to allow to specify a list of secondary netbox instances, which are also to be updated with the ironic node state. Part of osism/issues#1246 Signed-off-by: Jan Horstmann <[email protected]>
1 parent d202dac commit 121615f

File tree

3 files changed

+111
-36
lines changed

3 files changed

+111
-36
lines changed

osism/settings.py

+4
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,7 @@ def read_secret(secret_name):
3939
"OSISM_CONDUCTOR_NETBOX_FILTER_LIST",
4040
"[{'state': 'active', 'tag': ['managed-by-ironic']}]",
4141
)
42+
43+
NETBOX_SECONDARIES = (
44+
os.getenv("NETBOX_SECONDARIES", read_secret("NETBOX_SECONDARIES")) or "[]"
45+
)

osism/tasks/netbox.py

+40-24
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ def run(self, action, arguments):
2121
pass
2222

2323

24+
# NOTE: While `get_*` tasks only operate on the netbox configured in NETBOX_URL, `set_*` tasks additionally operate on all netbox instances listed in NETBOX_SECONDARIES
25+
26+
2427
@app.task(bind=True, name="osism.tasks.netbox.set_maintenance")
2528
def set_maintenance(self, device_name, state=True):
2629
"""Set the maintenance state for a device in the Netbox."""
@@ -32,14 +35,18 @@ def set_maintenance(self, device_name, state=True):
3235
)
3336
if lock.acquire(timeout=20):
3437
try:
35-
logger.info(f"Set maintenance state of device {device_name} = {state}")
36-
37-
device = utils.nb.dcim.devices.get(name=device_name)
38-
if device:
39-
device.custom_fields.update({"maintenance": state})
40-
device.save()
41-
else:
42-
logger.error(f"Could not set maintenance for {device_name}")
38+
for nb in [utils.nb] + utils.secondary_nb_list:
39+
logger.info(
40+
f"Set maintenance state of device {device_name} = {state} on {nb.base_url}"
41+
)
42+
device = nb.dcim.devices.get(name=device_name)
43+
if device:
44+
device.custom_fields.update({"maintenance": state})
45+
device.save()
46+
else:
47+
logger.error(
48+
f"Could not set maintenance for {device_name} on {nb.base_url}"
49+
)
4350
finally:
4451
lock.release()
4552
else:
@@ -57,14 +64,19 @@ def set_provision_state(self, device_name, state):
5764
)
5865
if lock.acquire(timeout=20):
5966
try:
60-
logger.info(f"Set provision state of device {device_name} = {state}")
61-
62-
device = utils.nb.dcim.devices.get(name=device_name)
63-
if device:
64-
device.custom_fields.update({"provision_state": state})
65-
device.save()
66-
else:
67-
logger.error(f"Could not set provision state for {device_name}")
67+
68+
for nb in [utils.nb] + utils.secondary_nb_list:
69+
logger.info(
70+
f"Set provision state of device {device_name} = {state} on {nb.base_url}"
71+
)
72+
device = nb.dcim.devices.get(name=device_name)
73+
if device:
74+
device.custom_fields.update({"provision_state": state})
75+
device.save()
76+
else:
77+
logger.error(
78+
f"Could not set provision state for {device_name} on {nb.base_url}"
79+
)
6880
finally:
6981
lock.release()
7082
else:
@@ -82,14 +94,18 @@ def set_power_state(self, device_name, state):
8294
)
8395
if lock.acquire(timeout=20):
8496
try:
85-
logger.info(f"Set power state of device {device_name} = {state}")
86-
87-
device = utils.nb.dcim.devices.get(name=device_name)
88-
if device:
89-
device.custom_fields.update({"power_state": state})
90-
device.save()
91-
else:
92-
logger.error(f"Could not set power state for {device_name}")
97+
for nb in [utils.nb] + utils.secondary_nb_list:
98+
logger.info(
99+
f"Set power state of device {device_name} = {state} on {nb.base_url}"
100+
)
101+
device = nb.dcim.devices.get(name=device_name)
102+
if device:
103+
device.custom_fields.update({"power_state": state})
104+
device.save()
105+
else:
106+
logger.error(
107+
f"Could not set power state for {device_name} on {nb.base_url}"
108+
)
93109
finally:
94110
lock.release()
95111
else:

osism/utils/__init__.py

+67-12
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,34 @@
11
# SPDX-License-Identifier: Apache-2.0
22

33
import keystoneauth1
4+
from loguru import logger
45
import openstack
56
import pynetbox
67
from redis import Redis
78
import urllib3
9+
import yaml
810

911
from osism import settings
1012

13+
14+
def get_netbox_connection(netbox_url, netbox_token, ignore_ssl_errors=False):
15+
if netbox_url and netbox_token:
16+
nb = pynetbox.api(netbox_url, token=netbox_token)
17+
18+
if ignore_ssl_errors and nb:
19+
import requests
20+
21+
urllib3.disable_warnings()
22+
session = requests.Session()
23+
session.verify = False
24+
nb.http_session = session
25+
26+
else:
27+
nb = None
28+
29+
return nb
30+
31+
1132
redis = Redis(
1233
host=settings.REDIS_HOST,
1334
port=settings.REDIS_PORT,
@@ -16,19 +37,53 @@
1637
)
1738
redis.ping()
1839

19-
if settings.NETBOX_URL and settings.NETBOX_TOKEN:
20-
nb = pynetbox.api(settings.NETBOX_URL, token=settings.NETBOX_TOKEN)
21-
22-
if settings.IGNORE_SSL_ERRORS and nb:
23-
import requests
24-
25-
urllib3.disable_warnings()
26-
session = requests.Session()
27-
session.verify = False
28-
nb.http_session = session
40+
nb = get_netbox_connection(
41+
settings.NETBOX_URL, settings.NETBOX_TOKEN, settings.IGNORE_SSL_ERRORS
42+
)
2943

30-
else:
31-
nb = None
44+
try:
45+
secondary_nb_settings_list = yaml.safe_load(settings.NETBOX_SECONDARIES)
46+
supported_secondary_nb_keys = ["NETBOX_URL", "NETBOX_TOKEN", "IGNORE_SSL_ERRORS"]
47+
secondary_nb_list = []
48+
if type(secondary_nb_settings_list) is not list:
49+
raise TypeError(
50+
f"Setting NETBOX_SECONDARIES needs to be an array of mappings containing supported netbox API configuration: {supported_secondary_nb_keys}"
51+
)
52+
for secondary_nb_settings in secondary_nb_settings_list:
53+
if type(secondary_nb_settings) is not dict:
54+
raise TypeError(
55+
f"Elements in setting NETBOX_SECONDARIES need to be mappings containing supported netbox API configuration: {supported_secondary_nb_keys}"
56+
)
57+
for key in list(secondary_nb_settings.keys()):
58+
if key not in supported_secondary_nb_keys:
59+
raise ValueError(
60+
f"Unknown key in element of setting NETBOX_SECONDARIES. Supported keys: {supported_secondary_nb_keys}"
61+
)
62+
if (
63+
"NETBOX_URL" not in secondary_nb_settings
64+
or not secondary_nb_settings["NETBOX_URL"]
65+
):
66+
raise ValueError(
67+
"All NETBOX_URL values in the elements of setting NETBOX_SECONDARIES need to be valid netbox URLs"
68+
)
69+
if (
70+
"NETBOX_TOKEN" not in secondary_nb_settings
71+
or not secondary_nb_settings["NETBOX_TOKEN"]
72+
):
73+
raise ValueError(
74+
"All NETBOX_TOKEN values in the elements of setting NETBOX_SECONDARIES need to be valid netbox tokens"
75+
)
76+
77+
secondary_nb_list.append(
78+
get_netbox_connection(
79+
secondary_nb_settings["NETBOX_URL"],
80+
secondary_nb_settings["NETBOX_TOKEN"],
81+
secondary_nb_settings.get("IGNORE_SSL_ERRORS", True),
82+
)
83+
)
84+
except (yaml.YAMLError, TypeError, ValueError) as exc:
85+
logger.error(f"Error parsing settings NETBOX_SECONDARIES: {exc}")
86+
secondary_nb_list = []
3287

3388

3489
def get_openstack_connection():

0 commit comments

Comments
 (0)