ansible_qemu_ceph_xcat_test.../cluster/bootstrap_hypervisors.yml

252 lines
9.3 KiB
YAML

---
- name: populate inventory
hosts: localhost
user: ansible
# become: yes
gather_facts: false
tasks:
######## wipe inventory to ensure this playbook only uses it own dynamically generated variables
- name: refresh inventory
meta: refresh_inventory
######## load core group_vars
#
# load the following core environment files under vars['testbench']
# - inventory/group_vars/cluster.yml
# - inventory/group_vars/networks.yml
- name: load core environment configuration
block:
- name: set runtime facts
ansible.builtin.set_fact:
_env_files:
- 'cluster.yml'
- 'hypervisor.yml'
- 'networks.yml'
_env_dir: "{{ ansible_inventory_sources[0] | dirname }}/group_vars"
config_namespace: "testbench"
- name: include vars from core config files
ansible.builtin.include_vars:
file: "{{ env_path }}"
name: "env_import_{{ env_namespace }}"
loop: "{{ _env_files }}"
loop_control:
loop_var: entry
vars:
env_path: "{{ _env_dir }}/{{ entry }}"
env_namespace: "{{ entry.split('.yml')[0] }}"
- name: append env vars to temp dict
ansible.builtin.set_fact:
_env_dict: "{{ _env_dict | default({}) | combine (env_import, recursive=True) }}"
loop: "{{ lookup('ansible.builtin.varnames', 'env_import_').split(',') }}"
loop_control:
loop_var: entry
vars:
env_import: "{{ vars[entry] }}"
- name: copy dict of env vars under top level namespace, access @ vars[config_namespace]
ansible.builtin.set_fact:
{ "{{ config_namespace }}": "{{ _env_dict }}" }
# think i only need to include hypervisor.yml here - it looks nicer to only include a small set of vars then ref directly at top level not config_namespace
######## populate arp cache, find dhcp ip of hypervisor and add to inventory
# uncomment if arp cache stale, this is slow so comment during dev
# - name: populate arp cache
# command: nmap -sn {{ range }}
# vars:
# dhcp_network: "{{ vars[config_namespace]['hypervisor']['nmcli_con_names']['primary'] }}"
# network: "{{ vars[config_namespace]['hypervisor']['cluster_networks'][dhcp_network]['network'] }}"
# netmask: "{{ vars[config_namespace]['hypervisor']['cluster_networks'][dhcp_network]['netmask'] }}"
# range: "{{ network }}/{{ (network + '/' + netmask) | ansible.utils.ipaddr('prefix') }}"
# WSL2 specific method to get host arp cache
- name: get arp table
ansible.builtin.command: '/mnt/c/Windows/system32/arp.exe -a'
register: _arp_cache
# windows arp.exe parse, write new mac_map with dhcp_ip
- name: find dhcp ip
ansible.builtin.set_fact:
_update_mac_map: "{{ _update_mac_map | default([]) + [new_record] }}"
loop: "{{ _arp_cache['stdout_lines'] }}"
loop_control:
loop_var: entry
vars:
check_record: "{{ entry | trim | regex_search('^[0-9]+') is not none }}"
format_record: "{{ entry | trim | regex_replace('\\s+', ',') | split(',') }}"
dhcp_ip: "{{ format_record[0] }}"
arp_mac: "{{ format_record[1] | regex_replace('-', ':') }}"
mac_map: "{{ vars[config_namespace]['hypervisor']['mac_map'] }}"
match_host: "{{ mac_map | selectattr('mac', '==', arp_mac) | map(attribute='host') }}"
match_ip: "{{ mac_map | selectattr('mac', '==', arp_mac) | map(attribute='ip') }}"
ipv6_link_local: "{{ 'fe80::0000:0000:0000:0000' | ansible.utils.slaac(arp_mac) }}"
nmcli_con: "{{ mac_map | selectattr('mac', '==', arp_mac) | map(attribute='nmcli_con') }}"
new_record: "{{ { 'host': match_host[0], 'mac': arp_mac, 'dhcp_ip': dhcp_ip, 'ip': match_ip[0], 'ipv6': ipv6_link_local, 'nmcli_con': nmcli_con[0] } }}"
when:
- check_record
- match_host | length >0
- name: fail with insufficient hosts matched, check mac_map
fail:
when:
- _update_mac_map is not defined
- _update_mac_map | length <2
# sort to ensure first host in mac_map gets the first vxlan ip, initially the arp cache dictates the order in which hosts are discovered
- name: sort mac_map
set_fact:
_sort_mac_map: "{{ _sort_mac_map | default([]) + mac_map_entry }}"
loop: "{{ vars[config_namespace]['hypervisor']['mac_map'] }}"
loop_control:
loop_var: entry
vars:
host: "{{ entry['host'] }}"
mac_map_entry: "{{ _update_mac_map | selectattr('host', '==', host) }}"
- name: write global mac map
set_fact:
# mac_map: "{{ _update_mac_map }}"
mac_map: "{{ _sort_mac_map }}"
delegate_to: localhost
delegate_facts: true
######## update the in-memory inventory with the hypervisors
- name: add hosts to in-memory inventory
ansible.builtin.add_host: >
name={{ host }}
groups={{ host_groups }}
ansible_ssh_host={{ ansible_ssh_host }}
ansible_ssh_common_args='-o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no"'
ansible_user={{ ansible_user }}
ansible_password={{ ansible_password }}
loop: "{{ hostvars['localhost']['mac_map'] }}"
loop_control:
loop_var: entry
vars:
host: "{{ entry['host'] }}"
# set host group membership, auto-create groups
host_groups:
- all
- hypervisor
- ceph
ansible_ssh_host: "{{ entry['dhcp_ip'] }}"
ansible_user: "{{ vars[config_namespace]['hypervisor']['ssh_user'] }}"
ansible_password: "{{ vars[config_namespace]['hypervisor']['ssh_password'] }}"
######## bootstrap hypervisors
- name: run roles on hypervisors
hosts: hypervisor
gather_facts: yes
tasks:
######## load core group_vars
#
# load the following core environment files under vars['testbench']
# - inventory/group_vars/cluster.yml
# - inventory/group_vars/networks.yml
- name: load core environment configuration
block:
# roles:
# hypervisor_network - setup interfaces
# hypervisor_vxlan - setup overlay networks - we also want to add ceph_public and ceph_cluster - we should do an overlay here
# hypervisor_ceph - great reference https://github.com/jcmdln/cephadm-playbook
# hypervisor_qemu - not written
# hypervisor_qemu_gui - not written, great qt5 web container for virt-manager that accepts qemu api endpoints over ssh as ENV vars
#
# need a role to replace nested dict items - needs to accept a dict as path maybe
- name: set runtime facts
ansible.builtin.set_fact:
_run_roles:
# - hypervisor_network
# - ntp
# - os_packages
# - hypervisor_prep
# - hypervisor_vxlan
# - cephadm_prep
# - cephadm_bootstrap
- cephadm_services
_env_dir: "{{ ansible_inventory_sources[0] | dirname }}/group_vars"
_env_files:
- 'cluster.yml'
- 'hypervisor.yml'
- 'networks.yml'
config_namespace: "testbench"
- name: include vars from core config files
ansible.builtin.include_vars:
file: "{{ env_path }}"
name: "env_import_{{ env_namespace }}"
loop: "{{ _env_files }}"
loop_control:
loop_var: entry
vars:
env_path: "{{ _env_dir }}/{{ entry }}"
env_namespace: "{{ entry.split('.yml')[0] }}"
- name: append env vars to temp dict
ansible.builtin.set_fact:
_env_dict: "{{ _env_dict | default({}) | combine (env_import, recursive=True) }}"
loop: "{{ lookup('ansible.builtin.varnames', 'env_import_').split(',') }}"
loop_control:
loop_var: entry
vars:
env_import: "{{ vars[entry] }}"
- name: copy dict of env vars under top level namespace, access @ vars[config_namespace]
ansible.builtin.set_fact:
{ "{{ config_namespace }}": "{{ _env_dict }}" }
######## set some global variables used by roles for (vm) cluster node provisioning, if these roles are to be reused in the bootstrap of the hypervisors some static values will be required
# this needs to loop over hypervisor.cluster_networks but exclude primary/external for vxlan creation//
# - debug:
# msg:
# - "{{ groups }}"
# - "{{ ['all'] + hostvars[inventory_hostname]['group_names'] }}"
# - fail:
# msg:
- name: populate the active_role_groups variable, add ceph_cluster network for vxlan creation
ansible.builtin.set_fact:
# active_role_groups: ['all', 'hypervisor', 'ceph'] # this should be a copy of hostvars['groups'] with additional all group
active_role_groups: "{{ ['all'] + hostvars[inventory_hostname]['group_names'] }}"
_cluster_networks: "{{ vars[config_namespace] | combine( {'cluster_networks' :{'cephclus': { 'comment': comment, 'gateway': 'null', 'mtu': 'null', 'nameserver': 'null', 'netmask': netmask, 'network': network } } }, recursive=True) }}"
vars:
network: "{{ vars['hypervisor']['cluster_networks']['cephclus']['network'] }}"
netmask: "{{ vars['hypervisor']['cluster_networks']['cephclus']['netmask'] }}"
comment: "{{ vars['hypervisor']['cluster_networks']['cephclus']['comment'] }}"
- ansible.builtin.set_fact:
{ "{{ config_namespace }}": "{{ _cluster_networks }}" }
######## run roles against hypervisor hosts
# - debug:
# msg:
# - "{{ hostvars[inventory_hostname] }}"
# - fail:
# msg:
- ansible.builtin.include_role:
name: "{{ entry }}"
loop: "{{ _run_roles }}"
loop_control:
loop_var: entry
label: run {{ entry }} role on {{ inventory_hostname }}