Skip to content

Commit

Permalink
Merge branch 'netbox-community:devel' into 1333-feature-netbox_device…
Browse files Browse the repository at this point in the history
…_interface_template
  • Loading branch information
richbibby authored Oct 26, 2024
2 parents 71ab8fb + 4b203df commit 9f4bf44
Show file tree
Hide file tree
Showing 17 changed files with 372 additions and 1 deletion.
2 changes: 2 additions & 0 deletions changelogs/fragments/1323-fixing-bug-#975.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bugfixes:
- netbox_ip_address - Fixed the problem preventing assignment of an IP address to a network interface
2 changes: 2 additions & 0 deletions changelogs/fragments/1327-add-custom-headers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- Add support for custom headers
2 changes: 2 additions & 0 deletions changelogs/fragments/1332-add-hostname_field-option.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- Add example for using ansible variables in lookup
2 changes: 2 additions & 0 deletions changelogs/fragments/1335-api-status-page-not-found.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bugfixes:
- fix call /api/status/ instead /api/status in nb_inventory plugin. (https://github.com/netbox-community/ansible_modules/issues/1335).
15 changes: 14 additions & 1 deletion plugins/inventory/nb_inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@
- By default, the inventory hostname is the netbox device name
- If set, sets the inventory hostname from this field in custom_fields instead
default: False
headers:
description: Dictionary of headers to be passed to the NetBox API.
default: {}
env:
- name: NETBOX_HEADERS
"""

EXAMPLES = """
Expand All @@ -281,6 +286,8 @@
device_query_filters:
- has_primary_ip: 'true'
- tenant__n: internal
headers:
Cookie: "{{ auth_cookie }}"
# has_primary_ip is a useful way to filter out patch panels and other passive devices
# Adding '__n' to a field searches for the negation of the value.
Expand Down Expand Up @@ -1600,7 +1607,7 @@ def fetch_api_docs(self):
cached_api_version = None
cache = None

status = self._fetch_information(self.api_endpoint + "/api/status")
status = self._fetch_information(self.api_endpoint + "/api/status/")
netbox_api_version = ".".join(status["netbox-version"].split(".")[:2])

if version.parse(netbox_api_version) >= version.parse("3.5.0"):
Expand Down Expand Up @@ -2115,6 +2122,12 @@ def _set_authorization(self):
)
else:
self.headers.update({"Authorization": "Token %s" % token})
headers = self.get_option("headers")
if headers:
if isinstance(headers, str):
headers = json.loads(headers)
if isinstance(headers, dict):
self.headers.update(headers)

def parse(self, inventory, loader, path, cache=True):
super(InventoryModule, self).parse(inventory, loader, path)
Expand Down
25 changes: 25 additions & 0 deletions plugins/lookup/nb_lookup.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@
- name: NETBOX_TOKEN
- name: NETBOX_API_TOKEN
required: false
headers:
description: Dictionary of headers to be passed to the NetBox API.
default: {}
env:
- name: NETBOX_HEADERS
validate_certs:
description:
- Whether or not to validate SSL of the NetBox instance
Expand Down Expand Up @@ -97,6 +102,20 @@
api_endpoint='http://localhost/',
api_filter='role=management tag=Dell'),
token='<redacted>') }}"
# This example uses an API Filter with a variable and jinja concatenation
- name: Set hostname fact
set_fact:
hostname: "my-server"
- name: Obtain details of a single device from NetBox
debug:
msg: >
"Device {{item.0.value.display}} (ID: {{item.0.key}}) was
manufactured by {{ item.0.value.device_type.manufacturer.name }}"
loop:
- '{{ query("netbox.netbox.nb_lookup", "devices",
api_endpoint="http://localhost/",
api_filter="name=" ~hostname,
token="<redacted>") }}'
"""

RETURN = """
Expand All @@ -108,6 +127,7 @@

import os
import functools
import json
from pprint import pformat

from ansible.errors import AnsibleError
Expand Down Expand Up @@ -411,6 +431,7 @@ def run(self, terms, variables=None, **kwargs):
or os.getenv("NETBOX_API")
or os.getenv("NETBOX_URL")
)
netbox_headers = kwargs.get("headers") or os.getenv("NETBOX_HEADERS") or {}
netbox_ssl_verify = kwargs.get("validate_certs", True)
netbox_private_key = kwargs.get("private_key")
netbox_private_key_file = kwargs.get("key_file")
Expand All @@ -421,8 +442,12 @@ def run(self, terms, variables=None, **kwargs):
if not isinstance(terms, list):
terms = [terms]

