Skip to content

Commit a3874c6

Browse files
authored
Merge branch 'ltm-2.4' into u/smk4664-fix-vrfs
2 parents 86e5dcf + cc1a6fb commit a3874c6

File tree

13 files changed

+47
-7
lines changed

13 files changed

+47
-7
lines changed

changes/484.added

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added support for assigning a tenant to devices created by the SSOTSyncDevices job.

docs/images/sync_devices_inputs.png

100755100644
13.5 KB
Loading

docs/user/app_use_cases.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ To properly onboard a device, a user needs to provide, at a minimum:
2121
!!! note
2222
For DNS Name Resolution to work, the Celery instance of Nautobot must be able to resolve the name of the device to IP address.
2323

24-
If `Platform`, `Device Type` and/or `Role` are not provided, the plugin will try to identify this information automatically and, based on the settings, it can create them in Nautobot as needed.
24+
If `Platform`, `Device Type` and/or `Role` are not provided, the plugin will try to identify this information automatically and, based on the settings, it can create them in Nautobot as needed. Optionally, a Tenant can be selected as part of the job inputs. When provided, the tenant will be assigned to newly onboarded devices during the sync process.
2525

2626
!!! note
2727
The SSoT jobs use nornir-netmiko to run the show commands defined in the command mappers.

docs/user/app_use_cases_original.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ To properly onboard a device, a user needs to provide, at a minimum:
1414
!!! note
1515
For DNS Name Resolution to work, the instance of Nautobot must be able to resolve the name of the device to IP address.
1616

17-
If other attributes (`Platform`, `Device Type`, `Role`) are provided in the onboarding job, the app will use provided value for the onboarded device.
17+
If other attributes (`Platform`, `Device Type`, `Role`) are provided in the onboarding job, the app will use provided value for the onboarded device. Optionally, a Tenant can be selected as part of the job inputs. When provided, the tenant will be assigned to newly onboarded devices during the sync process.
1818

1919
If `Platform`, `Device Type` and/or `Role` are not provided, the plugin will try to identify this information automatically and, based on the settings, it can create them in Nautobot as needed.
2020

nautobot_device_onboarding/diffsync/adapters/sync_devices_adapters.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ def load_devices(self):
126126
primary_ip4__status__name=(device.primary_ip4.status.name if device.primary_ip4 else ""),
127127
role__name=device.role.name,
128128
status__name=device.status.name,
129+
tenant__name=device.tenant.name if device.tenant else None,
129130
secrets_group__name=(device.secrets_group.name if device.secrets_group else ""),
130131
interfaces=interfaces,
131132
mask_length=(device.primary_ip4.mask_length if device.primary_ip4 else None),
@@ -302,6 +303,7 @@ def load_devices(self):
302303
primary_ip4__status = job_form_attrs["ip_address_status"]
303304
device_role = job_form_attrs["device_role"]
304305
device_status = job_form_attrs["device_status"]
306+
device_tenant = job_form_attrs["device_tenant"]
305307
secrets_group = job_form_attrs["secrets_group"]
306308

307309
onboarding_device = self.device(
@@ -314,6 +316,7 @@ def load_devices(self):
314316
primary_ip4__status__name=primary_ip4__status.name,
315317
role__name=device_role.name,
316318
status__name=device_status.name,
319+
tenant__name=device_tenant.name if device_tenant else None,
317320
secrets_group__name=secrets_group.name,
318321
interfaces=[self.device_data[ip_address]["mgmt_interface"]],
319322
mask_length=int(self.device_data[ip_address]["mask_length"]),

nautobot_device_onboarding/diffsync/models/sync_devices_models.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from nautobot.dcim.models import Device, DeviceType, Interface, Manufacturer, Platform
99
from nautobot.extras.models import Role, SecretsGroup, Status
1010
from nautobot.ipam.models import IPAddressToInterface
11+
from nautobot.tenancy.models import Tenant
1112
from nautobot_ssot.contrib import NautobotModel
1213

1314
from nautobot_device_onboarding.utils import diffsync_utils
@@ -31,6 +32,7 @@ class SyncDevicesDevice(DiffSyncModel):
3132
"role__name",
3233
"secrets_group__name",
3334
"status__name",
35+
"tenant__name",
3436
"interfaces",
3537
)
3638

