Skip to content

Commit 809dac9

Browse files
committed
Inventory: Fix fetching services from VMs, and devices with spaces in the name (netbox-community#142)
1 parent 716ca38 commit 809dac9

File tree

6 files changed

+270
-35
lines changed

6 files changed

+270
-35
lines changed

plugins/inventory/nb_inventory.py

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,10 @@ def group_extractors(self):
541541
"cluster_type": self.extract_cluster_type,
542542
}
543543

544+
def _host_is_vm(self, host):
545+
# Determine whether a host is a vm, or a "device"
546+
return "device_role" not in host
547+
544548
def _pluralize(self, extracted_value):
545549
# If plurals is enabled, wrap in a single-element list for backwards compatibility
546550
if self.plurals:
@@ -566,13 +570,16 @@ def extract_platform(self, host):
566570
def extract_services(self, host):
567571
try:
568572
if self.services:
569-
url = (
570-
self.api_endpoint
571-
+ "/api/ipam/services/?device="
572-
+ str(host["name"])
573+
path = (
574+
"/api/ipam/services/?limit=0&virtual_machine_id=%s"
575+
if self._host_is_vm(host)
576+
else "/api/ipam/services/?limit=0&device_id=%s"
573577
)
574-
device_lookup = self._fetch_information(url)
575-
return device_lookup["results"]
578+
579+
url = self.api_endpoint + path % (to_text(host["id"]))
580+
581+
service_lookup = self._fetch_information(url)
582+
return service_lookup["results"]
576583
except Exception:
577584
return
578585

@@ -656,18 +663,14 @@ def extract_tags(self, host):
656663
def extract_ipaddresses(self, host):
657664
try:
658665
if self.interfaces:
659-
if "device_role" in host:
660-
url = (
661-
self.api_endpoint
662-
+ "/api/ipam/ip-addresses/?limit=0&device_id=%s"
663-
% (to_text(host["id"]))
664-
)
665-
elif "role" in host:
666-
url = (
667-
self.api_endpoint
668-
+ "/api/ipam/ip-addresses/?limit=0&virtual_machine_id=%s"
669-
% (to_text(host["id"]))
670-
)
666+
path = (
667+
"/api/ipam/ip-addresses/?limit=0&virtual_machine_id=%s"
668+
if self._host_is_vm(host)
669+
else "/api/ipam/ip-addresses/?limit=0&device_id=%s"
670+
)
671+
672+
url = self.api_endpoint + path % (to_text(host["id"]))
673+
671674
ipaddress_lookup = self.get_resource_list(api_url=url)
672675

673676
return ipaddress_lookup
@@ -677,18 +680,14 @@ def extract_ipaddresses(self, host):
677680
def extract_interfaces(self, host):
678681
try:
679682
if self.interfaces:
680-
if "device_role" in host:
681-
url = (
682-
self.api_endpoint
683-
+ "/api/dcim/interfaces/?limit=0&device_id=%s"
684-
% (to_text(host["id"]))
685-
)
686-
elif "role" in host:
687-
url = (
688-
self.api_endpoint
689-
+ "/api/virtualization/interfaces/?limit=0&virtual_machine_id=%s"
690-
% (to_text(host["id"]))
691-
)
683+
path = (
684+
"/api/virtualization/interfaces/?limit=0&virtual_machine_id=%s"
685+
if self._host_is_vm(host)
686+
else "/api/dcim/interfaces/?limit=0&device_id=%s"
687+
)
688+
689+
url = self.api_endpoint + path % (to_text(host["id"]))
690+
692691
interface_lookup = self.get_resource_list(api_url=url)
693692

694693
# Collect all IP Addresses associated with the device

tests/integration/netbox-deploy.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
__metaclass__ = type
66

7+
import os
78
import pynetbox
89

910
# Set nb variable to connec to Netbox and use the veriable in future calls
@@ -240,6 +241,25 @@
240241
]
241242
created_ip_addresses = nb.ipam.ip_addresses.create(ip_addresses)
242243

244+
245+
## Create Services
246+
247+
### Netbox 2.6 uses id int instead of string
248+
protocol_tcp = "tcp" if os.environ["INTEGRATION_TESTS"] == "latest" else 6
249+
250+
services = [
251+
{"device": test100.id, "name": "ssh", "port": 22, "protocol": protocol_tcp},
252+
{
253+
"device": test100.id,
254+
"name": "http",
255+
"port": 80,
256+
"protocol": protocol_tcp,
257+
"ipaddresses": [created_ip_addresses[0].id, created_ip_addresses[1].id],
258+
},
259+
]
260+
created_services = nb.ipam.services.create(services)
261+
262+
243263
## Create RIRs
244264
rirs = [{"name": "Example RIR", "slug": "example-rir"}]
245265
created_rirs = nb.ipam.rirs.create(rirs)