if isinstance(netbox_headers, str):
netbox_headers = json.loads(netbox_headers)

try:
session = requests.Session()
session.headers = netbox_headers
session.verify = netbox_ssl_verify

if Version(version("pynetbox")) < Version("7.0.0"):
Expand Down
5 changes: 5 additions & 0 deletions plugins/module_utils/netbox_ipam.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,11 @@ def run(self):
else:
name = data.get("name")

if self.endpoint == "ip_addresses":
if "interface" in data:
data["assigned_object_id"] = data["interface"]
data["assigned_object_type"] = "dcim.interface"

if self.endpoint in SLUG_REQUIRED:
if not data.get("slug"):
data["slug"] = self._to_slug(name)
Expand Down
49 changes: 49 additions & 0 deletions tests/integration/targets/v3.5/tasks/netbox_ip_address.yml
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,52 @@
- test_sixteen['diff']['after']['state'] == "present"
- test_sixteen['msg'] == "ip_address 10.120.10.1/32 created"
- test_sixteen['ip_address']['address'] == "10.120.10.1/32"

- name: "17 - Create IP address on GigabitEthernet2 - test100 with interface value - State: present"
netbox.netbox.netbox_ip_address:
netbox_url: http://localhost:32768
netbox_token: "0123456789abcdef0123456789abcdef01234567"
data:
family: 4
address: 10.10.200.31/16
interface:
device: test100
name: GigabitEthernet2
register: test_seventeen

- name: 17 - ASSERT
ansible.builtin.assert:
that:
- test_seventeen is changed
- test_seventeen['diff']['before']['state'] == "absent"
- test_seventeen['diff']['after']['state'] == "present"
- test_seventeen['msg'] == "ip_address 10.10.200.31/16 created"
- test_seventeen['ip_address']['address'] == "10.10.200.31/16"
- test_seventeen['ip_address']['family'] == 4
- test_seventeen['ip_address']['assigned_object_type'] == "dcim.interface"
- test_seventeen['ip_address']['assigned_object_id'] == 4

- name: "18 - Create IP address on GigabitEthernet2 - test100 with interface value - State: new"
netbox.netbox.netbox_ip_address:
netbox_url: http://localhost:32768
netbox_token: "0123456789abcdef0123456789abcdef01234567"
data:
family: 4
prefix: 10.10.0.0/16
interface:
name: GigabitEthernet2
device: test100
state: new
register: test_eighteen

- name: 18 - ASSERT
ansible.builtin.assert:
that:
- test_eighteen is changed
- test_eighteen['diff']['before']['state'] == "absent"
- test_eighteen['diff']['after']['state'] == "present"
- test_eighteen['msg'] == "ip_address 10.10.0.2/16 created"
- test_eighteen['ip_address']['address'] == "10.10.0.2/16"
- test_eighteen['ip_address']['family'] == 4
- test_eighteen['ip_address']['assigned_object_type'] == "dcim.interface"
- test_eighteen['ip_address']['assigned_object_id'] == 4
15 changes: 15 additions & 0 deletions tests/integration/targets/v3.5/tasks/netbox_lookup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,18 @@
vars:
query_result: "{{ query('netbox.netbox.nb_lookup', 'devices', api_filter='id=1', api_endpoint='http://localhost:32768', token='0123456789abcdef0123456789abcdef01234567')
}}"

- name: "NETBOX_LOOKUP 11: Device query by ansible variable"
ansible.builtin.set_fact:
hostname: "L2"

- name: "NETBOX LOOKUP 11.1: Obtain details of a single device from NetBox"
ansible.builtin.debug:
msg: >
"Device {{item.0.value.display}} (ID: {{item.0.key}}) was
manufactured by {{ item.0.value.device_type.manufacturer.name }}"
loop:
- '{{ query("netbox.netbox.nb_lookup", "devices",
api_filter="name=" ~hostname,
api_endpoint="http://localhost:32768",
token="0123456789abcdef0123456789abcdef01234567") }}'
49 changes: 49 additions & 0 deletions tests/integration/targets/v3.6/tasks/netbox_ip_address.yml
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,52 @@
- test_sixteen['diff']['after']['state'] == "present"
- test_sixteen['msg'] == "ip_address 10.120.10.1/32 created"
- test_sixteen['ip_address']['address'] == "10.120.10.1/32"

