303 lines
12 KiB
YAML
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'] }}"
|