Skip to content

Commit b756b2c

Browse files
authored
Add site_group to netbox_inventory (#755)
* add site_group to netbox_inventory
1 parent 48c7b5e commit b756b2c

File tree

50 files changed

+544
-95
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+544
-95
lines changed

plugins/inventory/nb_inventory.py

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@
160160
- platforms
161161
- platform
162162
- region
163+
- site_group
163164
- cluster
164165
- cluster_type
165166
- cluster_group
@@ -469,6 +470,7 @@ def group_extractors(self):
469470
"local_context_data": self.extract_local_context_data,
470471
"custom_fields": self.extract_custom_fields,
471472
"region": self.extract_regions,
473+
"site_group": self.extract_site_groups,
472474
"cluster": self.extract_cluster,
473475
"cluster_group": self.extract_cluster_group,
474476
"cluster_type": self.extract_cluster_type,
@@ -799,6 +801,29 @@ def extract_regions(self, host):
799801
object_parent_lookup=self.regions_parent_lookup,
800802
)
801803

804+
def extract_site_groups(self, host):
805+
# A host may have a site. A site may have a site_group. A site_group may have a parent site_group.
806+
# Produce a list of site_groups:
807+
# - it will be empty if the device has no site, or the site has no site_group set
808+
# - it will have 1 element if the site's site_group has no parent
809+
# - it will have multiple elements if the site's site_group has a parent site_group
810+
811+
site = host.get("site", None)
812+
if not isinstance(site, dict):
813+
# Device has no site
814+
return []
815+
816+
site_id = site.get("id", None)
817+
if site_id is None:
818+
# Device has no site
819+
return []
820+
821+
return self._objects_array_following_parents(
822+
initial_object_id=self.sites_site_group_lookup[site_id],
823+
object_lookup=self.site_groups_lookup,
824+
object_parent_lookup=self.site_groups_parent_lookup,
825+
)
826+
802827
def extract_location(self, host):
803828
# A host may have a location. A location may have a parent location.
804829
# Produce a list of locations:
@@ -904,6 +929,16 @@ def get_region_for_site(site):
904929
# Dictionary of site id to region id
905930
self.sites_region_lookup = dict(map(get_region_for_site, sites))
906931

932+
def get_site_group_for_site(site):
933+
# Will fail if site does not have a site_group defined in NetBox
934+
try:
935+
return (site["id"], site["group"]["id"])
936+
except Exception:
937+
return (site["id"], None)
938+
939+
# Dictionary of site id to site_group id
940+
self.sites_site_group_lookup = dict(map(get_site_group_for_site, sites))
941+
907942
# Note: depends on the result of refresh_sites_lookup for self.sites_with_prefixes
908943
def refresh_prefixes(self):
909944
# Pull all prefixes defined in NetBox
@@ -943,6 +978,25 @@ def get_region_parent(region):
943978
filter(lambda x: x is not None, map(get_region_parent, regions))
944979
)
945980

981+
def refresh_site_groups_lookup(self):
982+
url = self.api_endpoint + "/api/dcim/site-groups/?limit=0"
983+
site_groups = self.get_resource_list(api_url=url)
984+
self.site_groups_lookup = dict(
985+
(site_group["id"], site_group["slug"]) for site_group in site_groups
986+
)
987+
988+
def get_site_group_parent(site_group):
989+
# Will fail if site_group does not have a parent site_group
990+
try:
991+
return (site_group["id"], site_group["parent"]["id"])
992+
except Exception:
993+
return (site_group["id"], None)
994+
995+
# Dictionary of site_group id to parent site_group id
996+
self.site_groups_parent_lookup = dict(
997+
filter(lambda x: x is not None, map(get_site_group_parent, site_groups))
998+
)
999+
9461000
def refresh_locations_lookup(self):
9471001
# Locations were added in v2.11. Return empty lookups for previous versions.
9481002
if self.api_version < version.parse("2.11"):
@@ -1234,6 +1288,7 @@ def lookup_processes(self):
12341288
lookups = [
12351289
self.refresh_sites_lookup,
12361290
self.refresh_regions_lookup,
1291+
self.refresh_site_groups_lookup,
12371292
self.refresh_locations_lookup,
12381293
self.refresh_tenants_lookup,
12391294
self.refresh_device_roles_lookup,
@@ -1505,7 +1560,7 @@ def add_host_to_groups(self, host, hostname):
15051560

15061561
# Don't handle regions here since no hosts are ever added to region groups
15071562
# Sites and locations are also specially handled in the main()
1508-
if grouping in ["region", site_group_by, "location"]:
1563+
if grouping in ["region", site_group_by, "location", "site_group"]:
15091564
continue
15101565

15111566
if grouping not in self.group_extractors:
@@ -1572,6 +1627,23 @@ def _add_region_groups(self):
15721627
self.site_group_names[site_id],
15731628
)
15741629