- name: "17 - Create IP address on GigabitEthernet2 - test100 with interface value - State: present"
netbox.netbox.netbox_ip_address:
netbox_url: http://localhost:32768
netbox_token: "0123456789abcdef0123456789abcdef01234567"
data:
family: 4
address: 10.10.200.31/16
interface:
device: test100
name: GigabitEthernet2
register: test_seventeen

- name: 17 - ASSERT
ansible.builtin.assert:
that:
- test_seventeen is changed
- test_seventeen['diff']['before']['state'] == "absent"
- test_seventeen['diff']['after']['state'] == "present"
- test_seventeen['msg'] == "ip_address 10.10.200.31/16 created"
- test_seventeen['ip_address']['address'] == "10.10.200.31/16"
- test_seventeen['ip_address']['family'] == 4
- test_seventeen['ip_address']['assigned_object_type'] == "dcim.interface"
- test_seventeen['ip_address']['assigned_object_id'] == 4

- name: "18 - Create IP address on GigabitEthernet2 - test100 with interface value - State: new"
netbox.netbox.netbox_ip_address:
netbox_url: http://localhost:32768
netbox_token: "0123456789abcdef0123456789abcdef01234567"
data:
family: 4
prefix: 10.10.0.0/16
interface:
name: GigabitEthernet2
device: test100
state: new
register: test_eighteen

- name: 18 - ASSERT
ansible.builtin.assert:
that:
- test_eighteen is changed
- test_eighteen['diff']['before']['state'] == "absent"
- test_eighteen['diff']['after']['state'] == "present"
- test_eighteen['msg'] == "ip_address 10.10.0.2/16 created"
- test_eighteen['ip_address']['address'] == "10.10.0.2/16"
- test_eighteen['ip_address']['family'] == 4
- test_eighteen['ip_address']['assigned_object_type'] == "dcim.interface"
- test_eighteen['ip_address']['assigned_object_id'] == 4
15 changes: 15 additions & 0 deletions tests/integration/targets/v3.6/tasks/netbox_lookup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,18 @@
vars:
query_result: "{{ query('netbox.netbox.nb_lookup', 'devices', api_filter='id=1', api_endpoint='http://localhost:32768', token='0123456789abcdef0123456789abcdef01234567')
}}"

- name: "NETBOX_LOOKUP 11: Device query by ansible variable"
ansible.builtin.set_fact:
hostname: "L2"

- name: "NETBOX LOOKUP 11.1: Obtain details of a single device from NetBox"
ansible.builtin.debug:
msg: >
"Device {{item.0.value.display}} (ID: {{item.0.key}}) was
manufactured by {{ item.0.value.device_type.manufacturer.name }}"
loop:
- '{{ query("netbox.netbox.nb_lookup", "devices",
api_filter="name=" ~hostname,
api_endpoint="http://localhost:32768",
token="0123456789abcdef0123456789abcdef01234567") }}'
49 changes: 49 additions & 0 deletions tests/integration/targets/v3.7/tasks/netbox_ip_address.yml
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,52 @@
- test_sixteen['diff']['after']['state'] == "present"
- test_sixteen['msg'] == "ip_address 10.120.10.1/32 created"
- test_sixteen['ip_address']['address'] == "10.120.10.1/32"

- name: "17 - Create IP address on GigabitEthernet2 - test100 with interface value - State: present"
netbox.netbox.netbox_ip_address:
netbox_url: http://localhost:32768
netbox_token: "0123456789abcdef0123456789abcdef01234567"
data:
family: 4
address: 10.10.200.31/16
interface:
device: test100
name: GigabitEthernet2
register: test_seventeen

- name: 17 - ASSERT
ansible.builtin.assert:
that:
- test_seventeen is changed
- test_seventeen['diff']['before']['state'] == "absent"
- test_seventeen['diff']['after']['state'] == "present"
- test_seventeen['msg'] == "ip_address 10.10.200.31/16 created"
- test_seventeen['ip_address']['address'] == "10.10.200.31/16"
- test_seventeen['ip_address']['family'] == 4
- test_seventeen['ip_address']['assigned_object_type'] == "dcim.interface"
- test_seventeen['ip_address']['assigned_object_id'] == 4

