ansible_qemu_ceph_xcat_test.../cluster/xcat_dynamic_inventory.yml

303 lines
12 KiB
YAML

---
- name: build inventory
hosts: localhost
# user: ansible
vars:
## default inventory file specified in the ansible.cfg
# _inventory_file_name: "{{ ansible_inventory_sources[0] }}"
#
## custom inventory file
_inventory_file_name: "{{ ansible_inventory_sources[0].split('/')[:-1] | join('/') }}/xcat-inventory.yml"
_overwrite_inventory_file: False
#
## enable dynamic inventory, disables writing inventory file
_dynamic_inventory: True
## xcat API connection
_xcat_api:
xcat_user: "ansible"
xcat_password: "0cf5t33lAcc355"
xcat_http_scheme: "http"
xcat_api_endpoint: "127.0.0.1"
xcat_api_endpoint_port: "80"
# - This playbook can be called as the first task in the runner/site task to act as a purely dynamic inventory sourced from xcat, use the _dynamic_inventory variable to enable
# - it will populate an in-memory inventory from xcat, meaning other inventory files do not need to be written
# - when present, existing inventory file or group_vars/ + host_vars/ inventory sources will also be used as per ansibles inventory sourcing precedence (this will merge hostvars/groups, so watch out)
tasks:
###### getting the xcat web service replying to API calls without ssl, purely for dev
# sudo nano -cw /etc/httpd/conf.d/xcat-ws.conf
# ORIGIONAL
# ScriptAlias /xcatrhevh /opt/xcat/ws/xcatrhevh.cgi
# ScriptAlias /xcatws /opt/xcat/ws/xcatws.cgi
# LoadModule rewrite_module /usr/lib64/apache2-prefork/mod_rewrite.so
# RewriteEngine On
# RewriteCond %{SERVER_PORT} 80
# RewriteCond %{HTTPS} !=on
# RewriteRule ^/?xcatws/(.*) https://%{SERVER_NAME}/xcatws/$1 [R,L]
# RewriteRule ^/?xcatwsv2/(.*) https://%{SERVER_NAME}/xcatwsv2/$1 [R,L]
# <FilesMatch "^(xcatws.cgi|zvmxcatws.cgi)$">
# Require all granted
# </FilesMatch>
# DISABLED SSL AND CHANGE REDIRECT TO CGI SCRIPT @ HTTP
# ScriptAlias /xcatrhevh /opt/xcat/ws/xcatrhevh.cgi
# ScriptAlias /xcatws /opt/xcat/ws/xcatws.cgi
# LoadModule rewrite_module /usr/lib64/apache2-prefork/mod_rewrite.so
# RewriteEngine On
# RewriteCond %{SERVER_PORT} 80
# RewriteCond %{HTTPS} !=off
# RewriteRule ^/?xcatws/(.*) http://%{SERVER_NAME}/xcatws/$1 [R,L]
# RewriteRule ^/?xcatwsv2/(.*) http://%{SERVER_NAME}/xcatwsv2/$1 [R,L]
# <FilesMatch "^(xcatws.cgi|zvmxcatws.cgi)$">
# Require all granted
# </FilesMatch>
###### finding xcat service account password
# [root@xcat01(ansible-service) ~]# /opt/xcat/bin/gettab key=xcat passwd.username passwd.password
# passwd.username: ansible
# passwd.password: 0cf5t33lAcc355
###### testing curl
# curl -X GET 'http://127.0.0.1/xcatws/nodes?userName=ansible&userPW=0cf5t33lAcc355'
###### query the xcat API
- name: set runtime facts
set_fact:
_xcat_api_token: "{{ _xcat_api['xcat_http_scheme'] }}://{{ _xcat_api['xcat_api_endpoint'] }}:{{ _xcat_api['xcat_api_endpoint_port'] }}/xcatws/tokens"
_xcat_api_nodes: "{{ _xcat_api['xcat_http_scheme'] }}://{{ _xcat_api['xcat_api_endpoint'] }}:{{ _xcat_api['xcat_api_endpoint_port'] }}/xcatws/nodes"
- name: get API auth cookie
uri:
url: "{{ _xcat_api_token }}?pretty=1"
validate_certs: no
method: POST
headers:
Content-Type: application/json
body: '{"userName":"{{ xcat_user }}","userPW":"{{ xcat_password }}"}'
body_format: json
status_code: 201
vars:
xcat_user: "{{ _xcat_api['xcat_user'] }}"
xcat_password: "{{ _xcat_api['xcat_password'] }}"
register: request
- name: set API token
set_fact:
_xcat_api_token: "{{ request['json']['token']['id'] }}"
- name: get nodes list
uri:
url: "{{ _xcat_api_nodes }}"
validate_certs: no
method: GET
headers:
X-Auth-Token: "{{ _xcat_api_token }}"
status_code: 200
register: request
- name: set node list
set_fact:
_node_list: "{{ request['json'] }}"
- name: get nodes attributes
uri:
url: "{{ _xcat_api_nodes }}/{{ entry }}?pretty=1"
validate_certs: no
method: GET
headers:
X-Auth-Token: "{{ _xcat_api_token }}"
status_code: 200
loop: "{{ _node_list }}"
loop_control:
loop_var: entry
register: request
# - debug:
# msg:
# - "{{ request }}"
# - "{{ request['results'][1] }}"
# - "{{ _node_list }}"
###### sort the API request into inventory ingestable format
- name: create list of hosts and interfaces
set_fact:
_host_interfaces: "{{ _host_interfaces | default([]) +[ {'host': host, 'interfaces': interfaces} ] }}"
loop: "{{ request['results'] }}"
loop_control:
loop_var: entry
vars:
host: "{{ entry['entry'] }}"
host_record: "{{ entry['json'] }}"
interfaces: "{{ host_record[host] | dict2items | selectattr('key', 'search', '^nicips.' ) | map(attribute='key') | map('split', '.') | map('last') }}"
when:
- interfaces | length >0
- name: build inventory artefacts
set_fact:
_xcat_nics: "{{ _xcat_nics | default([]) +[{ 'host': host, 'intspec': [{ 'device': interface, 'ip': nicip, 'network': nicnetwork, 'type': nictype }] }] }}"
_host_groups: "{{ _host_groups | default([]) +[{ 'host': host, 'groups': remove_all_group }] }}"
# build a dict to the ansible yaml inventory spec, include placeholder fields for xcat_nics/ipmi_nic, these fields will be populated with selectattr based on host name from xcat_nics dict
_all_host_group: "{{ _all_host_group | default({}) | combine({ 'all': { 'hosts': { host: { 'ansible_ssh_host': primary_ip, 'xcat_nics': 'placeholder', 'ipmi_nic': 'placeholder' } } } }, recursive=True) }}"
# unused - groups are created from host entries
# _xcat_groups: "{{ _xcat_groups | default([]) +[remove_all_group] }}"
with_subelements:
- "{{ _host_interfaces }}"
- "interfaces"
loop_control:
loop_var: entry
vars:
host: "{{ entry.0['host'] }}"
interface: "{{ entry.1 }}"
request_host_record: "{{ request['results'] | selectattr('entry', '==', host) | map(attribute='json') }}"
nicips_key: "nicips.{{ interface }}"
nicnetworks_key: "nicnetworks.{{ interface }}"
nictype_key: "nictypes.{{ interface }}"
nicip: "{{ request_host_record[0][host][nicips_key] | default('incomplete_record') }}"
nicnetwork: "{{ request_host_record[0][host][nicnetworks_key] | default('incomplete_record') }}"
nictype: "{{ request_host_record[0][host][nictype_key] | default('incomplete_record') }}"
host_groups: "{{ request_host_record[0][host]['groups'].split(',') | default([]) }}"
# remove 'all' group if added by xcat, this is a special group that will be used to store inventory hostvars and merged into the inventory dict
remove_all_group: "{{ host_groups | difference(['all']) }}"
primary_ip: "{{ request_host_record[0][host]['ip'] }}"
when:
- not nicip == 'incomplete_record'
- not nicnetwork == 'incomplete_record'
- not nictype == 'incomplete_record'
- host_groups | length >0
# unused - groups are automatically created from host entries
# - name: set runtime facts
# set_fact:
# _xcat_groups: "{{ _xcat_groups | flatten | unique | sort }}"
- name: build 'all' group inventory dict
set_fact:
_all_host_group: "{{ _all_host_group | default({}) | combine({ 'all': { 'hosts': { host: all_host_group_entry } } }, recursive=True) }}"
loop: "{{ _all_host_group['all']['hosts'] | list }}"
loop_control:
loop_var: entry
vars:
xcat_nics: "{{ _xcat_nics | selectattr('host', '==', entry) | map(attribute='intspec') | flatten | rejectattr('network', '==', 'ipmi') }}"
ipmi_nic: "{{ _xcat_nics | selectattr('host', '==', entry) | map(attribute='intspec') | flatten | selectattr('network', '==', 'ipmi') }}"
host: "{{ entry }}"
all_host_group_entry: "{{ _all_host_group['all']['hosts'][entry] | combine({'xcat_nics': xcat_nics, 'ipmi_nic': ipmi_nic }, recursive=True) }}"
- name: append groups to inventory dict
set_fact:
_other_host_groups: "{{ _other_host_groups | default({}) | combine({ group: { 'hosts': { host: none } } }, recursive=True) }}"
with_subelements:
- "{{ _host_groups }}"
- "groups"
loop_control:
loop_var: entry
vars:
host: "{{ entry.0['host'] }}"
group: "{{ entry.1 }}"
- name: combine _all_host_group with _other_host_groups, inventory complete
set_fact:
_all_host_group: "{{ _all_host_group | default({}) | combine(_other_host_groups, recursive=True) }}"
###### write the inventory dict to flat file
- name: write flat file inventory
block:
- name: find current user uid facts
ansible.builtin.getent:
database: passwd
key: "{{ current_user }}"
vars:
current_user: "{{ lookup('env', 'USER') }}"
- name: get current uid:gid
ansible.builtin.set_fact:
_current_uid: "{{ ansible_facts['getent_passwd'][current_user][1] }}"
_current_gid: "{{ ansible_facts['getent_passwd'][current_user][2] }}"
vars:
current_user: "{{ lookup('env', 'USER') }}"
- name: find current user primary group gid facts
getent:
database: group
key: "{{ _current_gid }}"
- name: get user/group names
set_fact:
_current_user: "{{ current_user }}"
_current_group: "{{ primary_group[0] }}"
vars:
current_user: "{{ lookup('env', 'USER') }}"
primary_group: "{{ ansible_facts['getent_group'] | dict2items | map(attribute='key') }}"
- name: check for existing inventory file
ansible.builtin.stat:
path: "{{ _inventory_file_name }}"
register: _inventory_present
# note: the regex removal of 'null' (sourced from _other_host_groups {host: none}), this tidies the inventory file to look like the ansible spec examples although it is invalid yaml
# ansible doesnt mind the 'null' host value in an inventory file but doesnt like strings
- name: write to file
copy:
content: |
#jinja2: lstrip_blocks: True
{{ _all_host_group | to_nice_yaml(indent=2,sort_keys=False) | regex_replace('null', '') }}
dest: "{{ _inventory_file_name }}"
force: true
owner: "{{ _current_user }}"
group: "{{ _current_group }}"
mode: 0640
when:
- not _inventory_present['stat']['exists'] | bool or _overwrite_inventory_file | bool
# test inventory
# ansible <some group name> -i output.yml -a "uname -a"
when:
- not _dynamic_inventory
###### write the networks dict to flat file
# this same logic should be used to get all unique networks - these will be used in an api query
# need to also get some other info from xcat such as the cluster name?
###### add hosts to in-memory inventory
- name: add hosts to in-memory inventory
add_host: >
name={{ host }}
groups={{ host_groups }}
ansible_ssh_host={{ ansible_ssh_host }}
xcat_nics={{ xcat_nics }}
ipmi_nic={{ ipmi_nic }}
dynamic_inventory=True
loop: "{{ _all_host_group['all']['hosts'] | list }}"
loop_control:
loop_var: entry
vars:
host: "{{ entry }}"
ansible_ssh_host: "{{ _all_host_group['all']['hosts'][entry]['ansible_ssh_host'] }}"
xcat_nics: "{{ _all_host_group['all']['hosts'][entry]['xcat_nics'] }}"
ipmi_nic: "{{ _all_host_group['all']['hosts'][entry]['ipmi_nic'] }}"
host_groups: "{{ _host_groups | selectattr('host', '==', entry) | map(attribute='groups') | flatten | unique }}"
when:
- _dynamic_inventory
# - debug:
# msg:
# - "{{ hostvars['compute001'] }}"
# - "{{ groups }}"
# - "{{ hostvars['compute001']['dynamic_inventory'] }}"