Skip to content

Commit 76691b6

Browse files
authored
Add NetBox 3.2 to CI (#759)
1 parent 4fcbff1 commit 76691b6

File tree

89 files changed

+15899
-0
lines changed

Some content is hidden

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

89 files changed

+15899
-0
lines changed

.github/workflows/main.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ jobs:
5454
- python-version: 3.8
5555
VERSION: "v3.1"
5656
INTEGRATION_TESTS: "v3.1"
57+
- python-version: 3.8
58+
VERSION: "v3.2"
59+
INTEGRATION_TESTS: "v3.2"
5760
steps:
5861
- name: Checkout repo
5962
uses: actions/checkout@v2
@@ -122,6 +125,26 @@ jobs:
122125
docker container ls
123126
cd ..
124127
if: matrix.VERSION == 'v3.1'
128+
- name: Clone & Start netbox-docker containers - 3.2
129+
env:
130+
VERSION: ${{ matrix.VERSION }}
131+
run: |
132+
cd ..
133+
git clone https://github.com/netbox-community/netbox-docker.git
134+
cd netbox-docker
135+
git checkout 1.6.1
136+
tee docker-compose.override.yml <<EOF
137+
version: '3.4'
138+
services:
139+
netbox:
140+
image: netboxcommunity/netbox:v3.2
141+
ports:
142+
- 32768:8080
143+
EOF
144+
docker-compose up -d --quiet-pull
145+
docker container ls
146+
cd ..
147+
if: matrix.VERSION == 'v3.2'
125148
- name: Install and configure Poetry
126149
uses: snok/install-poetry@v1.1.1
127150
with:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
runme_config
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# https://docs.ansible.com/ansible/devel/dev_guide/testing/sanity/integration-aliases.html
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
#!/usr/bin/env python
2+
3+
# Inspired by community.aws collection script_inventory_ec2 test
4+
# https://github.com/ansible-collections/community.aws/blob/master/tests/integration/targets/script_inventory_ec2/inventory_diff.py
5+
6+
from __future__ import absolute_import, division, print_function
7+
8+
__metaclass__ = type
9+
10+
import sys
11+
import json
12+
import argparse
13+
from jsondiff import diff
14+
from typing import Iterable
15+
from operator import itemgetter
16+
17+
# NetBox includes "created" and "last_updated" times on objects. These end up in the interfaces objects that are included verbatim from the NetBox API.
18+
# "url" may be different if local tests use a different host/port
19+
# Remove these from files saved in git as test data
20+
KEYS_REMOVE = frozenset(["created", "last_updated", "url"])
21+
22+
# Ignore these when performing diffs as they will be different for each test run
23+
# (Was previously keys specific to NetBox 2.6)
24+
KEYS_IGNORE = frozenset()
25+
26+
# Rack Groups became hierarchical in NetBox 2.8. Don't bother comparing against test data in NetBox 2.7
27+
KEYS_IGNORE_27 = frozenset(
28+
[
29+
"rack_groups", # host var
30+
"rack_group_parent_rack_group", # group, group_names_raw = False
31+
"parent_rack_group", # group, group_names_raw = True
32+
]
33+
)
34+
35+
36+
def all_keys_to_ignore(netbox_version):
37+
keys = KEYS_REMOVE.union(KEYS_IGNORE)
38+
39+
if netbox_version == "v2.7":
40+
return keys.union(KEYS_IGNORE_27)
41+
else:
42+
return keys
43+
44+
45+
# Assume the object will not be recursive, as it originally came from JSON
46+
def remove_keys(obj, keys):
47+
48+
if isinstance(obj, dict):
49+
keys_to_remove = keys.intersection(obj.keys())
50+
for key in keys_to_remove:
51+
del obj[key]
52+
53+
for (key, value) in obj.items():
54+
remove_keys(value, keys)
55+
56+
elif isinstance(obj, list):
57+
# Iterate over temporary copy, as we may remove items
58+
for item in obj[:]:
59+
if isinstance(item, str) and item in keys:
60+
# List contains a string that we want to remove
61+
# eg. a group name in list of groups
62+
obj.remove(item)
63+
remove_keys(item, keys)
64+
65+
66+
def sort_hostvar_arrays(obj):
67+
meta = obj.get("_meta")
68+
if not meta:
69+
return
70+
71+
hostvars = meta.get("hostvars")
72+
if not hostvars:
73+
return
74+
75+
for hostname, host in hostvars.items():
76+
interfaces = host.get("interfaces")
77+
if interfaces:
78+
host["interfaces"] = sorted(interfaces, key=itemgetter("id"))
79+
80+
services = host.get("services")
81+
if services:
82+
host["services"] = sorted(services, key=itemgetter("id"))
83+
84+
85+
def read_json(filename):
86+
with open(filename, "r") as f:
87+
return json.loads(f.read())
88+
89+
90+
def write_json(filename, data):
91+
with open(filename, "w") as f:
92+
json.dump(data, f, indent=4)
93+
94+
95+
def main():
96+
parser = argparse.ArgumentParser(description="Diff Ansible inventory JSON output")
97+
parser.add_argument(
98+
"filename_a",
99+
metavar="ORIGINAL.json",
100+
type=str,
101+
help="Original json to test against",
102+
)
103+
parser.add_argument(
104+
"filename_b",
105+
metavar="NEW.json",
106+
type=str,
107+
help="Newly generated json to compare against original",
108+
)
109+
parser.add_argument(
110+
"--write",
111+
action="store_true",
112+
help=(
113+
"When comparing files, various keys are removed. "
114+
"This option will not compare the files, and instead writes ORIGINAL.json to NEW.json after removing these keys. "
115+
"This is used to clean the test json files before saving to the git repo. "
116+
"For example, this removes dates. "
117+
),
118+
)
119+
parser.add_argument(
120+
"--netbox-version",
121+
metavar="VERSION",
122+
type=str,
123+
help=(
124+
"Apply comparison specific to NetBox version. "
125+
"For example, rack_groups arrays will only contain a single item in v2.7, so are ignored in the comparison."
126+
),
127+
)
128+
129+
args = parser.parse_args()
130+
131+
data_a = read_json(args.filename_a)
132+
133+
if args.write:
134+
# When writing test data, only remove "remove_keys" that will change on every git commit.
135+
# This makes diffs more easily readable to ensure changes to test data look correct.
136+
remove_keys(data_a, KEYS_REMOVE)
137+
sort_hostvar_arrays(data_a)
138+
write_json(args.filename_b, data_a)
139+
140+
else:
141+
data_b = read_json(args.filename_b)
142+
143+
# Ignore keys that we don't want to diff, in addition to the ones removed that change on every commit
144+
keys = all_keys_to_ignore(args.netbox_version)
145+
remove_keys(data_a, keys)
146+
remove_keys(data_b, keys)
147+
148+
sort_hostvar_arrays(data_a)
149+
sort_hostvar_arrays(data_b)
150+
151+
# Perform the diff
152+
# syntax='symmetric' will produce output that prints both the before and after as "$insert" and "$delete"
153+
# marshal=True removes any special types, allowing to be dumped as json
154+
result = diff(data_a, data_b, marshal=True, syntax="symmetric")
155+
156+
if result:
157+
# Dictionary is not empty - print differences
158+
print(json.dumps(result, sort_keys=True, indent=4))
159+
sys.exit(1)
160+
else:
161+
# Success, no differences
162+
sys.exit(0)
163+
164+
165+
if __name__ == "__main__":
166+
main()

0 commit comments

Comments
 (0)