Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/1459-add-netbox-data-sources.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- netbox_data_source - New module `#1459 <https://github.com/netbox-community/ansible_modules/pull/1459>`

Check failure on line 2 in changelogs/fragments/1459-add-netbox-data-sources.yml

View workflow job for this annotation

GitHub Actions / ansible-lint / Ansible Lint

yaml[indentation]

Wrong indentation: expected at least 1
84 changes: 84 additions & 0 deletions plugins/module_utils/netbox_core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2025, Daniel Chiquito (@dchiquito) <daniel.chiquito@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function

__metaclass__ = type

from ansible_collections.netbox.netbox.plugins.module_utils.netbox_utils import (
NetboxModule,
ENDPOINT_NAME_MAPPING,
SLUG_REQUIRED,
)

NB_DATA_SOURCES = "data_sources"


class NetboxCoreModule(NetboxModule):
def __init__(self, module, endpoint):
super().__init__(module, endpoint)

def _handle_state_new(self, nb_app, nb_endpoint, endpoint_name, data):
if self.state == "new":
self.nb_object, diff = self._create_netbox_object(nb_endpoint, data)
self.result["msg"] = "%s created" % (endpoint_name)
self.result["changed"] = True
self.result["diff"] = diff

def run(self):
"""
This function should have all necessary code for endpoints within the application
to create/update/delete the endpoint objects
Supported endpoints:
- data_sources
"""
# Used to dynamically set key when returning results
endpoint_name = ENDPOINT_NAME_MAPPING[self.endpoint]

self.result = {"changed": False}

application = self._find_app(self.endpoint)
nb_app = getattr(self.nb, application)
nb_endpoint = getattr(nb_app, self.endpoint)
user_query_params = self.module.params.get("query_params")

data = self.data

# Used for msg output
if data.get("name"):
name = data["name"]
elif data.get("slug"):
name = data["slug"]

if self.endpoint in SLUG_REQUIRED:
if not data.get("slug"):
data["slug"] = self._to_slug(name)

# Make color params lowercase
if data.get("color"):
data["color"] = data["color"].lower()

# Handle journal entry
if self.state == "new" and endpoint_name == "journal_entry":
self._handle_state_new(nb_app, nb_endpoint, endpoint_name, data)
else:
object_query_params = self._build_query_params(
endpoint_name, data, user_query_params
)
self.nb_object = self._nb_endpoint_get(
nb_endpoint, object_query_params, name
)

if self.state == "present":
self._ensure_object_exists(nb_endpoint, endpoint_name, name, data)
elif self.state == "absent":
self._ensure_object_absent(endpoint_name, name)

try:
serialized_object = self.nb_object.serialize()
except AttributeError:
serialized_object = self.nb_object

self.result.update({endpoint_name: serialized_object})

