Merge pull request #689 from thekad/feature/inventory_hostname

Adding hostname support to dynamic inventory
This commit is contained in:
Chris Hawk 2025-06-20 13:16:35 -07:00 committed by GitHub
commit 43d8fd6960
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 257 additions and 3 deletions

View file

@ -23,7 +23,7 @@ DOCUMENTATION = """
required: True
choices: ['google.cloud.gcp_compute', 'gcp_compute']
zones:
description: A list of regions in which to describe GCE instances.
description: A list of zones in which to describe GCE instances.
If none provided, it defaults to all zones available to a given project.
type: list
elements: string
@ -48,7 +48,7 @@ DOCUMENTATION = """
hostnames:
description: A list of options that describe the ordering for which
hostnames should be assigned. Currently supported hostnames are
'public_ip', 'private_ip', 'name' or 'labels.vm_name'.
'public_ip', 'private_ip', 'name', 'hostname' or 'labels.vm_name'.
default: ['public_ip', 'private_ip', 'name']
type: list
elements: string
@ -121,7 +121,7 @@ DOCUMENTATION = """
EXAMPLES = """
plugin: google.cloud.gcp_compute
zones: # populate inventory with instances in these regions
zones: # populate inventory with instances in these zones
- us-east1-a
projects:
- gcp-prod-gke-100
@ -248,6 +248,8 @@ class GcpInstance(object):
name = self._get_publicip()
elif order == "private_ip":
name = self._get_privateip()
elif order == "hostname":
name = self.json.get("hostname", self.json["name"] + self.name_suffix)
elif order == "name":
name = self.json["name"] + self.name_suffix
else:

View file

@ -0,0 +1 @@
cloud/gcp

View file

@ -0,0 +1,51 @@
---
- name: Setup test suite
hosts: localhost
connection: local
gather_facts: false
vars_files:
- vars.yml
tasks:
- name: SETUP | Create network
google.cloud.gcp_compute_network:
name: "{{ prefix }}"
project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
auto_create_subnetworks: true
state: present
register: _network
- name: SETUP | Create disks
google.cloud.gcp_compute_disk:
name: "{{ prefix }}-{{ item.name }}"
size_gb: 20
zone: "{{ gcp_zone }}"
project: "{{ gcp_project }}"
service_account_file: "{{ gcp_cred_file }}"
source_image: "{{ gcp_disk_image }}"
auth_kind: "{{ gcp_cred_kind }}"
state: present
register: _disks
loop: "{{ sut }}"
- name: SETUP | Create instance
google.cloud.gcp_compute_instance:
name: "{{ prefix }}-{{ item.name }}"
machine_type: n1-standard-1
disks:
- auto_delete: true
boot: true
source: "{{ _disks.results[idx] }}"
network_interfaces:
- network: "{{ _network }}"
labels: "{{ item.labels | default({}) }}"
hostname: "{{ item.hostname | default(omit) }}"
zone: "{{ gcp_zone }}"
project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
state: present
loop: "{{ sut }}"
loop_control:
index_var: idx

View file

@ -0,0 +1,38 @@
---
- name: Teardown test suite
hosts: localhost
connection: local
gather_facts: false
vars_files:
- vars.yml
tasks:
- name: TEARDOWN | Delete instance # noqa: ignore-errors
google.cloud.gcp_compute_instance:
name: "{{ prefix }}-{{ item.name }}"
zone: "{{ gcp_zone }}"
project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
state: absent
loop: "{{ sut }}"
ignore_errors: true # try to delete as much as possible
- name: TEARDOWN | Delete disk # noqa: ignore-errors
google.cloud.gcp_compute_disk:
name: "{{ prefix }}-{{ item.name }}"
zone: "{{ gcp_zone }}"
project: "{{ gcp_project }}"
service_account_file: "{{ gcp_cred_file }}"
source_image: "{{ gcp_disk_image }}"
auth_kind: "{{ gcp_cred_kind }}"
state: absent
loop: "{{ sut }}"
ignore_errors: true # try to delete as much as possible
- name: TEARDOWN | Delete network
google.cloud.gcp_compute_network:
name: "{{ prefix }}"
project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
state: absent

View file