1630+
def _add_site_group_groups(self):
1631+
# Mapping of site_group id to group name
1632+
site_group_transformed_group_names = self._setup_nested_groups(
1633+
"site_group", self.site_groups_lookup, self.site_groups_parent_lookup
1634+
)
1635+
1636+
# Add site groups as children of site_group groups
1637+
for site_id in self.sites_lookup:
1638+
site_group_id = self.sites_site_group_lookup.get(site_id, None)
1639+
if site_group_id is None:
1640+
continue
1641+
1642+
self.inventory.add_child(
1643+
site_group_transformed_group_names[site_group_id],
1644+
self.site_group_names[site_id],
1645+
)
1646+
15751647
def _add_location_groups(self):
15761648
# Mapping of location id to group name
15771649
self.location_group_names = self._setup_nested_groups(
@@ -1646,6 +1718,9 @@ def _fill_host_variables(self, host, hostname):
16461718
if attribute == "region":
16471719
attribute = "regions"
16481720

1721+
if attribute == "site_group":
1722+
attribute = "site_groups"
1723+
16491724
if attribute == "location":
16501725
attribute = "locations"
16511726

@@ -1702,6 +1777,7 @@ def main(self):
17021777
site_group_by in self.group_by
17031778
or "location" in self.group_by
17041779
or "region" in self.group_by
1780+
or "site_group" in self.group_by
17051781
):
17061782
self._add_site_groups()
17071783

@@ -1713,6 +1789,10 @@ def main(self):
17131789
if "region" in self.group_by:
17141790
self._add_region_groups()
17151791

1792+
# Create groups for site_groups, containing the site groups
1793+
if "site_group" in self.group_by:
1794+
self._add_site_group_groups()
1795+
17161796
for host in chain(self.devices_list, self.vms_list):
17171797

17181798
virtual_chassis_master = self._get_host_virtual_chassis_master(host)

tests/integration/netbox-deploy.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,20 @@ def make_netbox_calls(endpoint, payload):
8585
test_region.parent = parent_region
8686
test_region.save()
8787

88+
## Create site_groups
89+
site_groups = [
90+
{"name": "Test site_group", "slug": "test-site_group"},
91+
{"name": "Parent site_group", "slug": "parent-site_group"},
92+
{"name": "Other site_group", "slug": "other-site_group"},
93+
]
94+
created_site_groups = make_netbox_calls(nb.dcim.site_groups, site_groups)
95+
### site_group variables to be used later on
96+
parent_site_group = nb.dcim.site_groups.get(slug="parent-site_group")
97+
test_site_group = nb.dcim.site_groups.get(slug="test-site_group")
98+
99+
### Create relationship between site_groups
100+
test_site_group.parent = parent_site_group
101+
test_site_group.save()
88102

89103
## Create SITES and register variables
90104
sites = [
@@ -93,6 +107,7 @@ def make_netbox_calls(endpoint, payload):
93107
"slug": "test-site",
94108
"tenant": test_tenant.id,
95109
"region": test_region.id,
110+
"site_group": test_site_group.id,
96111
},
97112
{"name": "Test Site2", "slug": "test-site2"},
98113
]

