diff --git a/.github/workflows/ansible-lint.yml b/.github/workflows/ansible-lint.yml new file mode 100644 index 0000000..70189b2 --- /dev/null +++ b/.github/workflows/ansible-lint.yml @@ -0,0 +1,18 @@ +# .github/workflows/ansible-lint.yml +name: ansible-lint +on: + pull_request: + branches: ["main", "stable", "release/v*", "dev"] +jobs: + build: + name: Ansible Lint # Naming the build is important to use it as a status check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run ansible-lint + uses: ansible/ansible-lint@v24.10.0 + # optional (see below): + with: + args: " -c .ansible-lint" + setup_python: "true" + requirements_file: requirements.yml diff --git a/README.md b/README.md index 225dd44..2a6fbce 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,74 @@ -Role Name -========= +# Netbox Inventory -A brief description of the role goes here. +[![ansible-lint](https://github.com/tfindley/Ansible-Role-NetboxInventory/actions/workflows/ansible-lint.yml/badge.svg?branch=main)](https://github.com/tfindley/Ansible-Role-NetboxInventory/actions/workflows/ansible-lint.yml) -Requirements ------------- +This role will inventory your device or VM and update that record in Netbox -Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. +Execution order -Role Variables --------------- +- Determine Host (Physical) or Guest (Virtual) machine +- Pull any existing records from Netbox +- Write new record to Netbox +- Enumerate network adapters and create in Netbox +- Enumerate bond adapters and create in Netbox + +## Requirements + +In order to run this role you will require: +- A working installation of Netbox with a reachable API from your Ansible Host machine (the machine you wish to run Ansible on) + +The following variables will also need to be set: + +| Variable Name | Type | Required | Default | Example | Playbook Env example | +| -------------------------- | ---- | -------- | -------------------------------------------- | ---------------------------- | --------------------------------------------------------- | +| inventory_netbox_api | str | true | `{{ netbox_api }}` | https://netboxurl.domain.tld | `netbox_api: "{{ lookup('env', 'NETBOX_API') }}"` | +| inventory_netbox_api_key | str | true | `{{ netbox_api_key }}` | abcdef1234567890 | `netbox_api_key: "{{ lookup('env', 'NETBOX_API_KEY') }}"` | +| inventory_netbox_validcert | bool | false | `{{ netbox_validcert }} \| default(true) }}` | true | | + +## Role Variables A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. -Dependencies ------------- +## Dependencies A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. -Example Playbook ----------------- +## Example Playbook Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: - - hosts: servers - roles: - - { role: username.rolename, x: 42 } +```yaml +--- +- name: Inventory CI into Netbox + hosts: + - hostname + - group + + # - p-vibobjectstor-2.vib.local + # become: true # This shouldn't occour at the playbook level + gather_facts: true + roles: + - inventory + vars: + # Standard variables for Netbox integration + netbox_api: "{{ lookup('env', 'NETBOX_API') }}" # This must be defined in your environmental variables. + netbox_api_key: "{{ lookup('env', 'NETBOX_API_KEY') }}" # This must be defined in your environmental variables. DO NOT HARD CODE! + netbox_validcert: false # Change this variable to true if your Netbox server is using untrusted (i.e: self-signed) certificates -License -------- +``` + +## License BSD -Author Information ------------------- +## Author Information + +**Tristan Findley** + +Find out more about me [here](https://about.me/tfindley). + +If you're fan of my work and would like to show your support: + +[!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/yellow_img.png)](https://www.buymeacoffee.com/tristan) -An optional section for the role authors to include contact information, or a website (HTML is not allowed). +[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/Z8Z016573P) diff --git a/defaults/main.yml b/defaults/main.yml index 24ae9ac..867e5c9 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,6 +1,11 @@ --- # defaults file for inventory +# Input variables +inventory_netbox_api: "{{ netbox_api }}" +inventory_netbox_api_key: "{{ netbox_api_key }}" +inventory_netbox_validcert: "{{ netbox_validcert | default(true) }}" + # inventory_os_tag: "os_{{ ansible_system | lower }}_{{ ansible_distribution | lower }}{% if ansible_distribution_major_version is defined %}_{{ ansible_distribution_major_version }}{% if ansible_distribution_minor_version is defined %}_{{ ansible_distribution_minor_version }}{% endif %}{% endif %}" # noqa: yaml[line-length] inventory_os_selection_slug: "{{ ansible_system | lower }}_{{ ansible_distribution | lower }}{% if ansible_distribution_major_version is defined %}_{{ ansible_distribution_major_version }}{% if ansible_distribution_minor_version is defined %}_{{ ansible_distribution_minor_version }}{% endif %}{% endif %}" # noqa: yaml[line-length] inventory_os_tag: "os_{{ inventory_os_selection_slug }}" # No need to do this twice so we use the OS selection slug var. @@ -15,3 +20,5 @@ inventory_custom_fields_mapping: ssh_host_key_ed25519: "{{ ansible_ssh_host_key_ed25519_public }}" # ssh_host_key_rsa_public: "{{ ansible_ssh_host_key_rsa_public }}" os_version: "{{ inventory_os_selection_slug }}" + +inventory_primary_ipv4: "{{ ansible_default_ipv4.address }}/{{ _inventory_primary_ipv4_cidr_logic | ansible.utils.ipaddr('prefix') }}" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c371a23 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,40 @@ +ansible==9.5.1 +ansible-compat==4.1.11 +ansible-core==2.16.6 +ansible-lint==24.2.3 +attrs==23.2.0 +black==24.4.2 +bracex==2.4 +certifi==2024.2.2 +cffi==1.16.0 +charset-normalizer==3.3.2 +click==8.1.7 +cryptography==42.0.5 +filelock==3.14.0 +idna==3.7 +Jinja2==3.1.3 +jsonschema==4.22.0 +jsonschema-specifications==2023.12.1 +markdown-it-py==3.0.0 +MarkupSafe==2.1.5 +mdurl==0.1.2 +mypy-extensions==1.0.0 +netaddr==1.2.1 +packaging==23.2 +pathspec==0.12.1 +platformdirs==4.2.1 +pycparser==2.22 +Pygments==2.17.2 +pynetbox==7.3.3 +PyYAML==6.0.1 +referencing==0.35.1 +requests==2.31.0 +resolvelib==1.0.1 +rich==13.7.1 +rpds-py==0.18.0 +ruamel.yaml==0.18.6 +ruamel.yaml.clib==0.2.8 +subprocess-tee==0.4.1 +urllib3==2.2.1 +wcmatch==8.5.1 +yamllint==1.35.1 diff --git a/requirements.yml b/requirements.yml new file mode 100644 index 0000000..cbfdf75 --- /dev/null +++ b/requirements.yml @@ -0,0 +1,4 @@ +--- +collections: + - name: netbox.netbox + version: '3.19.0' diff --git a/tasks/device/adapter.yml b/tasks/device/adapter.yml index ab83580..6fa8ca8 100644 --- a/tasks/device/adapter.yml +++ b/tasks/device/adapter.yml @@ -69,9 +69,9 @@ connection: local become: false netbox.netbox.netbox_device_interface: - netbox_url: "{{ netbox_api }}" - netbox_token: "{{ netbox_api_key }}" - validate_certs: "{{ netbox_validcert }}" + netbox_url: "{{ inventory_netbox_api }}" + netbox_token: "{{ inventory_netbox_api_key }}" + validate_certs: "{{ inventory_netbox_validcert }}" data: device: "{{ inventory_hostname }}" name: "{{ network_adapters[interface_name]['name'] }}" diff --git a/tasks/device/device.yml b/tasks/device/device.yml index f21d1e6..027a0a3 100644 --- a/tasks/device/device.yml +++ b/tasks/device/device.yml @@ -30,34 +30,20 @@ ansible.builtin.set_fact: inventory_model_output: 'PowerEdge R760xa' -# - name: Debug variables -# ansible.builtin.debug: -# msg: | -# device_type "{{ inventory_mb_lookup.manufacturer }}_{{ inventory_model_output.stdout | lower | replace(' ', '_') }}" -# when: not ansible_check - -# ------ - -- name: Calculate device netmask - ansible.builtin.set_fact: - _inventory_device_cidr: "{{ ansible_default_ipv4.network }}/{{ ansible_default_ipv4.netmask }}" - -# ------ - - name: Write CI information delegate_to: localhost connection: local become: false netbox.netbox.netbox_device: - netbox_url: "{{ netbox_api }}" - netbox_token: "{{ netbox_api_key }}" - validate_certs: "{{ netbox_validcert }}" + netbox_url: "{{ inventory_netbox_api }}" + netbox_token: "{{ inventory_netbox_api_key }}" + validate_certs: "{{ inventory_netbox_validcert }}" data: name: "{{ inventory_hostname }}" # device_type: "{{ inventory_model_output.stdout | lower | replace(' ', '-') }}" custom_fields: "{{ inventory_custom_fields_mapping }}" device_type: "{{ inventory_mb_lookup.manufacturer }}_{{ inventory_model_output.stdout | lower | replace(' ', '_') }}" - primary_ip4: "{{ ansible_default_ipv4.address }}/{{ _inventory_device_cidr | ansible.utils.ipaddr('prefix') }}" + primary_ip4: "{{ inventory_primary_ipv4 }}" serial: "{{ inventory_serial_output.stdout | default(omit) }}" tags: "{{ netbox_ci_info.device.tags + inventory_add_tags }}" state: present diff --git a/tasks/device/fetch.yml b/tasks/device/fetch.yml index 4af3a0c..8cf0387 100644 --- a/tasks/device/fetch.yml +++ b/tasks/device/fetch.yml @@ -8,8 +8,8 @@ when: - ansible_virtualization_role == "host" netbox.netbox.netbox_device: - netbox_url: "{{ netbox_api }}" - netbox_token: "{{ netbox_api_key }}" - validate_certs: "{{ netbox_validcert }}" + netbox_url: "{{ inventory_netbox_api }}" + netbox_token: "{{ inventory_netbox_api_key }}" + validate_certs: "{{ inventory_netbox_validcert }}" data: name: "{{ inventory_hostname }}" diff --git a/tasks/preflight.yml b/tasks/preflight.yml index b1a8223..a9ccc51 100644 --- a/tasks/preflight.yml +++ b/tasks/preflight.yml @@ -6,28 +6,28 @@ become: false ansible.builtin.assert: that: - - netbox_api is defined and netbox_api| length > 0 - - netbox_api_key is defined and netbox_api_key | length > 0 + - inventory_netbox_api is defined and inventory_netbox_api | length > 0 + - inventory_netbox_api_key is defined and inventory_netbox_api_key | length > 0 - name: Check that you can connect to NetBox delegate_to: localhost connection: local become: false ansible.builtin.uri: - url: "{{ netbox_api }}" - validate_certs: "{{ netbox_validcert }}" + url: "{{ inventory_netbox_api }}" + validate_certs: "{{ inventory_netbox_validcert }}" - name: Test NetBox API Key delegate_to: localhost connection: local become: false ansible.builtin.uri: - url: "{{ netbox_api }}/api/" - validate_certs: "{{ netbox_validcert }}" + url: "{{ inventory_netbox_api }}/api/" + validate_certs: "{{ inventory_netbox_validcert }}" method: GET return_content: true headers: - Authorization: Token {{ netbox_api_key }} + Authorization: Token {{ inventory_netbox_api_key }} Accept: application/json register: api_check failed_when: diff --git a/tasks/virtual/adapter.yml b/tasks/virtual/adapter.yml index 2467fd1..f220b1f 100644 --- a/tasks/virtual/adapter.yml +++ b/tasks/virtual/adapter.yml @@ -46,9 +46,9 @@ connection: local become: false netbox.netbox.netbox_vm_interface: - netbox_url: "{{ netbox_api }}" - netbox_token: "{{ netbox_api_key }}" - validate_certs: "{{ netbox_validcert }}" + netbox_url: "{{ inventory_netbox_api }}" + netbox_token: "{{ inventory_netbox_api_key }}" + validate_certs: "{{ inventory_netbox_validcert }}" data: virtual_machine: "{{ inventory_hostname }}" name: "{{ network_adapters[interface_name]['name'] }}" diff --git a/tasks/virtual/fetch.yml b/tasks/virtual/fetch.yml index 5c317b3..30ce31b 100644 --- a/tasks/virtual/fetch.yml +++ b/tasks/virtual/fetch.yml @@ -7,8 +7,8 @@ check_mode: true register: netbox_ci_info netbox.netbox.netbox_virtual_machine: - netbox_url: "{{ netbox_api }}" - netbox_token: "{{ netbox_api_key }}" - validate_certs: "{{ netbox_validcert }}" + netbox_url: "{{ inventory_netbox_api }}" + netbox_token: "{{ inventory_netbox_api_key }}" + validate_certs: "{{ inventory_netbox_validcert }}" data: name: "{{ inventory_hostname }}" diff --git a/tasks/virtual/machine.yml b/tasks/virtual/machine.yml index fb1fdb7..ec161c8 100644 --- a/tasks/virtual/machine.yml +++ b/tasks/virtual/machine.yml @@ -1,24 +1,16 @@ --- -# ------ - -- name: Calculate VM netmask - ansible.builtin.set_fact: - _inventory_machine_cidr: "{{ ansible_default_ipv4.network }}/{{ ansible_default_ipv4.netmask }}" - -# ------ - - name: Write VM information delegate_to: localhost connection: local become: false netbox.netbox.netbox_virtual_machine: - netbox_url: "{{ netbox_api }}" - netbox_token: "{{ netbox_api_key }}" - validate_certs: "{{ netbox_validcert }}" + netbox_url: "{{ inventory_netbox_api }}" + netbox_token: "{{ inventory_netbox_api_key }}" + validate_certs: "{{ inventory_netbox_validcert }}" data: name: "{{ inventory_hostname }}" custom_fields: "{{ inventory_custom_fields_mapping }}" - primary_ip4: "{{ ansible_default_ipv4.address }}/{{ _inventory_machine_cidr | ansible.utils.ipaddr('prefix') }}" + primary_ip4: "{{ inventory_primary_ipv4 }}" tags: "{{ netbox_ci_info.virtual_machine.tags + inventory_add_tags }}" state: present diff --git a/vars/main.yml b/vars/main.yml index afb1fcd..5e004f4 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -4,6 +4,8 @@ inventory_sfp_check: false inventory_model_output: 'unset' inventory_serial_output: 'unset' +_inventory_primary_ipv4_cidr_logic: "{{ ansible_default_ipv4.network }}/{{ ansible_default_ipv4.netmask }}" + _inventory_mb_logic: "dell inc.": serialno: "dmidecode -t system | grep Serial | cut -d ':' -f 2 | cut -d ' ' -f 2"