@ -0,0 +1,30 @@
---
- name: Test
hosts: localhost
connection: local
gather_facts: false
vars_files:
- vars.yml
tasks:
- name: TEST | render inventory file
ansible.builtin.copy:
dest: "../{{ inventory_filename }}"
content: "{{ lookup('template', '../templates/inventory.yml.j2') }}"
mode: preserve
- name: slurp
ansible.builtin.slurp:
src: "../{{ inventory_filename }}"
register: _inv
- name: debug
ansible.builtin.debug:
msg: "{{ _inv.content | b64decode }}"
verbosity: 3
- name: TEST | refresh inventory
ansible.builtin.meta: refresh_inventory
- name: TEST | run test case
ansible.builtin.include_tasks:
file: "testcase_{{ testcase }}.yml"

View file

@ -0,0 +1,16 @@
---
- name: TEST | print hosts
ansible.builtin.debug:
var: groups
- name: TEST | assert instances exist
ansible.builtin.assert:
that:
- groups['all'] | length > 0
- name: TEST | assert grouping works
ansible.builtin.assert:
that:
- groups['gcp_env_prod'] | length == 2
- groups['gcp_cluster_db'] | length == 1
- groups['gcp_cluster_web'] | length == 1

View file

@ -0,0 +1,22 @@
---
- name: TEST | print hosts
ansible.builtin.debug:
var: groups
- name: TEST | fetch instance info for vm1
google.cloud.gcp_compute_instance_info:
filters:
- name = {{ prefix }}-vm1
zone: "{{ gcp_zone }}"
project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
scopes:
- https://www.googleapis.com/auth/compute
register: _vm
- name: TEST | compare API vs inventory hostnames
ansible.builtin.assert:
that:
- _vm.resources | length > 0
- _vm.resources[0].hostname in groups['gcp_dns_static']

View file

@ -0,0 +1,38 @@
---
gcp_region: us-central1
gcp_zones:
- "{{ gcp_region }}-a"
- "{{ gcp_region }}-b"
- "{{ gcp_region }}-c"
- "{{ gcp_region }}-f"
gcp_zone: "{{ gcp_zones | first }}"
gcp_disk_image: projects/centos-cloud/global/images/centos-stream-9-v20250513
prefix: "{{ resource_prefix | default('d3adb33f') }}"
sut:
- name: vm1
hostname: "vm1.static.{{ prefix }}.com"
labels:
dns: static
- name: vm2
labels:
cluster: db
env: prod
- name: vm3
labels:
cluster: web
env: prod
testcase: basic
testcases:
basic:
filters:
- status = RUNNING
hostnames:
- name
hostname:
hostnames:
- hostname
- name
inventory_filename: test.gcp_compute.yml

View file

@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -eux
# test infra
ansible-playbook playbooks/setup.yml "$@"
export ANSIBLE_INVENTORY=test.gcp_compute.yml
RC=0
# we want to run teardown regardless of playbook exit status, so catch the
# exit code of ansible-playbook manually
set +e
for ts in playbooks/testcase_*.yml;
do
testcase=$( basename "$ts" | sed -e 's/testcase_//' | sed -e 's/.yml//' )
ansible-playbook playbooks/test.yml "$@" --extra-vars "testcase=${testcase}"
RC=$?
test $RC -ne 0 && break
done
set -e
unset ANSIBLE_INVENTORY
# delete test infra
ansible-playbook playbooks/teardown.yml "$@"
exit $RC

View file

@ -0,0 +1,27 @@
---
plugin: google.cloud.gcp_compute
zones:
{{ gcp_zones | to_nice_yaml }}
projects:
- {{ gcp_project }}
auth_kind: {{ gcp_cred_kind }}
service_account_file: {{ gcp_cred_file }}
scopes:
- 'https://www.googleapis.com/auth/cloud-platform'
- 'https://www.googleapis.com/auth/compute.readonly'
keyed_groups:
- prefix: gcp
key: labels
name_suffix: .{{ prefix }}.com
filters:
{{ testcases[testcase]['filters'] | default(testcases['basic']['filters']) | default([]) | to_nice_yaml }}
hostnames:
{{ testcases[testcase]['hostnames'] | default(testcases['basic']['hostnames']) | default([]) | to_nice_yaml }}

View file

@ -0,0 +1 @@
# keep empty