osism 0.20250312.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/commands/netbox.py +38 -327
- osism/services/listener.py +0 -40
- osism/settings.py +0 -3
- osism/tasks/__init__.py +44 -14
- osism/tasks/netbox.py +22 -98
- {osism-0.20250312.0.dist-info → osism-0.20250314.0.dist-info}/METADATA +4 -4
- {osism-0.20250312.0.dist-info → osism-0.20250314.0.dist-info}/RECORD +14 -18
- {osism-0.20250312.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.20250312.0.dist-info/pbr.json +0 -1
- {osism-0.20250312.0.dist-info → osism-0.20250314.0.dist-info}/AUTHORS +0 -0
- {osism-0.20250312.0.dist-info → osism-0.20250314.0.dist-info}/LICENSE +0 -0
- {osism-0.20250312.0.dist-info → osism-0.20250314.0.dist-info}/WHEEL +0 -0
- {osism-0.20250312.0.dist-info → osism-0.20250314.0.dist-info}/top_level.txt +0 -0
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
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: osism
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.20250314.0
|
4
4
|
Summary: OSISM manager interface
|
5
5
|
Home-page: https://github.com/osism/python-osism
|
6
6
|
Author: OSISM GmbH
|
@@ -37,13 +37,13 @@ Requires-Dist: flower==2.0.1
|
|
37
37
|
Requires-Dist: hiredis==3.1.0
|
38
38
|
Requires-Dist: jc==1.25.4
|
39
39
|
Requires-Dist: keystoneauth1==5.10.0
|
40
|
-
Requires-Dist: kombu==5.
|
40
|
+
Requires-Dist: kombu==5.5.0
|
41
41
|
Requires-Dist: kubernetes==32.0.1
|
42
42
|
Requires-Dist: loguru==0.7.3
|
43
43
|
Requires-Dist: netmiko==4.5.0
|
44
44
|
Requires-Dist: nornir-ansible==2023.12.28
|
45
45
|
Requires-Dist: nornir==3.5.0
|
46
|
-
Requires-Dist: openstacksdk==4.
|
46
|
+
Requires-Dist: openstacksdk==4.4.0
|
47
47
|
Requires-Dist: pottery==3.0.0
|
48
48
|
Requires-Dist: prompt-toolkit==3.0.50
|
49
49
|
Requires-Dist: pydantic==1.10.21
|
@@ -61,7 +61,7 @@ Provides-Extra: ansible
|
|
61
61
|
Requires-Dist: ansible-runner==2.4.0; extra == "ansible"
|
62
62
|
Requires-Dist: ansible-core==2.18.3; extra == "ansible"
|
63
63
|
Provides-Extra: openstack-image-manager
|
64
|
-
Requires-Dist: openstack-image-manager==0.
|
64
|
+
Requires-Dist: openstack-image-manager==0.20250314.0; extra == "openstack-image-manager"
|
65
65
|
Dynamic: author
|
66
66
|
Dynamic: author-email
|
67
67
|
Dynamic: classifier
|
@@ -2,13 +2,9 @@ osism/__init__.py,sha256=1UiNTBus0V0f2AbZQzAtVtu6zkfCCrw0OTq--NwFAqY,341
|
|
2
2
|
osism/__main__.py,sha256=ILe4gu61xEISiBsxanqTQIdSkV-YhpZXTRlguCYyssk,141
|
3
3
|
osism/api.py,sha256=X3IVLWbKMtfozJ5sEx6sLEZ1rD4U9s3uNnLLwxiwDjs,4802
|
4
4
|
osism/main.py,sha256=Dt2-9sLXcS-Ny4DAz7hrha-KRc7zd7BFUTRdfs_X8z4,893
|
5
|
-
osism/settings.py,sha256=
|
5
|
+
osism/settings.py,sha256=m__DltxKQo5D-vDKKwY8RNBVs5bverYdJmtyVyln_6o,1049
|
6
6
|
osism/actions/__init__.py,sha256=bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E,38
|
7
|
-
osism/actions/
|
8
|
-
osism/actions/deploy_configuration.py,sha256=uHrW6J0908zloK3SnOcKq3m53H8KCihplU1IA10mZMA,2712
|
9
|
-
osism/actions/diff_configuration.py,sha256=sGoUPQWxINE_qqqBgePxOtEOXgtMFRM43TGJtGFFwhs,1513
|
10
|
-
osism/actions/generate_configuration.py,sha256=eAv1IfKYMw3466rStHB1HXHVksM0wn4CrHjZDfTgV40,4391
|
11
|
-
osism/actions/manage_device.py,sha256=VXrRRcu78i05QjmN3t3vdeF1OoMAE7oYUaSyK0aJOjo,37457
|
7
|
+
osism/actions/manage_device.py,sha256=joQwPnwEUw5V1ZRRbdrM0FjfNlG4vPNc0r8FBRTOJiA,3541
|
12
8
|
osism/actions/manage_interface.py,sha256=iDp7zY16XXtwdLk1sxa-TBAkpdPxmtbVeEvMZuP5h4s,472
|
13
9
|
osism/commands/__init__.py,sha256=Ag4wX_DCgXRdoLn6t069jqb3DdRylsX2nyYkiyCx4uk,456
|
14
10
|
osism/commands/apply.py,sha256=n3lLb1cS3GahQqRT0723di98hg47MjVzDzkAoeZX7qU,16780
|
@@ -20,7 +16,7 @@ osism/commands/container.py,sha256=Fku2GaCM3Idq_FxExUtNqjrEM0XYjpVvXmueSVO8S_c,1
|
|
20
16
|
osism/commands/get.py,sha256=ryytjtXWmlMV0NucP5tGkMZu0nIlC4xVtjRk4iMZ06c,8967
|
21
17
|
osism/commands/log.py,sha256=2IpYuosC7FZwwLvM8HmKSU1NRNIelVVYzqjjVMCrOJk,4072
|
22
18
|
osism/commands/manage.py,sha256=HGU1VPU7rBJ2oYfaAbg2IzjRjOYatVNRv1gUUDFgEqk,9690
|
23
|
-
osism/commands/netbox.py,sha256=
|
19
|
+
osism/commands/netbox.py,sha256=OJiNAdMObIt2ffc7C80eLRjwqZmD4lgidQ8I8VWtF8s,4900
|
24
20
|
osism/commands/noset.py,sha256=7zDFuFMyNpo7DUOKcNiYV8nodtdMOYFp5LDPcuJhlZ8,1481
|
25
21
|
osism/commands/reconciler.py,sha256=Ja_b86gX6-_Pr3DmrUUvskmEnnJpHQ-XJNQLycMJeyc,2818
|
26
22
|
osism/commands/server.py,sha256=zFXRdYoj4ZNDJNPSaGddMPEWxt8G2GyMomPOcCOaN3c,4137
|
@@ -40,22 +36,22 @@ osism/core/playbooks.py,sha256=M3T3ajV-8Lt-orsRO3jAoukhaoYFr4EZ2dzYXQjt1kg,728
|
|
40
36
|
osism/data/__init__.py,sha256=izXdh0J3vPLQI7kBhJI7ibJQzPqU_nlONP0L4Cf_k6A,1504
|
41
37
|
osism/plugins/__init__.py,sha256=bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E,38
|
42
38
|
osism/services/__init__.py,sha256=bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E,38
|
43
|
-
osism/services/listener.py,sha256
|
44
|
-
osism/tasks/__init__.py,sha256=
|
39
|
+
osism/services/listener.py,sha256=JjCdwPG5U9b_xYDpGFQeiLPP4y00GM3Me6NW1tt6Jws,11275
|
40
|
+
osism/tasks/__init__.py,sha256=qZQGMeaaeUN9CUBqVXGEx2pvDZpDJbhudq0jl4-7GRU,9111
|
45
41
|
osism/tasks/ansible.py,sha256=0c5nY1M0jf_9Me8HMP2Je_Ibjii4rFm-5HW8tmE6aos,1681
|
46
42
|
osism/tasks/ceph.py,sha256=eIQkah3Kj4INtOkF9kTjHbXJ3_J2lg48EWJKfHc-UYw,615
|
47
43
|
osism/tasks/conductor.py,sha256=g9ulqWlGim0DjwQkVgW8Tl8MsXBGuukuQvM12CXbEmM,3892
|
48
44
|
osism/tasks/kolla.py,sha256=wJQpWn_01iWLkr7l7T7RNrQGfRgsgmYi4WQlTmNGvew,618
|
49
45
|
osism/tasks/kubernetes.py,sha256=VzXq_VrYU_CLm4cOruqnE3Kq2ydfO9glZ3p0bp3OYoc,625
|
50
|
-
osism/tasks/netbox.py,sha256=
|
46
|
+
osism/tasks/netbox.py,sha256=yR8z6VYkNXmNCsHzxP6KGmPtGW5mbpLks8XEw6TUwjk,4692
|
51
47
|
osism/tasks/openstack.py,sha256=i9dIVz9RPVC38gIhUPIE0oq8Wj2ppf9bHrHLTrsjaJ8,9098
|
52
48
|
osism/tasks/reconciler.py,sha256=RpepZtRgBgYTwmAkfuT9kIaxU1ITDb8SFalMoShdRNQ,3547
|
53
49
|
osism/utils/__init__.py,sha256=5yng8l5Jd6GhNO4FNi6iYH4569UuTYAynamANgZnm1E,1258
|
54
|
-
osism-0.
|
55
|
-
osism-0.
|
56
|
-
osism-0.
|
57
|
-
osism-0.
|
58
|
-
osism-0.
|
59
|
-
osism-0.
|
60
|
-
osism-0.
|
61
|
-
osism-0.
|
50
|
+
osism-0.20250314.0.dist-info/AUTHORS,sha256=DJIRsjyrFxKjFvmpUNDRDBS04nRiJ5B6FpKcDcfnoGM,36
|
51
|
+
osism-0.20250314.0.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
52
|
+
osism-0.20250314.0.dist-info/METADATA,sha256=9Yv6LRSN9ZDCXQN5U4KpHrZZK7j7hW4NIJcP11nKO58,2950
|
53
|
+
osism-0.20250314.0.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
|
54
|
+
osism-0.20250314.0.dist-info/entry_points.txt,sha256=8yx03jRhfk45lMfGV8t4tZ2Xp95puuj8LEnx9Ogjefc,3050
|
55
|
+
osism-0.20250314.0.dist-info/pbr.json,sha256=Wlz72FgMvVrweUm0EjV2XpPxCiO9BCUCpb61UvKTyBc,47
|
56
|
+
osism-0.20250314.0.dist-info/top_level.txt,sha256=8L8dsI9hcaGHsdnR4k_LN9EM78EhwrXRFHyAryPXZtY,6
|
57
|
+
osism-0.20250314.0.dist-info/RECORD,,
|
@@ -36,19 +36,11 @@ manage flavors = osism.commands.manage:Flavors
|
|
36
36
|
manage image clusterapi = osism.commands.manage:ImageClusterapi
|
37
37
|
manage image octavia = osism.commands.manage:ImageOctavia
|
38
38
|
manage images = osism.commands.manage:Images
|
39
|
+
manage netbox = osism.commands.netbox:Manage
|
39
40
|
manage server list = osism.commands.server:ServerList
|
40
41
|
manage server migrate = osism.commands.server:ServerMigrate
|
41
42
|
manage volume list = osism.commands.volume:VolumeList
|
42
43
|
netbox = osism.commands.netbox:Run
|
43
|
-
netbox check = osism.commands.netbox:Check
|
44
|
-
netbox connect = osism.commands.netbox:Connect
|
45
|
-
netbox deploy = osism.commands.netbox:Deploy
|
46
|
-
netbox diff = osism.commands.netbox:Diff
|
47
|
-
netbox disable = osism.commands.netbox:Disable
|
48
|
-
netbox generate = osism.commands.netbox:Generate
|
49
|
-
netbox import = osism.commands.netbox:Import
|
50
|
-
netbox init = osism.commands.netbox:Init
|
51
|
-
netbox manage = osism.commands.netbox:Manage
|
52
44
|
netbox ping = osism.commands.netbox:Ping
|
53
45
|
netbox sync = osism.commands.netbox:Sync
|
54
46
|
netbox sync ironic = osism.commands.netbox:Ironic
|
@@ -0,0 +1 @@
|
|
1
|
+
{"git_version": "73a2ae0", "is_release": false}
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# SPDX-License-Identifier: Apache-2.0
|
2
|
-
|
3
|
-
from loguru import logger
|
4
|
-
from pottery import Redlock
|
5
|
-
|
6
|
-
from osism import utils
|
7
|
-
|
8
|
-
|
9
|
-
def for_device(name, parameters={}):
|
10
|
-
device = utils.nb.dcim.devices.get(name=name)
|
11
|
-
|
12
|
-
if (
|
13
|
-
"device_type" not in device.custom_fields
|
14
|
-
or device.custom_fields["device_type"] != "switch"
|
15
|
-
):
|
16
|
-
return
|
17
|
-
|
18
|
-
if "Managed by OSISM" not in [str(x) for x in device.tags]:
|
19
|
-
return
|
20
|
-
|
21
|
-
if "deployment_enabled" in device.custom_fields and not bool(
|
22
|
-
device.custom_fields["deployment_enabled"]
|
23
|
-
):
|
24
|
-
return
|
25
|
-
|
26
|
-
if "deployment_type" not in device.custom_fields:
|
27
|
-
return
|
28
|
-
|
29
|
-
# Allow only one change per time
|
30
|
-
lock = Redlock(
|
31
|
-
key=f"lock_check_{name}", masters={utils.redis}, auto_release_time=120
|
32
|
-
)
|
33
|
-
lock.acquire()
|
34
|
-
|
35
|
-
logger.info(
|
36
|
-
f"Check configuration for device {device.name} with plugin {device.custom_fields['deployment_type']}"
|
37
|
-
)
|
38
|
-
|
39
|
-
deployment_type = device.custom_fields["deployment_type"]
|
40
|
-
logger.error(
|
41
|
-
f"Deployment type {deployment_type} for device {device.name} not supported"
|
42
|
-
)
|
43
|
-
last_configuration = None
|
44
|
-
|
45
|
-
if last_configuration:
|
46
|
-
for line in last_configuration.split("\n"):
|
47
|
-
logger.info(f"configuration - {device.name}: {line}")
|
48
|
-
|
49
|
-
lock.release()
|
@@ -1,92 +0,0 @@
|
|
1
|
-
# SPDX-License-Identifier: Apache-2.0
|
2
|
-
|
3
|
-
from loguru import logger
|
4
|
-
from pottery import Redlock
|
5
|
-
import git
|
6
|
-
import jinja2
|
7
|
-
|
8
|
-
from osism import utils
|
9
|
-
|
10
|
-
|
11
|
-
def for_device(name, parameters={}, mode="deploy"):
|
12
|
-
device = utils.nb.dcim.devices.get(name=name)
|
13
|
-
|
14
|
-
if (
|
15
|
-
"device_type" not in device.custom_fields
|
16
|
-
or device.custom_fields["device_type"] != "switch"
|
17
|
-
):
|
18
|
-
return
|
19
|
-
|
20
|
-
if "Managed by OSISM" not in [str(x) for x in device.tags]:
|
21
|
-
return
|
22
|
-
|
23
|
-
if "deployment_enabled" in device.custom_fields and not bool(
|
24
|
-
device.custom_fields["deployment_enabled"]
|
25
|
-
):
|
26
|
-
return
|
27
|
-
|
28
|
-
if "deployment_type" not in device.custom_fields:
|
29
|
-
return
|
30
|
-
|
31
|
-
# Allow only one change per time
|
32
|
-
lock = Redlock(
|
33
|
-
key=f"lock_deploy_{name}", masters={utils.redis}, auto_release_time=120
|
34
|
-
)
|
35
|
-
lock.acquire()
|
36
|
-
|
37
|
-
repo = git.Repo.init(path="/state")
|
38
|
-
|
39
|
-
first = False
|
40
|
-
|
41
|
-
if device.name in repo.tags:
|
42
|
-
last_commit = repo.commit(device.name)
|
43
|
-
current_commit = repo.head.commit
|
44
|
-
else:
|
45
|
-
first = True
|
46
|
-
last_commit = repo.head.commit
|
47
|
-
current_commit = repo.head.commit
|
48
|
-
|
49
|
-
if device.name in repo.tags and mode == "deploy":
|
50
|
-
repo.delete_tag(name)
|
51
|
-
|
52
|
-
if not first and last_commit == current_commit and mode == "deploy":
|
53
|
-
logger.info(f"No deployment for device {device.name} required")
|
54
|
-
else:
|
55
|
-
if not first:
|
56
|
-
try:
|
57
|
-
last_configuration = repo.git.show(
|
58
|
-
f"{last_commit.hexsha}:{device.name}.cfg.j2"
|
59
|
-
)
|
60
|
-
except git.exc.GitCommandError:
|
61
|
-
last_configuration = None
|
62
|
-
else:
|
63
|
-
last_configuration = None
|
64
|
-
|
65
|
-
try:
|
66
|
-
current_configuration = repo.git.show(
|
67
|
-
f"{current_commit.hexsha}:{device.name}.cfg.j2"
|
68
|
-
)
|
69
|
-
except git.exc.GitCommandError:
|
70
|
-
current_configuration = None
|
71
|
-
|
72
|
-
if not current_configuration:
|
73
|
-
logger.error(f"There is no prepared configuration for device {device.name}")
|
74
|
-
else:
|
75
|
-
t = jinja2.Environment(loader=jinja2.BaseLoader()).from_string(
|
76
|
-
current_configuration
|
77
|
-
)
|
78
|
-
rendered_current_configuration = t.render(**parameters)
|
79
|
-
|
80
|
-
logger.info(
|
81
|
-
f"{mode} configuration for device {device.name} with plugin {device.custom_fields['deployment_type']}"
|
82
|
-
)
|
83
|
-
|
84
|
-
deployment_type = device.custom_fields["deployment_type"]
|
85
|
-
logger.error(
|
86
|
-
f"Deployment type {deployment_type} for device {device.name} not supported"
|
87
|
-
)
|
88
|
-
|
89
|
-
if mode == "deploy":
|
90
|
-
repo.create_tag(device.name, current_commit)
|
91
|
-
|
92
|
-
lock.release()
|
@@ -1,59 +0,0 @@
|
|
1
|
-
# SPDX-License-Identifier: Apache-2.0
|
2
|
-
|
3
|
-
from loguru import logger
|
4
|
-
import git
|
5
|
-
from pottery import Redlock
|
6
|
-
|
7
|
-
from osism import utils
|
8
|
-
|
9
|
-
|
10
|
-
def for_device(name, parameters={}):
|
11
|
-
device = utils.nb.dcim.devices.get(name=name)
|
12
|
-
|
13
|
-
if (
|
14
|
-
"device_type" not in device.custom_fields
|
15
|
-
or device.custom_fields["device_type"] != "switch"
|
16
|
-
):
|
17
|
-
return
|
18
|
-
|
19
|
-
if "Managed by OSISM" not in [str(x) for x in device.tags]:
|
20
|
-
return
|
21
|
-
|
22
|
-
if "deployment_enabled" in device.custom_fields and not bool(
|
23
|
-
device.custom_fields["deployment_enabled"]
|
24
|
-
):
|
25
|
-
return
|
26
|
-
|
27
|
-
if "deployment_type" not in device.custom_fields:
|
28
|
-
return
|
29
|
-
|
30
|
-
# Allow only one change per time
|
31
|
-
lock = Redlock(
|
32
|
-
key=f"lock_diff_{name}", masters={utils.redis}, auto_release_time=120
|
33
|
-
)
|
34
|
-
lock.acquire()
|
35
|
-
|
36
|
-
logger.info(
|
37
|
-
f"Diff configuration for device {device.name} with plugin {device.custom_fields['deployment_type']}"
|
38
|
-
)
|
39
|
-
|
40
|
-
deployment_type = device.custom_fields["deployment_type"]
|
41
|
-
logger.error(
|
42
|
-
f"Deployment type {deployment_type} for device {device.name} not supported"
|
43
|
-
)
|
44
|
-
current_configuration = None
|
45
|
-
|
46
|
-
repo = git.Repo.init(path="/state")
|
47
|
-
|
48
|
-
try:
|
49
|
-
last_configuration = repo.git.show(
|
50
|
-
f"{repo.head.commit.hexsha}:{device.name}.cfg.j2"
|
51
|
-
)
|
52
|
-
except git.exc.GitCommandError:
|
53
|
-
last_configuration = None
|
54
|
-
|
55
|
-
logger.error(
|
56
|
-
f"Deployment type {deployment_type} for device {device.name} not supported"
|
57
|
-
)
|
58
|
-
|
59
|
-
lock.release()
|
@@ -1,137 +0,0 @@
|
|
1
|
-
# SPDX-License-Identifier: Apache-2.0
|
2
|
-
|
3
|
-
from datetime import datetime
|
4
|
-
import ipaddress
|
5
|
-
import os
|
6
|
-
|
7
|
-
from loguru import logger
|
8
|
-
import git
|
9
|
-
import gitdb
|
10
|
-
import jinja2
|
11
|
-
from pottery import Redlock
|
12
|
-
|
13
|
-
from osism.utils import first
|
14
|
-
from osism import utils
|
15
|
-
|
16
|
-
|
17
|
-
def vlans_as_string(untagged_vlan, tagged_vlans):
|
18
|
-
vlans = [str(x.vid) for x in tagged_vlans]
|
19
|
-
if untagged_vlan:
|
20
|
-
vlans = vlans + [str(untagged_vlan.vid)]
|
21
|
-
return ",".join(sorted(vlans))
|
22
|
-
|
23
|
-
|
24
|
-
def for_device(name, template=None):
|
25
|
-
device = utils.nb.dcim.devices.get(name=name)
|
26
|
-
|
27
|
-
if (
|
28
|
-
"device_type" not in device.custom_fields
|
29
|
-
or device.custom_fields["device_type"] != "switch"
|
30
|
-
):
|
31
|
-
return
|
32
|
-
|
33
|
-
if "Managed by OSISM" not in [str(x) for x in device.tags]:
|
34
|
-
return
|
35
|
-
|
36
|
-
logger.info(f"Generate configuration for device {device.name}")
|
37
|
-
|
38
|
-
if not template:
|
39
|
-
template = f"{device.name}.cfg.j2"
|
40
|
-
|
41
|
-
if not os.path.isfile(f"/netbox/templates/{template}"):
|
42
|
-
template = f"{device.device_type.manufacturer.name}.cfg.j2"
|
43
|
-
|
44
|
-
if not os.path.isfile(f"/netbox/templates/{template}"):
|
45
|
-
template = "default.cfg.j2"
|
46
|
-
|
47
|
-
vlans = utils.nb.ipam.vlans.filter(available_on_device=device.id)
|
48
|
-
interfaces = utils.nb.dcim.interfaces.filter(device=device)
|
49
|
-
|
50
|
-
interfaces_ethernet = []
|
51
|
-
interfaces_port_channels = []
|
52
|
-
interfaces_virtual = []
|
53
|
-
|
54
|
-
for interface in interfaces:
|
55
|
-
if str(interface.type) == "Link Aggregation Group (LAG)":
|
56
|
-
interfaces_port_channels.append(interface)
|
57
|
-
elif str(interface.type) == "Virtual":
|
58
|
-
interfaces_virtual.append(interface)
|
59
|
-
else:
|
60
|
-
interfaces_ethernet.append(interface)
|
61
|
-
|
62
|
-
# Port-Channel10 + Vlan4094 are always used as MLAG
|
63
|
-
try:
|
64
|
-
mlag = utils.nb.dcim.interfaces.get(device=device, name="Port-Channel10")
|
65
|
-
mlag_vlan = utils.nb.dcim.interfaces.get(device=device, name="Vlan4094")
|
66
|
-
mlag_address = utils.nb.ipam.ip_addresses.get(
|
67
|
-
device=device, interface="Vlan4094"
|
68
|
-
)
|
69
|
-
except: # noqa
|
70
|
-
mlag = None
|
71
|
-
mlag_vlan = None
|
72
|
-
mlag_address = None
|
73
|
-
|
74
|
-
# NOTE: only work with /30
|
75
|
-
try:
|
76
|
-
x = list(ipaddress.ip_interface(mlag_address.address).network.hosts())
|
77
|
-
x.remove(ipaddress.ip_interface(mlag_address.address).ip)
|
78
|
-
mlag_peer_address = x[0]
|
79
|
-
except: # noqa
|
80
|
-
mlag_peer_address = None
|
81
|
-
|
82
|
-
try:
|
83
|
-
mlag_domain_id = device.name.split("-")[1]
|
84
|
-
except: # noqa
|
85
|
-
mlag_domain_id = None
|
86
|
-
|
87
|
-
repo = git.Repo.init(path="/state")
|
88
|
-
repo.config_writer().set_value("user", "name", "Netbox Generator").release()
|
89
|
-
repo.config_writer().set_value(
|
90
|
-
"user", "email", "netbox-generator@reconciler.local"
|
91
|
-
).release()
|
92
|
-
|
93
|
-
data = {
|
94
|
-
"hostname": device.name,
|
95
|
-
"interfaces_ethernet": interfaces_ethernet,
|
96
|
-
"interfaces_virtual": interfaces_virtual,
|
97
|
-
"interfaces_port_channels": interfaces_port_channels,
|
98
|
-
"vlans": vlans,
|
99
|
-
"device": name,
|
100
|
-
"nb": utils.nb,
|
101
|
-
"first": first,
|
102
|
-
"vlans_as_string": vlans_as_string,
|
103
|
-
"mlag": mlag,
|
104
|
-
"mlag_vlan": mlag_vlan,
|
105
|
-
"mlag_peer_address": mlag_peer_address,
|
106
|
-
"mlag_domain_id": mlag_domain_id,
|
107
|
-
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
108
|
-
"device_type": device.device_type.model,
|
109
|
-
"device_manufacturer": device.device_type.manufacturer.name,
|
110
|
-
}
|
111
|
-
|
112
|
-
loader = jinja2.FileSystemLoader(searchpath="/netbox/templates/")
|
113
|
-
environment = jinja2.Environment(loader=loader)
|
114
|
-
template = environment.get_template(template)
|
115
|
-
result = template.render(data)
|
116
|
-
|
117
|
-
logger.info(f"Writing generated configuration to /state/{device.name}.cfg.j2")
|
118
|
-
with open(f"/state/{device.name}.cfg.j2", "w+") as fp:
|
119
|
-
fp.write(os.linesep.join([s for s in result.splitlines() if s]))
|
120
|
-
|
121
|
-
# Allow only one change per time
|
122
|
-
lock = Redlock(key="lock_repository", masters={utils.redis})
|
123
|
-
lock.acquire()
|
124
|
-
|
125
|
-
repo.git.add(f"/state/{device.name}.cfg.j2")
|
126
|
-
|
127
|
-
try:
|
128
|
-
if len(repo.index.diff("HEAD")) > 0:
|
129
|
-
logger.info(f"Committing changes in /state/{device.name}.cfg.j2")
|
130
|
-
repo.git.commit(message=f"Update {device.name}")
|
131
|
-
|
132
|
-
# Ref 'HEAD' did not resolve to an object
|
133
|
-
except gitdb.exc.BadName:
|
134
|
-
logger.info("Initial commit")
|
135
|
-
repo.git.commit(message="Initial commit")
|
136
|
-
|
137
|
-
lock.release()
|
@@ -1 +0,0 @@
|
|
1
|
-
{"git_version": "314593e", "is_release": false}
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|