- name: "18 - Create IP address on GigabitEthernet2 - test100 with interface value - State: new"
netbox.netbox.netbox_ip_address:
netbox_url: http://localhost:32768
netbox_token: "0123456789abcdef0123456789abcdef01234567"
data:
family: 4
prefix: 10.10.0.0/16
interface:
name: GigabitEthernet2
device: test100
state: new
register: test_eighteen

- name: 18 - ASSERT
ansible.builtin.assert:
that:
- test_eighteen is changed
- test_eighteen['diff']['before']['state'] == "absent"
- test_eighteen['diff']['after']['state'] == "present"
- test_eighteen['msg'] == "ip_address 10.10.0.2/16 created"
- test_eighteen['ip_address']['address'] == "10.10.0.2/16"
- test_eighteen['ip_address']['family'] == 4
- test_eighteen['ip_address']['assigned_object_type'] == "dcim.interface"
- test_eighteen['ip_address']['assigned_object_id'] == 4
15 changes: 15 additions & 0 deletions tests/integration/targets/v3.7/tasks/netbox_lookup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,18 @@
vars:
query_result: "{{ query('netbox.netbox.nb_lookup', 'devices', api_filter='id=1', api_endpoint='http://localhost:32768', token='0123456789abcdef0123456789abcdef01234567')
}}"

- name: "NETBOX_LOOKUP 11: Device query by ansible variable"
ansible.builtin.set_fact:
hostname: "L2"

- name: "NETBOX LOOKUP 11.1: Obtain details of a single device from NetBox"
ansible.builtin.debug:
msg: >
"Device {{item.0.value.display}} (ID: {{item.0.key}}) was
manufactured by {{ item.0.value.device_type.manufacturer.name }}"
loop:
- '{{ query("netbox.netbox.nb_lookup", "devices",
api_filter="name=" ~hostname,
api_endpoint="http://localhost:32768",
token="0123456789abcdef0123456789abcdef01234567") }}'
49 changes: 49 additions & 0 deletions tests/integration/targets/v4.0/tasks/netbox_ip_address.yml
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,52 @@
- test_sixteen['diff']['after']['state'] == "present"
- test_sixteen['msg'] == "ip_address 10.120.10.1/32 created"
- test_sixteen['ip_address']['address'] == "10.120.10.1/32"

- name: "17 - Create IP address on GigabitEthernet2 - test100 with interface value - State: present"
netbox.netbox.netbox_ip_address:
netbox_url: http://localhost:32768
netbox_token: "0123456789abcdef0123456789abcdef01234567"
data:
family: 4
address: 10.10.200.31/16
interface:
device: test100
name: GigabitEthernet2
register: test_seventeen

- name: 17 - ASSERT
ansible.builtin.assert:
that:
- test_seventeen is changed
- test_seventeen['diff']['before']['state'] == "absent"
- test_seventeen['diff']['after']['state'] == "present"
- test_seventeen['msg'] == "ip_address 10.10.200.31/16 created"
- test_seventeen['ip_address']['address'] == "10.10.200.31/16"
- test_seventeen['ip_address']['family'] == 4
- test_seventeen['ip_address']['assigned_object_type'] == "dcim.interface"
- test_seventeen['ip_address']['assigned_object_id'] == 4

- name: "18 - Create IP address on GigabitEthernet2 - test100 with interface value - State: new"
netbox.netbox.netbox_ip_address:
netbox_url: http://localhost:32768
netbox_token: "0123456789abcdef0123456789abcdef01234567"
data:
family: 4
prefix: 10.10.0.0/16
interface:
name: GigabitEthernet2
device: test100
state: new
register: test_eighteen

- name: 18 - ASSERT
ansible.builtin.assert:
that:
- test_eighteen is changed
- test_eighteen['diff']['before']['state'] == "absent"
- test_eighteen['diff']['after']['state'] == "present"
- test_eighteen['msg'] == "ip_address 10.10.0.2/16 created"
- test_eighteen['ip_address']['address'] == "10.10.0.2/16"
- test_eighteen['ip_address']['family'] == 4
- test_eighteen['ip_address']['assigned_object_type'] == "dcim.interface"
- test_eighteen['ip_address']['assigned_object_id'] == 4
Loading

0 comments on commit 9f4bf44

Please sign in to comment.