openstack-ansible-ops/multi-node-aio/playbooks/setup-host.yml

419 lines
14 KiB
YAML

---
# Copyright 2018, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in witing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
- name: Gather facts
hosts: vm_hosts
gather_facts: "{{ gather_facts | default(true) }}"
environment: "{{ deployment_environment_variables | default({}) }}"
tags:
- setup-host
tasks:
- name: Check for a supported Operating System
assert:
that:
- (ansible_distribution == 'Ubuntu' and ansible_distribution_release == 'xenial') or
(ansible_distribution == 'Ubuntu' and ansible_distribution_release == 'bionic')
msg: >-
The only supported host platforms for this tooling are Ubuntu 16.04 LTS (Xenial)
and Ubuntu 18.04 LTS (Bionic). Patches to add support for other distributions are
most welcome.
- name: Gather variables for each operating system
include_vars: "{{ item }}"
with_first_found:
- "{{ playbook_dir }}/vars/{{ ansible_distribution | lower }}-{{ ansible_distribution_version | lower }}.yml"
- "{{ playbook_dir }}/vars/{{ ansible_distribution | lower }}-{{ ansible_distribution_major_version | lower }}.yml"
- "{{ playbook_dir }}/vars/{{ ansible_os_family | lower }}-{{ ansible_distribution_major_version | lower }}.yml"
- "{{ playbook_dir }}/vars/{{ ansible_distribution | lower }}.yml"
- "{{ playbook_dir }}/vars/{{ ansible_os_family | lower }}.yml"
tags:
- always
- name: Install pre-requisite host distro packages
package:
name: "{{ mnaio_host_required_distro_packages }}"
state: "latest"
update_cache: yes
cache_valid_time: 600
register: _install_required_host_packages
until: _install_required_host_packages is success
retries: 3
delay: 15
when:
- "mnaio_host_required_distro_packages | length > 0"
- name: Add/Remove/Update apt repositories
apt_repository:
repo: "{{ repo.repo }}"
state: "{{ repo.state | default('present') }}"
filename: "{{ repo.filename | default(omit) }}"
update_cache: no
with_items: "{{ mnaio_host_package_repos }}"
loop_control:
loop_var: repo
register: _add_apt_repo
when:
- "ansible_os_family == 'Debian'"
- "mnaio_host_package_repos | length > 0"
- "(repo.condition | default(True)) | bool"
- name: Update apt cache
apt:
update_cache: yes
register: _update_apt_cache
until: _update_apt_cache is success
retries: 3
delay: 15
when:
- "ansible_os_family == 'Debian'"
- "_add_apt_repo is changed"
- name: Install host distro packages
package:
name: "{{ mnaio_host_distro_packages }}"
state: "latest"
update_cache: yes
cache_valid_time: 600
register: _install_host_packages
until: _install_host_packages is success
retries: 3
delay: 15
- name: Get version of libguestfs
shell: >-
guestfish --version | awk '{print $2}'
changed_when: false
register: _libguestfs_version
# See:
# https://bugzilla.redhat.com/show_bug.cgi?id=1591617
# https://bugs.launchpad.net/ubuntu/+source/libguestfs/+bug/1615337
# Exit codes:
# 0 - Fix already enabled
# 1 - Error
# 2 - Fix enabled by task (should show task as changed)
- name: Apply workaround for older versions to make guestfish work
shell: |
set -e
TEST_FILE_PATH='/usr/lib/x86_64-linux-gnu/guestfs/supermin.d/zz-dash-packages'
if [[ ! -e ${TEST_FILE_PATH} ]] || ! grep -q dash ${TEST_FILE_PATH}; then
echo dash > ${TEST_FILE_PATH}
rm -rf /var/tmp/.guestfs*
exit 2
fi
args:
executable: /bin/bash
when:
- (_libguestfs_version.stdout is version('1.38.1', '<')) or
((_libguestfs_version.stdout is version('1.39.0', '>=')) and
(_libguestfs_version.stdout is version('1.39.1', '<')))
register: _libguestfs_fix
changed_when: _libguestfs_fix.rc == 2
failed_when: _libguestfs_fix.rc not in [0, 2]
# If the host had already installed kvm_intel.ko without nested=1, then
# re-load it now, honoring whatever is in qemu-system-x86.modprobe
# Exit codes:
# 0 - Nested virt already enabled
# 1 - Error
# 2 - Nested virt enabled by task (should show task as changed)
# 3 - Nested virt not available
- name: Ensure that nested virtualization is enabled (if it is available)
shell: |
set -e
INTEL_NESTED=/sys/module/kvm_intel/parameters/nested
if grep -q kvm_intel /proc/modules; then
echo "Intel CPU found. Checking for nested virtualization capabilities."
if [ -f ${INTEL_NESTED} ]; then
echo "Nested virtualization capability found. Checking if it is enabled."
v=$(cat ${INTEL_NESTED})
if [ "x${v}" != "xY" ]; then
echo "Nested virtualization not enabled. Enabling it now."
rmmod kvm_intel && modprobe kvm_intel
exit 2
else
echo "Nested virtualization already enabled."
fi
else
echo "Nested virtualization capability not found."
exit 3
fi
else
echo "Intel CPU not found."
exit 3
fi
args:
executable: /bin/bash
register: _enable_nested_virt
changed_when: _enable_nested_virt.rc == 2
failed_when: _enable_nested_virt.rc not in [0, 2, 3]
- name: Ensure root has a .ssh directory
file:
path: /root/.ssh
state: directory
owner: root
group: root
mode: 0700
- name: Create ssh key pair for root
user:
name: root
generate_ssh_key: yes
ssh_key_bits: 2048
ssh_key_file: /root/.ssh/id_rsa
- name: Get root public key
command: cat /root/.ssh/id_rsa.pub
register: public_key_get
changed_when: false
- name: Set key facts
set_fact:
root_public_key: "{{ public_key_get.stdout }}"
- name: Ensure root can ssh to localhost
authorized_key:
user: "root"
key: "{{ root_public_key }}"
- name: Setup SSH client to disable strict host key checks
lineinfile:
path: /etc/ssh/ssh_config
regexp: "^.*StrictHostKeyChecking.*$"
line: " StrictHostKeyChecking no"
insertafter: "^Host \\*$"
state: present
- name: Setup SSH client to have a non-persistant known hosts file
lineinfile:
path: /etc/ssh/ssh_config
regexp: "^.*UserKnownHostsFile.*$"
line: " UserKnownHostsFile=/dev/null"
insertafter: "^Host \\*$"
state: present
- name: Setup SSH client to disable DNS host key checks
lineinfile:
path: /etc/ssh/ssh_config
regexp: "^.*VerifyHostKeyDNS.*$"
line: " VerifyHostKeyDNS no"
insertafter: "^Host \\*$"
state: present
- name: Add sysctl options
sysctl:
name: net.ipv4.ip_forward
value: 1
sysctl_set: yes
state: present
reload: yes
sysctl_file: /etc/sysctl.conf
- name: Get gateway interface
shell: "/sbin/ip r g 1 | awk '{print $5}'"
register: gw_iface
- set_fact:
masquerade_interface: "{{ gw_iface.stdout.strip() }}"
- name: Add IPtables rules
iptables:
table: "{{ item.table | default(omit) }}"
chain: "{{ item.chain | default(omit) }}"
in_interface: "{{ item.in_interface | default(omit) }}"
out_interface: "{{ item.out_interface | default(omit) }}"
source: "{{ item.source | default(omit) }}"
destination: "{{ item.destination | default(omit) }}"
protocol: "{{ item.protocol | default(omit) }}"
match: "{{ item.match | default(omit) }}"
destination_port: "{{ item.destination_port | default(omit) }}"
jump: "{{ item.jump | default(omit) }}"
to_ports: "{{ item.to_ports | default(omit) }}"
with_items: "{{ mnaio_host_iptables_rules }}"
# These rules are added manually due to bugs in the iptables module.
- name: Add IPtables rules
shell: |
if ! iptables -w -t {{ item.table }} -C {{ item.rule }};then
iptables -w -t {{ item.table }} -I {{ item.rule }}
fi
with_items:
- table: 'nat'
rule: 'POSTROUTING -s 10.0.2.0/22 ! -d 10.0.2.0/22 -j MASQUERADE'
- table: 'mangle'
rule: 'POSTROUTING -s 10.0.2.0/22 -o vm-br-dhcp -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill'
- table: 'mangle'
rule: 'POSTROUTING -s 10.0.2.0/22 -o vm-br-dhcp -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill'
- name: Add IPtables pre-routing rules to allow external access to VMs
shell: |
if ! iptables -w -t nat -C PREROUTING -p tcp -d {{ ansible_default_ipv4.address }} --dport {{ item.host_port }} -j DNAT --to {{ item.vm_ip }}:{{ item.vm_port }};then
iptables -w -t nat -I PREROUTING -p tcp -d {{ ansible_default_ipv4.address }} --dport {{ item.host_port }} -j DNAT --to {{ item.vm_ip }}:{{ item.vm_port }}
fi
with_items: "{{ mnaio_host_iptables_prerouting_ports }}"
when: config_prerouting | default(false) | bool
- name: Start netfilter persistent
service:
name: "{{ mnaio_host_iptables_service }}"
state: started
enabled: yes
when:
- ansible_distribution | lower == 'ubuntu'
- name: Deploy systemd-networkd bridge devices
template:
src: "mnaio_host/systemd-networkd-bridges-netdev.j2"
dest: /etc/systemd/network/{{ item.value.iface }}.netdev
mode: "0644"
owner: root
group: root
with_dict:
- "{{ mnaio_host_networks }}"
register: mnaio_bridges
- name: Deploy systemd-networkd bridge networks
template:
src: "mnaio_host/systemd-networkd-bridges-network.j2"
dest: /etc/systemd/network/{{ item.value.iface }}.network
mode: "0644"
owner: root
group: root
with_dict:
- "{{ mnaio_host_networks }}"
register: mnaio_bridges
- name: Restart the systemd-networkd daemon to load new networks
systemd:
name: systemd-networkd
daemon_reload: yes
state: restarted
when:
- mnaio_bridges is changed
- name: Disable default virt network
virt_net:
name: "default"
state: inactive
- name: Prevent default virt network autostart
virt_net:
name: "default"
autostart: no
- name: Define virt network(s)
virt_net:
name: "{{ item.value.iface }}"
state: present
xml: "{{ lookup('template', 'kvm/libvirt-network-template.xml.j2') }}"
with_dict: "{{ mnaio_host_networks }}"
- name: Set virt network(s) to active
virt_net:
name: "{{ item.value.iface }}"
state: active
with_dict: "{{ mnaio_host_networks }}"
- name: Set virt network(s) to autostart
virt_net:
name: "{{ item.value.iface }}"
autostart: yes
with_dict: "{{ mnaio_host_networks }}"
- name: Locate the largest writable data disk if mnaio_data_disk is not set
shell: >
lsblk -brndo NAME,TYPE,FSTYPE,RO,SIZE | awk '/d[b-z]+ disk +0/{ if ($4>m){m=$4; d=$1}}; END{print d}'
register: lsblk
changed_when: false
when:
- mnaio_data_disk is undefined
- name: Setup the data disk partition
parted:
device: "/dev/{{ mnaio_data_disk | default(lsblk.stdout) }}"
label: gpt
number: 1
name: data1
state: present
register: _add_partition
- name: Prepare the data disk file system
filesystem:
fstype: ext4
dev: "/dev/{{ mnaio_data_disk | default(lsblk.stdout) }}1"
force: yes
when:
- _add_partition is changed
- name: Mount the data disk
mount:
src: "/dev/{{ mnaio_data_disk | default(lsblk.stdout) }}1"
path: /data
state: mounted
fstype: ext4
- name: Create the images directory
file:
path: /data/images
owner: root
group: root
mode: "0755"
state: directory
- name: Define the default virt storage pool
virt_pool:
name: default
state: present
xml: |
<pool type='dir'>
<name>default</name>
<target>
<path>/data/images</path>
<permissions>
<mode>0755</mode>
<owner>0</owner>
<group>0</group>
</permissions>
</target>
</pool>
- name: Set default virt storage pool to active
virt_pool:
name: default
state: active
- name: Set default virt storage pool to autostart
virt_pool:
name: default
autostart: yes
- name: Load virtio kernel modules
shell: |
for mod in $(find /lib/modules/$(uname -r) -type f -name 'virtio*.ko'); do
module=$(echo $(basename $mod) | sed 's/\.ko//g')
modprobe ${module}
if ! grep ${module} /etc/modules; then
echo ${module} | tee -a /etc/modules
fi
done
- name: Wait for guest capabilities to appear
command: "virsh capabilities"
register: virsh_caps
until: "'<guest>' in virsh_caps.stdout"
retries: 6
delay: 10