@@ -46,6 +48,7 @@ class SyncDevicesDevice(DiffSyncModel):
4648
role__name: Optional[str] = None
4749
secrets_group__name: Optional[str] = None
4850
status__name: Optional[str] = None
51+
tenant__name: Optional[str] = None
4952

5053
interfaces: Optional[list] = None
5154

@@ -85,6 +88,7 @@ def _get_or_create_device(cls, adapter, ids, attrs):
8588
device = Device(
8689
location=location,
8790
status=job_form_attrs["device_status"],
91+
tenant=job_form_attrs["device_tenant"],
8892
role=job_form_attrs["device_role"],
8993
device_type=DeviceType.objects.get(model=attrs["device_type__model"]),
9094
name=ids["name"],
@@ -228,6 +232,8 @@ def update(self, attrs):
228232
device.role = Role.objects.get(name=attrs.get("role__name"))
229233
if attrs.get("status__name"):
230234
device.status = Status.objects.get(name=attrs.get("status__name"))
235+
if attrs.get("tenant__name"):
236+
device.tenant = Tenant.objects.get(name=attrs.get("tenant__name"))
231237
if attrs.get("secrets_group__name"):
232238
device.secrets_group = SecretsGroup.objects.get(name=attrs.get("secrets_group__name"))
233239

nautobot_device_onboarding/jobs.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
Status,
3737
)
3838
from nautobot.ipam.models import Namespace
39+
from nautobot.tenancy.models import Tenant
3940
from nautobot_plugin_nornir.constants import NORNIR_SETTINGS
4041
from nautobot_ssot.jobs.base import DataSource
4142
from nornir import InitNornir
@@ -337,6 +338,11 @@ class Meta:
337338
required=False,
338339
description="Device platform. Define ONLY to override auto-recognition of platform.",
339340
)
341+
device_tenant = ObjectVar(
342+
model=Tenant,
343+
required=False,
344+
description="Tenant to be applied to all synced devices.",
345+
)
340346

341347
template_name = "nautobot_device_onboarding/ssot_sync_devices.html"
342348

