--- - name: Update Linode Dynamic Inventory hosts: localhost gather_facts: true connection: local vars: # Override these variables as needed linode_inventory_output_dir: "/tmp/linode_inventory" inventory_format: "json" # or "ini" awx_integration: true cleanup_temp_files: false # Optional filters include_only_running: false specific_regions: [] # e.g., ['us-east', 'us-west'] specific_tags: [] # e.g., ['production', 'web'] pre_tasks: - name: Check for Linode API token (will be injected by AWX credential) ansible.builtin.fail: msg: "Linode API Token credential must be attached to this job template in AWX" when: linode_api_token is undefined or linode_api_token == "" - name: Display configuration ansible.builtin.debug: msg: | Linode Inventory Configuration: Output directory: {{ linode_inventory_output_dir }} Output format: {{ inventory_format }} AWX integration: {{ awx_integration }} Include only running: {{ include_only_running }} roles: - role: linode_inventory vars: linode_api_token: "{{ linode_api_token }}" post_tasks: - name: Display next steps ansible.builtin.debug: msg: | Inventory update complete! Next steps for AWX integration: 1. Copy the inventory script to your SCM repository 2. Create a custom inventory source in AWX 3. Point it to the linode_inventory.py script 4. Set up the Linode API credential Files created: - JSON inventory: {{ linode_inventory_output_dir }}/{{ linode_inventory_output_file }} {% if inventory_format == "ini" %} - INI inventory: {{ linode_inventory_output_dir }}/linode_static_inventory.ini {% endif %} # Optional: Run against discovered Linode hosts - name: Debug and use discovered Linode hosts hosts: localhost gather_facts: false tasks: - name: Check if inventory file exists ansible.builtin.stat: path: "{{ linode_inventory_output_dir | default('/tmp/linode_inventory') }}/{{ linode_inventory_output_file | default('linode_inventory.json') }}" register: inventory_file_stat - name: Display inventory file status ansible.builtin.debug: msg: | Inventory file path: {{ linode_inventory_output_dir | default('/tmp/linode_inventory') }}/{{ linode_inventory_output_file | default('linode_inventory.json') }} File exists: {{ inventory_file_stat.stat.exists }} File size: {{ inventory_file_stat.stat.size | default(0) }} bytes - name: Load and display inventory contents ansible.builtin.slurp: src: "{{ linode_inventory_output_dir | default('/tmp/linode_inventory') }}/{{ linode_inventory_output_file | default('linode_inventory.json') }}" register: inventory_content when: inventory_file_stat.stat.exists - name: Parse inventory JSON ansible.builtin.set_fact: dynamic_inventory: "{{ inventory_content.content | b64decode | from_json }}" when: inventory_file_stat.stat.exists - name: Display parsed inventory summary ansible.builtin.debug: msg: | Inventory loaded successfully! Total hostvars: {{ dynamic_inventory._meta.hostvars | length }} Groups: {{ dynamic_inventory.keys() | reject('equalto', '_meta') | list }} Hosts in hostvars: {{ dynamic_inventory._meta.hostvars.keys() | list }} when: dynamic_inventory is defined - name: Add discovered hosts to in-memory inventory ansible.builtin.add_host: name: "{{ item.key }}" groups: discovered_linodes ansible_host: "{{ item.value.ansible_host }}" linode_id: "{{ item.value.linode_id }}" linode_region: "{{ item.value.linode_region }}" linode_type: "{{ item.value.linode_type }}" linode_status: "{{ item.value.linode_status }}" linode_tags: "{{ item.value.linode_tags }}" is_debian: "{{ item.value.is_debian }}" is_ubuntu: "{{ item.value.is_ubuntu }}" is_k3s: "{{ item.value.is_k3s }}" is_control_plane: "{{ item.value.is_control_plane }}" is_worker_node: "{{ item.value.is_worker_node }}" tag_string: "{{ item.value.tag_string }}" loop: "{{ dynamic_inventory._meta.hostvars | dict2items }}" when: - dynamic_inventory is defined - item.value.linode_status == "running" - name: Display added hosts with tag information ansible.builtin.debug: msg: | Added {{ groups['discovered_linodes'] | default([]) | length }} running Linode hosts to inventory Host details: {% for host in groups['discovered_linodes'] | default([]) %} - {{ host }} ({{ hostvars[host]['ansible_host'] }}) Tags: {{ hostvars[host]['linode_tags'] | join(', ') }} K3s: {{ hostvars[host]['is_k3s'] }} Control Plane: {{ hostvars[host]['is_control_plane'] }} Worker: {{ hostvars[host]['is_worker_node'] }} {% endfor %} - name: Test connection to discovered Linode hosts hosts: discovered_linodes gather_facts: false vars: ansible_user: phlux ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o ConnectTimeout=10' tasks: - name: Test connectivity ansible.builtin.ping: register: ping_result ignore_errors: true - name: Display connectivity status with tag info ansible.builtin.debug: msg: | {{ inventory_hostname }} ({{ ansible_host }}): {{ 'REACHABLE' if ping_result is succeeded else 'UNREACHABLE' }} Tags: {{ linode_tags | join(', ') }} Role: {{ 'Control Plane' if is_control_plane else 'Worker Node' if is_worker_node else 'Other' }} # Example: Run tasks only on k3s control plane nodes - name: Example - Control Plane specific tasks hosts: discovered_linodes gather_facts: false vars: ansible_user: phlux tasks: - name: Control plane specific task ansible.builtin.debug: msg: "This would run control plane specific commands on {{ inventory_hostname }}" when: is_control_plane | bool # Example: Run tasks only on k3s worker nodes - name: Example - Worker Node specific tasks hosts: discovered_linodes gather_facts: false vars: ansible_user: phlux tasks: - name: Worker node specific task ansible.builtin.debug: msg: "This would run worker node specific commands on {{ inventory_hostname }}" when: is_worker_node | bool # Example: Run tasks on all k3s nodes (control plane + workers) - name: Example - All K3s nodes hosts: discovered_linodes gather_facts: false vars: ansible_user: phlux tasks: - name: K3s cluster task ansible.builtin.debug: msg: "This would run on all k3s nodes: {{ inventory_hostname }}" when: is_k3s | bool