482e845d92
In order to improve the readability and robustness of the mnaio feature I have replaced the shell out to virsh tasks to use the virt module where available. I have also created a vm-status play that will hopefully help resolve SSH failures into the VMs. This play utilizes the block/rescue/handler pattern to attempt to restart the VM once if it fails the initial SSH check. Hopefully this will reduce the SSH failures due to a suck VM. This adds a new variable called vm_ssh_timeout which allows the deployer an easy place to override the default timeout. The python-lxml package is needed for the virt module. Change-Id: I027556b71a8c26d08a56b4ffa56b2eeaf1cbabe9
332 lines
11 KiB
YAML
332 lines
11 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: mnaio_hosts
|
|
gather_facts: "{{ gather_facts | default(true) }}"
|
|
environment: "{{ deployment_environment_variables | default({}) }}"
|
|
tags:
|
|
- setup-host
|
|
tasks:
|
|
- 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: 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: Drop host network interfaces
|
|
template:
|
|
src: "pxe/configs/{{ ansible_os_family | lower }}/mnaio-bridges.cfg.j2"
|
|
dest: /etc/network/interfaces.d/mnaio-bridges.cfg
|
|
mode: "0644"
|
|
owner: root
|
|
group: root
|
|
register: mnaio_bridges
|
|
|
|
- name: Ensure extra interfaces are sourced
|
|
lineinfile:
|
|
line: "source /etc/network/interfaces.d/*.cfg"
|
|
dest: "/etc/network/interfaces"
|
|
regexp: "^source /etc/network/interfaces.d/.*"
|
|
|
|
- name: Set the host intefaces up
|
|
command: "/sbin/ifup {{ item.value.iface }}"
|
|
with_dict: "{{ mnaio_host_networks }}"
|
|
when: mnaio_bridges is changed
|
|
|
|
- name: Disable default virt network
|
|
virt_net:
|
|
name: "default"
|
|
state: inactive
|
|
autostart: no
|
|
|
|
- name: List virt network(s)
|
|
virt_net:
|
|
command: list_nets
|
|
register: vm_networks
|
|
|
|
- name: Define virt network(s)
|
|
virt_net:
|
|
command: define
|
|
name: "{{ item.value.iface }}"
|
|
xml: "{{ lookup('template', 'kvm/libvirt-network-template.xml.j2') }}"
|
|
with_dict: "{{ mnaio_host_networks }}"
|
|
when: "item.value.iface not in vm_networks.list_nets"
|
|
|
|
- name: Create virt network(s)
|
|
virt_net:
|
|
command: create
|
|
name: "{{ item.value.iface }}"
|
|
autostart: true
|
|
with_dict: "{{ mnaio_host_networks }}"
|
|
when: "item.value.iface not in vm_networks.list_nets"
|
|
|
|
- name: Locate data volume
|
|
command: "vgdisplay vg01"
|
|
failed_when: false
|
|
when:
|
|
- default_vm_disk_mode | default('lvm') == "lvm"
|
|
register: data_volume
|
|
|
|
- name: Locate data disk
|
|
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
|
|
when:
|
|
- default_vm_disk_mode | default('lvm') == "lvm"
|
|
- data_volume.rc != 0
|
|
- mnaio_data_disk is undefined
|
|
|
|
- name: Create data disk label
|
|
command: "parted --script /dev/{{ mnaio_data_disk | default(lsblk.stdout) }} mklabel gpt"
|
|
when:
|
|
- default_vm_disk_mode | default('lvm') == "lvm"
|
|
- data_volume.rc != 0
|
|
|
|
- name: Create data disk partition
|
|
command: "parted --align optimal --script /dev/{{ mnaio_data_disk | default(lsblk.stdout) }} mkpart data1 ext4 0% 100%"
|
|
when:
|
|
- default_vm_disk_mode | default('lvm') == "lvm"
|
|
- data_volume.rc != 0
|
|
|
|
- name: Create data volume group
|
|
lvg:
|
|
vg: vg01
|
|
pvs: "/dev/{{ mnaio_data_disk | default(lsblk.stdout) }}1"
|
|
when:
|
|
- default_vm_disk_mode | default('lvm') == "lvm"
|
|
- data_volume.rc != 0
|
|
|
|
- name: Locate virt data volume
|
|
virt_pool:
|
|
name: "vg01"
|
|
command: info
|
|
failed_when: false
|
|
when:
|
|
- default_vm_disk_mode | default('lvm') == "lvm"
|
|
register: virt_data_volume
|
|
|
|
- name: Create /etc/libvirt/storage directory
|
|
file:
|
|
path: "/etc/libvirt/storage/"
|
|
state: "directory"
|
|
|
|
- name: Create virt data volume
|
|
block:
|
|
- name: Create virt pool
|
|
virt_pool:
|
|
command: create
|
|
name: vg01
|
|
|
|
- name: Get virt pool xml
|
|
virt_pool:
|
|
command: get_xml
|
|
name: vg01
|
|
register: virt_pool_xml
|
|
|
|
- name: Write data volume xml
|
|
copy:
|
|
content: "{{ virt_pool_xml.get_xml }}"
|
|
dest: "/etc/libvirt/storage/vg01.xml"
|
|
|
|
- name: Define virt data volume
|
|
virt_pool:
|
|
command: define
|
|
name: vg01
|
|
xml: "/etc/libvirt/storage/vg01.xml"
|
|
autostart: true
|
|
when:
|
|
- default_vm_disk_mode | default('lvm') == "lvm"
|
|
- virt_data_volume.pools is not defined
|
|
|
|
- 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
|