From f166992fc451a4ad47de00ae5e2a6acb069b8168 Mon Sep 17 00:00:00 2001 From: Nicholas Kuechler Date: Tue, 14 Oct 2025 16:57:31 -0500 Subject: [PATCH] feat(nautobot): Adds ansible and kubernetes job to sync device types --- ansible/playbooks/nautobot-device-types.yaml | 34 +++++++ ansible/playbooks/nautobot-initial-setup.yaml | 1 + .../roles/device_types/tasks/device_types.yml | 88 +++++++++++++++++++ ansible/roles/device_types/tasks/main.yml | 24 +++++ 4 files changed, 147 insertions(+) create mode 100644 ansible/playbooks/nautobot-device-types.yaml create mode 100644 ansible/roles/device_types/tasks/device_types.yml create mode 100644 ansible/roles/device_types/tasks/main.yml diff --git a/ansible/playbooks/nautobot-device-types.yaml b/ansible/playbooks/nautobot-device-types.yaml new file mode 100644 index 000000000..9e939679c --- /dev/null +++ b/ansible/playbooks/nautobot-device-types.yaml @@ -0,0 +1,34 @@ +--- +# Copyright (c) 2025 Rackspace Technology, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Set up device types in Nautobot + connection: local + hosts: nautobot + gather_facts: false + + pre_tasks: + - name: Ensure nautobot is up and responding + ansible.builtin.uri: + url: "{{ nautobot_url }}/health/" + method: GET + validate_certs: false + register: nautobot_up_check + until: nautobot_up_check.status == 200 + retries: 24 # Retries for 24 * 5 seconds = 120 seconds = 2 minutes + delay: 5 # Every 5 seconds + check_mode: false + + roles: + - role: device_types diff --git a/ansible/playbooks/nautobot-initial-setup.yaml b/ansible/playbooks/nautobot-initial-setup.yaml index d07dc7bad..530b7454f 100644 --- a/ansible/playbooks/nautobot-initial-setup.yaml +++ b/ansible/playbooks/nautobot-initial-setup.yaml @@ -50,3 +50,4 @@ - role: computed_fields - role: platforms - role: relationships + - role: device_types diff --git a/ansible/roles/device_types/tasks/device_types.yml b/ansible/roles/device_types/tasks/device_types.yml new file mode 100644 index 000000000..54b5f02e7 --- /dev/null +++ b/ansible/roles/device_types/tasks/device_types.yml @@ -0,0 +1,88 @@ +--- +- name: Create default device types + networktocode.nautobot.device_type: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + model: "{{ device_type_item.model }}" + manufacturer: "{{ device_type_item.manufacturer }}" + u_height: "{{ device_type_item.u_height }}" + is_full_depth: "{{ device_type_item.is_full_depth }}" + part_number: "{{ device_type_item.part_number | default('') }}" + comments: "{{ device_type_item.comments | default('') }}" + subdevice_role: "parent" # need to set subdevice_role=parent to allow device bays to be attached + state: present + +- name: Loop through interfaces and add them + networktocode.nautobot.device_interface_template: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + device_type: "{{ device_type_item.model }}" + name: "{{ interface_item.name }}" + type: "{{ interface_item.type }}" + mgmt_only: "{{ interface_item.mgmt_only | default('false') }}" + state: present + loop: "{{ device_type_item.interfaces | default([]) | list }}" + loop_control: + loop_var: interface_item + async: 300 + poll: 0 + register: task1_jobs + +- name: Loop through console ports and add them + networktocode.nautobot.console_port_template: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + device_type: "{{ device_type_item.model }}" + name: "{{ console_port_item.name }}" + type: "{{ console_port_item.type }}" + state: present + loop: "{{ device_type_item['console-ports'] | default([]) | list }}" + loop_control: + loop_var: console_port_item + async: 300 + poll: 0 + register: task2_jobs + +- name: Loop through module bays and add them + networktocode.nautobot.device_bay_template: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + device_type: "{{ device_type_item.model }}" + name: "{{ module_bay_item.name }}" + state: present + loop: "{{ device_type_item['module-bays'] | default([]) | list }}" + loop_control: + loop_var: module_bay_item + async: 300 + poll: 0 + register: task3_jobs + +- name: Loop through power ports and add them + networktocode.nautobot.power_port_template: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + device_type: "{{ device_type_item.model }}" + name: "{{ power_port_item.name }}" + allocated_draw: "{{ power_port_item.allocated_draw | default(1) }}" + maximum_draw: "{{ power_port_item.maximum_draw | default(1) }}" + type: "{{ power_port_item.type }}" + state: present + loop: "{{ device_type_item['power-ports'] | default([]) | list }}" + loop_control: + loop_var: power_port_item + async: 300 + poll: 0 + register: task4_jobs + +- name: Combine all async jobs + ansible.builtin.set_fact: + all_jobs: "{{ task1_jobs.results + task2_jobs.results + task3_jobs.results + task4_jobs.results }}" + +- name: Wait for all API calls (all tasks) + ansible.builtin.async_status: + jid: "{{ item.ansible_job_id }}" + loop: "{{ all_jobs }}" + register: all_results + until: all_results.finished + retries: 30 + delay: 5 diff --git a/ansible/roles/device_types/tasks/main.yml b/ansible/roles/device_types/tasks/main.yml new file mode 100644 index 000000000..1c1184d98 --- /dev/null +++ b/ansible/roles/device_types/tasks/main.yml @@ -0,0 +1,24 @@ +--- +# Device Types as defined in https://rackerlabs.github.io/understack/design-guide/device-types/ + +- name: Collect device types from mounted ConfigMap data + ansible.builtin.set_fact: + device_types_data: "{{ device_types_data | d([]) + [lookup('file', item.src) | from_yaml] }}" + with_community.general.filetree: "/runner/data/device-types/" + when: item.state == "file" + check_mode: false + +- name: Sync manufacturers + networktocode.nautobot.manufacturer: + url: "{{ nautobot_url }}" + token: "{{ nautobot_token }}" + name: "{{ item }}" + description: "{{ item }}" + state: present + loop: "{{ device_types_data | community.general.json_query('[*].manufacturer') | unique }}" + +- name: Loop through device types + ansible.builtin.include_tasks: device_types.yml + loop: "{{ device_types_data }}" + loop_control: + loop_var: device_type_item