From 83932105efa56b106b278399ed52841f947271db Mon Sep 17 00:00:00 2001 From: Kevin Thompson Date: Sun, 27 Apr 2025 13:36:55 -0500 Subject: [PATCH] Let's just create a role that populates the Linode inventory.. --- inventory/linode_inventory.yml | 7 --- playbooks/inventory/linode_inventory.yml | 16 +++++++ .../files/linode_inventory.py | 47 +++++++++++++++++++ .../inventory/linode_inventory/tasks/main.yml | 17 +++++++ 4 files changed, 80 insertions(+), 7 deletions(-) delete mode 100644 inventory/linode_inventory.yml create mode 100644 playbooks/inventory/linode_inventory.yml create mode 100755 roles/inventory/linode_inventory/files/linode_inventory.py create mode 100644 roles/inventory/linode_inventory/tasks/main.yml diff --git a/inventory/linode_inventory.yml b/inventory/linode_inventory.yml deleted file mode 100644 index 567fcf0..0000000 --- a/inventory/linode_inventory.yml +++ /dev/null @@ -1,7 +0,0 @@ -plugin: linode.cloud.linode -api_token: '{{ lookup("env", "ANSIBLE_PASSWORD") }}' -regions: - - us-east -instance_tags: - - production - - k3s diff --git a/playbooks/inventory/linode_inventory.yml b/playbooks/inventory/linode_inventory.yml new file mode 100644 index 0000000..ec1fb55 --- /dev/null +++ b/playbooks/inventory/linode_inventory.yml @@ -0,0 +1,16 @@ +--- +- name: Build Inventory from Linode + hosts: localhost + gather_facts: false + + roles: + - populate_inventory + +- name: Test connection to Linode VMs + hosts: all + gather_facts: false + + tasks: + - name: Ping each Linode + ansible.builtin.ping + diff --git a/roles/inventory/linode_inventory/files/linode_inventory.py b/roles/inventory/linode_inventory/files/linode_inventory.py new file mode 100755 index 0000000..53273fa --- /dev/null +++ b/roles/inventory/linode_inventory/files/linode_inventory.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +import os +import sys +import requests +import json + +def main(): + linode_token = os.getenv("LINODE_API_TOKEN") or os.getenv("ANSIBLE_PASSWORD") + if not linode_token: + print("Error: LINODE_API_TOKEN or ANSIBLE_PASSWORD environment variable not set.", file=sys.stderr) + sys.exit(1) + + headers = {"Authorization": f"Bearer {linode_token}"} + response = requests.get("https://api.linode.com/v4/linode/instances", headers=headers) + + if response.status_code != 200: + print(f"Error fetching Linode instances: {response.status_code}", file=sys.stderr) + sys.exit(1) + + linodes = response.json()["data"] + + inventory = { + "all": { + "hosts": [], + "vars": {} + }, + "_meta": { + "hostvars": {} + } + } + + for linode in linodes: + hostname = linode["label"] + ipv4 = linode["ipv4"] + + if hostname and ipv4: + public_ip = ipv4[0] + inventory["all"]["hosts"].append(hostname) + inventory["_meta"]["hostvars"][hostname] = { + "ansible_host": public_ip + } + + print(json.dumps(inventory, indent=2)) + +if __name__ == "__main__": + main() diff --git a/roles/inventory/linode_inventory/tasks/main.yml b/roles/inventory/linode_inventory/tasks/main.yml new file mode 100644 index 0000000..cfcd35d --- /dev/null +++ b/roles/inventory/linode_inventory/tasks/main.yml @@ -0,0 +1,17 @@ +--- +- name: Run Linode dynamic inventory script + ansible.builtin.command: "{{ playbook_dir }}/roles/inventory/linode_inventory/files/linode_inventory.py" + register: linode_inventory_raw + changed_when: false + +- name: Parse JSON inventory output + ansible.builtin.set_fact: + linode_inventory: "{{ linode_inventory_raw.stdout | from_json }}" + +- name: Add Linode hosts dynamically + ansible.builtin.add_host: + name: "{{ item.key }}" + ansible_host: "{{ item.value.ansible_host }}" + groups: all + loop: "{{ linode_inventory['_meta']['hostvars'] | dict2items }}" +