tests/integration/targets/inventory/compare_inventory_json.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
# Netbox includes created and last_updated times on objects.
1616
# These end up in the interfaces objects that are included verbatim from the Netbox API.
1717
# Ignore these when performing diffs as they will be different for each test run
18-
ignored_keys = set(["created", "last_updated", "form_factor", "type", "status"])
19-
# interface "form_factor", "type" and ip_addresses "status" are differnt in Netbox 2.6 vs 2.7 APIs
18+
ignored_keys = set(
19+
["created", "last_updated", "form_factor", "type", "status", "protocol"]
20+
)
21+
# interface "form_factor", "type", ip_addresses "status", and service "protocol" are differnt in Netbox 2.6 vs 2.7 APIs
2022

2123

2224
# Assume the object will not be recursive, as it originally came from JSON
@@ -35,6 +37,17 @@ def remove_ignored_keys(obj):
3537
remove_ignored_keys(item)
3638

3739

40+
def remove_specifics(obj):
41+
try:
42+
# Netbox 2.6 doesn't output "tags" for services
43+
# I don't just want to ignore the "tags" key everywhere, as it's a host var that users care about
44+
services = obj["_meta"]["hostvars"]["test100"]["services"]
45+
for item in services:
46+
item.pop("tags", None)
47+
except Exception:
48+
pass
49+
50+
3851
def main():
3952
if len(sys.argv) != 3:
4053
print(
@@ -56,6 +69,8 @@ def main():
5669
# ie. times that will change on each run of tests
5770
remove_ignored_keys(adata)
5871
remove_ignored_keys(bdata)
72+
remove_specifics(adata)
73+
remove_specifics(bdata)
5974

6075
# Perform the diff
6176
# syntax='symmetric' will produce output that prints both the before and after as "$insert" and "$delete"

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

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"test-region",
3838
"parent-region"
3939
],
40+
"services": [],
4041
"sites": [
4142
"test-site"
4243
],
@@ -57,6 +58,7 @@
5758
"test-region",
5859
"parent-region"
5960
],
61+
"services": [],
6062
"sites": [
6163
"test-site"
6264
],
@@ -98,7 +100,67 @@
98100
"test-region",
99101
"parent-region"
100102
],
101-
"services": [],
103+
"services": [
104+
{
105+
"created": "2020-05-04",
106+
"custom_fields": {},
107+
"description": "",
108+
"device": {
109+
"display_name": "test100",
110+
"id": 1,
111+
"name": "test100",
112+
"url": "http://localhost:32768/api/dcim/devices/1/"
113+
},
114+
"id": 1,
115+
"ipaddresses": [],
116+
"last_updated": "2020-05-04T07:24:07.945347Z",
117+
"name": "ssh",
118+
"port": 22,
119+
"protocol": {
120+
"id": 6,
121+
"label": "TCP",
122+
"value": "tcp"
123+
},
124+
"tags": [],
125+
"virtual_machine": null
126+
},
127+
{
128+
"created": "2020-05-04",
129+
"custom_fields": {},
130+
"description": "",
131+
"device": {
132+
"display_name": "test100",
133+
"id": 1,
134+
"name": "test100",
135+
"url": "http://localhost:32768/api/dcim/devices/1/"
136+
},
137+
"id": 2,
138+
"ipaddresses": [
139+
{
140+
"address": "172.16.180.1/24",
141+
"family": 4,
142+
"id": 1,
143+
"url": "http://localhost:32768/api/ipam/ip-addresses/1/"
144+
},
145+
{
146+
"address": "2001::1:1/64",
147+
"family": 6,
148+
"id": 2,
149+
"url": "http://localhost:32768/api/ipam/ip-addresses/2/"
150+
}
151+
],
152+
"last_updated": "2020-05-04T07:24:07.955155Z",
153+
"name": "http",
154+
"port": 80,
155+
"protocol": {
156+
"id": 6,
157+
"label": "TCP",
158+
"value": "tcp"
159+
},
160+
"tags": [],
161+
"virtual_machine": null
162+
}
163+
],
102164
"sites": [
103165
"test-site"
104166
],
@@ -113,6 +175,7 @@
113175
"test-region",
114176
"parent-region"
115177
],
178+
"services": [],
116179
"sites": [
117180
"test-site"
118181
],
@@ -127,6 +190,7 @@
127190
"test-region",
128191
"parent-region"
129192
],
193+
"services": [],
130194
"sites": [
131195
"test-site"
132196
],
@@ -141,6 +205,7 @@
141205
"test-region",
142206
"parent-region"
143207
],
208+
"services": [],
144209
"sites": [
145210
"test-site"
146211
],
@@ -155,6 +220,7 @@
155220
"test-region",
156221
"parent-region"
157222
],
223+
"services": [],
158224
"sites": [
159225
"test-site"
160226
],
@@ -165,6 +231,7 @@
165231
"cluster_type": "test-cluster-type",
166232
"custom_fields": {},
167233
"regions": [],
234+
"services": [],
168235
"tags": []
169236
}
170237
}

0 commit comments

Comments
 (0)