@@ -398,6 +404,13 @@ def _process_csv_data(self, csv_file):
398404
device_status = Status.objects.get(
399405
name=row["device_status_name"].strip(),
400406
)
407+
if row.get("device_tenant_name"):
408+
query = f"device_tenant: {row.get('device_tenant_name')}"
409+
device_tenant = Tenant.objects.get(
410+
name=row["device_tenant_name"].strip(),
411+
)
412+
else:
413+
device_tenant = None
401414
query = f"interface_status: {row.get('interface_status_name')}"
402415
interface_status = Status.objects.get(
403416
name=row["interface_status_name"].strip(),
@@ -437,6 +450,7 @@ def _process_csv_data(self, csv_file):
437450
"update_devices_without_primary_ip": update_devices_without_primary_ip,
438451
"device_role": device_role,
439452
"device_status": device_status,
453+
"device_tenant": device_tenant,
440454
"interface_status": interface_status,
441455
"ip_address_status": ip_address_status,
442456
"secrets_group": secrets_group,
@@ -495,6 +509,7 @@ def run( # pylint: disable=too-many-positional-arguments
495509
ip_addresses=None,
496510
device_role=None,
497511
device_status=None,
512+
device_tenant=None,
498513
interface_status=None,
499514
ip_address_status=None,
500515
secrets_group=None,
@@ -541,6 +556,7 @@ def run( # pylint: disable=too-many-positional-arguments
541556
"namespace": namespace,
542557
"device_role": device_role,
543558
"device_status": device_status,
559+
"device_tenant": device_tenant,
544560
"interface_status": interface_status,
545561
"ip_address_status": ip_address_status,
546562
"set_mgmt_only": set_mgmt_only,

nautobot_device_onboarding/templates/nautobot_device_onboarding/ssot_sync_devices.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
{% block job_form %}
55

6-
{% render_form job_form excluded_fields="['location', 'namespace', 'ip_addresses', 'device_role', 'device_status', 'interface_status', 'ip_address_status', 'port', 'timeout', 'secrets_group', 'platform', 'set_mgmt_only', 'update_devices_without_primary_ip', 'csv_file']" %}
6+
{% render_form job_form excluded_fields="['location', 'namespace', 'ip_addresses', 'device_role', 'device_status', 'interface_status', 'ip_address_status', 'port', 'timeout', 'secrets_group', 'platform', 'device_tenant', 'set_mgmt_only', 'update_devices_without_primary_ip', 'csv_file']" %}
77

88
{% with csv_tab_active=form.initial.csv_input %}
99
<ul class="nav nav-tabs" role="tablist">
@@ -29,6 +29,7 @@
2929
{% render_field job_form.ip_address_status %}
3030
{% render_field job_form.secrets_group %}
3131
{% render_field job_form.platform %}
32+
{% render_field job_form.device_tenant %}
3233
</div>
3334
<div id="job_csv_input" class="tab-pane{% if csv_tab_active %} active{% endif %}">
3435
{% render_field job_form.csv_file %}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
ip_address_host,location_parent_name,location_name,namespace,port,timeout,set_mgmt_only,update_devices_without_primary_ip,device_role_name,device_status_name,interface_status_name,ip_address_status_name,secrets_group_name,platform_name
2-
10.1.1.10,Site A Parent,Site A,Global,22,30,TRUE,TRUE,Network,Active,Active,Active,test secrets group,cisco_ios
3-
10.1.1.11,Site B Parent,Site B,Global,22,30,FALSE,FALSE,Network,Active,Active,Active,test secrets group,cisco_ios
4-
10.1.1.12,,Site A Parent,Global,22,30,FALSE,FALSE,Network,Active,Active,Active,test secrets group,cisco_ios
1+
ip_address_host,location_parent_name,location_name,namespace,port,timeout,set_mgmt_only,update_devices_without_primary_ip,device_role_name,device_status_name,interface_status_name,ip_address_status_name,secrets_group_name,platform_name,device_tenant_name
2+
10.1.1.10,Site A Parent,Site A,Global,22,30,TRUE,TRUE,Network,Active,Active,Active,test secrets group,cisco_ios,Device Tenant 1
3+
10.1.1.11,Site B Parent,Site B,Global,22,30,FALSE,FALSE,Network,Active,Active,Active,test secrets group,cisco_ios,
4+
10.1.1.12,,Site A Parent,Global,22,30,FALSE,FALSE,Network,Active,Active,Active,test secrets group,cisco_ios,

nautobot_device_onboarding/tests/test_jobs.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def test_sync_devices__success(self, device_data):
5151
"update_devices_without_primary_ip": True,
5252
"device_role": self.testing_objects["device_role"].pk,
5353
"device_status": self.testing_objects["status"].pk,
54+
"device_tenant": self.testing_objects["device_tenant_1"].pk,
5455
"interface_status": self.testing_objects["status"].pk,
5556
"ip_address_status": self.testing_objects["status"].pk,
5657
"secrets_group": self.testing_objects["secrets_group"].pk,
@@ -100,6 +101,7 @@ def test_process_csv_data(self):
100101
self.assertEqual(processed_csv_data["10.1.1.10"]["update_devices_without_primary_ip"], True)
101102
self.assertEqual(processed_csv_data["10.1.1.10"]["device_role"], self.testing_objects["device_role"])
102103
self.assertEqual(processed_csv_data["10.1.1.10"]["device_status"], self.testing_objects["status"])
104+
self.assertEqual(processed_csv_data["10.1.1.10"]["device_tenant"], self.testing_objects["device_tenant_1"])
103105
self.assertEqual(processed_csv_data["10.1.1.10"]["interface_status"], self.testing_objects["status"])
104106
self.assertEqual(processed_csv_data["10.1.1.10"]["ip_address_status"], self.testing_objects["status"])
105107
self.assertEqual(processed_csv_data["10.1.1.10"]["secrets_group"], self.testing_objects["secrets_group"])

0 commit comments

Comments
 (0)