tests/integration/targets/inventory-v2.11/files/test-inventory-legacy.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"sites": [
2727
"test-site2"
2828
],
29+
"site_groups": [],
2930
"status": {
3031
"label": "Active",
3132
"value": "active"
@@ -85,6 +86,7 @@
8586
"sites": [
8687
"test-site"
8788
],
89+
"site_groups": [],
8890
"status": {
8991
"label": "Active",
9092
"value": "active"
@@ -125,6 +127,7 @@
125127
}
126128
}
127129
],
130+
"site_groups": [],
128131
"status": {
129132
"label": "Active",
130133
"value": "active"
@@ -161,6 +164,7 @@
161164
"sites": [
162165
"test-site"
163166
],
167+
"site_groups": [],
164168
"status": {
165169
"label": "Active",
166170
"value": "active"
@@ -258,6 +262,7 @@
258262
"sites": [
259263
"test-site"
260264
],
265+
"site_groups": [],
261266
"status": {
262267
"label": "Active",
263268
"value": "active"
@@ -282,6 +287,7 @@
282287
"sites": [
283288
"test-site"
284289
],
290+
"site_groups": [],
285291
"status": {
286292
"label": "Active",
287293
"value": "active"
@@ -306,6 +312,7 @@
306312
"sites": [
307313
"test-site"
308314
],
315+
"site_groups": [],
309316
"status": {
310317
"label": "Active",
311318
"value": "active"
@@ -330,6 +337,7 @@
330337
"sites": [
331338
"test-site"
332339
],
340+
"site_groups": [],
333341
"status": {
334342
"label": "Active",
335343
"value": "active"
@@ -354,6 +362,7 @@
354362
"sites": [
355363
"test-site"
356364
],
365+
"site_groups": [],
357366
"status": {
358367
"label": "Active",
359368
"value": "active"
@@ -371,6 +380,7 @@
371380
"locations": [],
372381
"regions": [],
373382
"services": [],
383+
"site_groups": [],
374384
"status": {
375385
"label": "Active",
376386
"value": "active"
@@ -398,4 +408,4 @@
398408
"test104-vm"
399409
]
400410
}
401-
}
411+
}

tests/integration/targets/inventory-v2.11/files/test-inventory-noracks.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"sites": [
2626
"test-site2"
2727
],
28+
"site_groups": [],
2829
"status": {
2930
"label": "Active",
3031
"value": "active"
@@ -226,6 +227,7 @@
226227
"sites": [
227228
"test-site"
228229
],
230+
"site_groups": [],
229231
"status": {
230232
"label": "Active",
231233
"value": "active"
@@ -326,6 +328,7 @@
326328
}
327329
}
328330
],
331+
"site_groups": [],
329332
"status": {
330333
"label": "Active",
331334
"value": "active"
@@ -359,6 +362,7 @@
359362
"sites": [
360363
"test-site"
361364
],
365+
"site_groups": [],
362366
"status": {
363367
"label": "Active",
364368
"value": "active"
@@ -607,6 +611,7 @@
607611
"sites": [
608612
"test-site"
609613
],
614+
"site_groups": [],
610615
"status": {
611616
"label": "Active",
612617
"value": "active"
@@ -765,6 +770,7 @@
765770
"sites": [
766771
"test-site"
767772
],
773+
"site_groups": [],
768774
"status": {
769775
"label": "Active",
770776
"value": "active"
@@ -923,6 +929,7 @@
923929
"sites": [
924930
"test-site"
925931
],
932+
"site_groups": [],
926933
"status": {
927934
"label": "Active",
928935
"value": "active"
@@ -950,6 +957,7 @@
950957
"sites": [
951958
"test-site"
952959
],
960+
"site_groups": [],
953961
"status": {
954962
"label": "Active",
955963
"value": "active"
@@ -977,6 +985,7 @@
977985
"sites": [
978986
"test-site"
979987
],
988+
"site_groups": [],
980989
"status": {
981990
"label": "Active",
982991
"value": "active"
@@ -997,6 +1006,7 @@
9971006
],
9981007
"regions": [],
9991008
"services": [],
1009+
"site_groups": [],
10001010
"status": {
10011011
"label": "Active",
10021012
"value": "active"
@@ -1018,6 +1028,8 @@
10181028
"manufacturers_cisco",
10191029
"region_other_region",
10201030
"region_parent_region",
1031+
"site_group_other_site_group",
1032+
"site_group_parent_site_group",
10211033
"sites_test_site2",
10221034
"status_active",
10231035
"ungrouped"
@@ -1115,6 +1127,11 @@
11151127
"sites_test_site"
11161128
]
11171129
},
1130+
"site_group_parent_site_group": {
1131+
"children": [
1132+
"site_group_test_site_group"
1133+
]
1134+
},
11181135
"sites_test_site": {
11191136
"children": [
11201137
"location_parent_rack_group"

tests/integration/targets/inventory-v2.11/files/test-inventory-noracks.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ group_by:
1919
- manufacturers
2020
- platforms
2121
- region
22+
- site_group
2223
- cluster
2324
- cluster_group
2425
- cluster_type

0 commit comments

Comments
 (0)