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/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
- check_configuration,
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.20250312.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.4.2
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.2.0
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.20241216.0; extra == "openstack-image-manager"
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=cv0vxsBNinCUAfAXANuQ1-W3YIRv6BWWwcdO5Y6HGko,1165
5
+ osism/settings.py,sha256=m__DltxKQo5D-vDKKwY8RNBVs5bverYdJmtyVyln_6o,1049
6
6
  osism/actions/__init__.py,sha256=bG7Ffen4LvQtgnYPFEpFccsWs81t4zqqeqn9ZeirH6E,38
7
- osism/actions/check_configuration.py,sha256=f_nwMsMh9G1z8tmxSoDGyWoFtI1NLVWks70fknY5st0,1301
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=k3wxekbTY79pbLabe0s8qxZ2FfNK_OnoFbXlfVkThjU,14245
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=-oknzaroJxpWzaeilkJnyxNUj_EF1q7zJGAexMP0YVY,12695
44
- osism/tasks/__init__.py,sha256=DHV40JwT0gSQrpjgT6AtxO-HBxBm1fexRNGUqbmFQZU,8556
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=a2g0iwuODCbptzjBXtwHNUpSpQxQRF9wCGE8JBZWVO0,6596
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.20250312.0.dist-info/AUTHORS,sha256=DJIRsjyrFxKjFvmpUNDRDBS04nRiJ5B6FpKcDcfnoGM,36
55
- osism-0.20250312.0.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
56
- osism-0.20250312.0.dist-info/METADATA,sha256=_PV0PsInCReaFHooi_DST5yYtlATeDgas34bajssFZ8,2950
57
- osism-0.20250312.0.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
58
- osism-0.20250312.0.dist-info/entry_points.txt,sha256=Hjy0x6duRr78IEPd2oHi-P0LWWIe85zgX9DwovKYNbM,3408
59
- osism-0.20250312.0.dist-info/pbr.json,sha256=GBO14uGezrRoQuN7HmabA-K5ph_U6W95Po1XXDzI-zU,47
60
- osism-0.20250312.0.dist-info/top_level.txt,sha256=8L8dsI9hcaGHsdnR4k_LN9EM78EhwrXRFHyAryPXZtY,6
61
- osism-0.20250312.0.dist-info/RECORD,,
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}