self.module.exit_json(**self.result)
5 changes: 5 additions & 0 deletions plugins/module_utils/netbox_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
"providers": {},
"provider_networks": {},
},
core={
"data_sources": {},
},
dcim={
"cables": {},
"console_ports": {},
Expand Down Expand Up @@ -371,6 +374,7 @@
"custom_fields": "custom_field",
"custom_field_choice_sets": "choice_set",
"custom_links": "custom_link",
"data_sources": "data_source",
"device_bays": "device_bay",
"device_bay_templates": "device_bay_template",
"devices": "device",
Expand Down Expand Up @@ -482,6 +486,7 @@
"custom_field_choice_set": set(["name"]),
"choice_set": set(["name"]),
"custom_link": set(["name"]),
"data_source": set(["name"]),
"dcim.consoleport": set(["name", "device"]),
"dcim.consoleserverport": set(["name", "device"]),
"dcim.frontport": set(["name", "device", "rear_port"]),
Expand Down
190 changes: 190 additions & 0 deletions plugins/modules/netbox_data_source.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2025, Daniel Chiquito (@dchiquito) <daniel.chiquito@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

__metaclass__ = type

DOCUMENTATION = r"""
---
module: netbox_data_source
short_description: Creates or removes data sources from NetBox
description:
- Creates or removes data sources from NetBox
author:
- Daniel Chiquito (@dchiquito)
requirements:
- pynetbox
version_added: "3.22.0"
extends_documentation_fragment:
- netbox.netbox.common
options:
data:
type: dict
description:
- Defines the data source configuration
suboptions:
name:
description:
- Name of the data source
required: true
type: str
type:
description:
- The origin of the data source
choices:
- local
- git
- amazon-s3
required: false
type: str
source_url:
description:
- URL of the data source to be created
required: false
type: str
enabled:
description:
- Whether or not this data source can be synced
required: false
type: bool
description:
description:
- Description of the data source
required: false
type: str
ignore_rules:
description:
- Patterns (one per line) matching files to ignore when syncing
required: false
type: str
sync_interval:
description:
- The interval in seconds between syncs
required: false
choices:
- 1
- 60
- 720
- 1440
- 10080
- 43200
type: int
comments:
description:
- Comments about the data source
required: false
type: str
required: true
"""

EXAMPLES = r"""
- name: "Test NetBox modules"
connection: local
hosts: localhost
gather_facts: false

tasks:
- name: "Create a new data source with only required information"
netbox.netbox.netbox_data_source:
netbox_url: http://netbox.local
netbox_token: thisIsMyToken
data:
name: "Data Source 1"
type: "local"
source_url: "/tmp/data-source.txt"
enabled: true
state: present
- name: "Update that data source with other fields"
netbox.netbox.netbox_data_source:
netbox_url: http://netbox.local
netbox_token: thisIsMyToken
data:
name: "Data Source 1"
type: "amazon-s3"
source_url: "path/to/bucket"
enabled: false
description: "My first data source"
ignore_rules: ".*\nfoo.txt\n*.yml"
sync_interval: 1440
comments: "Some commentary on this data source"
state: present
- name: "Delete the data source"
netbox.netbox.netbox_data_source:
netbox_url: http://netbox.local
netbox_token: thisIsMyToken
data:
name: "Data Source 1"
state: absent
"""

RETURN = r"""
data_source:
description: Serialized object as created or already existent within NetBox
returned: on creation
type: dict
msg:
description: Message indicating failure or info about what has been achieved
returned: always
type: str
"""


from ansible_collections.netbox.netbox.plugins.module_utils.netbox_utils import (
NetboxAnsibleModule,
NETBOX_ARG_SPEC,
)
from ansible_collections.netbox.netbox.plugins.module_utils.netbox_core import (
NetboxCoreModule,
NB_DATA_SOURCES,
)
from copy import deepcopy


def main():
"""
Main entry point for module execution
"""
argument_spec = deepcopy(NETBOX_ARG_SPEC)
argument_spec.update(
dict(
data=dict(
type="dict",
required=True,
options=dict(
name=dict(required=True, type="str"),
type=dict(
required=False,
choices=["local", "git", "amazon-s3"],
type="str",
),
source_url=dict(required=False, type="str"),
enabled=dict(required=False, type="bool"),
description=dict(required=False, type="str"),
ignore_rules=dict(required=False, type="str"),
sync_interval=dict(
required=False,
choices=[1, 60, 60 * 12, 60 * 24, 60 * 24 * 7, 60 * 24 * 30],
type="int",
),
comments=dict(required=False, type="str"),
),
),
)
)

required_if = [
("state", "present", ["name", "type", "source_url", "enabled"]),
("state", "absent", ["name"]),
]

module = NetboxAnsibleModule(
argument_spec=argument_spec, supports_check_mode=True, required_if=required_if
)

netbox_data_source = NetboxCoreModule(module, NB_DATA_SOURCES)
netbox_data_source.run()


if __name__ == "__main__": # pragma: no cover
main()
75 changes: 75 additions & 0 deletions tests/integration/targets/v4.0/tasks/netbox_data_source.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
##
##
### NETBOX_DATA_SOURCE
##
##
- name: "DATA SOURCE 1: Create"
netbox.netbox.netbox_data_source:
netbox_url: http://localhost:32768
netbox_token: "0123456789abcdef0123456789abcdef01234567"
data:
name: "Data Source 1"
type: "local"
source_url: "/tmp/data-source.txt"
enabled: true
state: present
register: test_one

- name: "DATA SOURCE 1: Assert - Create"
ansible.builtin.assert:
that:
- test_one is changed
- test_one['diff']['before']['state'] == "absent"
- test_one['diff']['after']['state'] == "present"
- test_one['data_source']['name'] == "Data Source 1"
- test_one['data_source']['type'] == "local"
- test_one['data_source']['source_url'] == "/tmp/data-source.txt"
- test_one['data_source']['enabled'] == true
- test_one['msg'] == "data_source Data Source 1 created"

- name: "DATA SOURCE 2: Update"
netbox.netbox.netbox_data_source:
netbox_url: http://localhost:32768
netbox_token: "0123456789abcdef0123456789abcdef01234567"
data:
name: "Data Source 1"
type: "amazon-s3"
source_url: "path/to/bucket"
enabled: false
description: "My first data source"
ignore_rules: ".*\nfoo.txt\n*.yml"
sync_interval: 1440
comments: "Some commentary on this data source"
state: present
register: test_two

- name: "DATA SOURCE 2: Assert - Update"
ansible.builtin.assert:
that:
- test_two is changed
- test_two['data_source']['name'] == "Data Source 1"
- test_two['data_source']['type'] == "amazon-s3"
- test_two['data_source']['source_url'] == "path/to/bucket"
- test_two['data_source']['enabled'] == false
- test_two['data_source']['description'] == "My first data source"
- test_two['data_source']['ignore_rules'] == ".*\nfoo.txt\n*.yml"
- test_two['data_source']['sync_interval'] == 1440
- test_two['data_source']['comments'] == "Some commentary on this data source"
- test_two['msg'] == "data_source Data Source 1 updated"

- name: "DATA SOURCE 3: Delete"
netbox.netbox.netbox_data_source:
netbox_url: http://localhost:32768
netbox_token: "0123456789abcdef0123456789abcdef01234567"
data:
name: "Data Source 1"
state: absent
register: test_three

- name: "DATA SOURCE 3: Assert - Delete"
ansible.builtin.assert:
that:
- test_three is changed
- test_three['diff']['before']['state'] == "present"
- test_three['diff']['after']['state'] == "absent"
Loading
Loading