openstack-ansible-nspawn_co.../tasks/main.yml

370 lines
13 KiB
YAML

---
# Copyright 2017, 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 writing, 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 physical host facts
setup:
gather_subset: "network,virtual"
delegate_to: "{{ physical_host }}"
delegate_facts: true
run_once: true
- name: Pull systemd version
command: "systemctl --version"
changed_when: false
register: systemd_version
delegate_to: "{{ physical_host }}"
tags:
- skip_ansible_lint
- always
- name: Set facts
set_fact:
nspawn_systemd_version: "{{ systemd_version.stdout_lines[0].split()[-1] }}"
tags:
- always
- name: Gather variables for each operating system
include_vars: "{{ item }}"
with_first_found:
- "{{ hostvars[physical_host]['ansible_distribution'] | lower }}-{{ hostvars[physical_host]['ansible_distribution_version'] | lower }}.yml"
- "{{ hostvars[physical_host]['ansible_distribution'] | lower }}-{{ hostvars[physical_host]['ansible_distribution_major_version'] | lower }}.yml"
- "{{ hostvars[physical_host]['ansible_os_family'] | lower }}-{{ hostvars[physical_host]['ansible_distribution_major_version'] | lower }}.yml"
- "{{ hostvars[physical_host]['ansible_distribution'] | lower }}.yml"
- "{{ hostvars[physical_host]['ansible_os_family'] | lower }}.yml"
tags:
- always
- name: Escape quote container name
command: "systemd-escape {{ inventory_hostname }}"
changed_when: false
register: systemd_escape
delegate_to: "{{ physical_host }}"
tags:
- skip_ansible_lint
- always
- name: Get container status
command: machinectl status "{{ inventory_hostname }}"
register: machinectl_container_status
failed_when: false
changed_when: false
delegate_to: "{{ physical_host }}"
- name: Get container image status
command: machinectl image-status "{{ inventory_hostname }}"
register: machinectl_container_image_status
failed_when: false
changed_when: false
delegate_to: "{{ physical_host }}"
- name: Get image status
command: machinectl image-status "{{ container_image }}"
register: machinectl_image_status
failed_when: false
changed_when: false
delegate_to: "{{ physical_host }}"
- name: Fail if base image does not exist
fail:
msg: >
The base container image "{{ container_image }}" does not exist. Check
the name and try again.
when:
- machinectl_image_status.rc != 0
- name: Locate nspawn config
stat:
path: "/etc/systemd/nspawn/{{ inventory_hostname }}.nspawn"
register: nspawn_config_exists
delegate_to: "{{ physical_host }}"
- name: Slurp existing nspawn config
slurp:
src: "/etc/systemd/nspawn/{{ inventory_hostname }}.nspawn"
register: nspawn_config
changed_when: false
delegate_to: "{{ physical_host }}"
when:
- nspawn_container_preserve_config | bool
- nspawn_systemd_version | int > 219
- nspawn_config_exists.stat.exists | bool
# Check for the existance of an nspawn configuration file. If found slurp it up
# and use it as the base nspawn config file with the option to config template
# override.
- name: Copy container config (existing)
config_template:
content: "{{ nspawn_config.content | b64decode }}"
dest: "/etc/systemd/nspawn/{{ inventory_hostname }}.nspawn"
owner: "root"
group: "root"
mode: "0644"
config_overrides: "{{ container_config_overrides | default({}) }}"
config_type: "ini"
register: container_config_existing
delegate_to: "{{ physical_host }}"
when:
- nspawn_container_preserve_config | bool
- nspawn_config_exists.stat.exists | bool
- nspawn_systemd_version | int > 219
# If no nspawn configuration file exists, create a new config file using the
# default template.
- name: Copy container config (new)
config_template:
src: templates/container_config.nspawn.j2
dest: "/etc/systemd/nspawn/{{ inventory_hostname }}.nspawn"
owner: "root"
group: "root"
mode: "0644"
config_overrides: "{{ container_config_overrides | default({}) }}"
config_type: "ini"
register: container_config_new
delegate_to: "{{ physical_host }}"
when:
- not nspawn_container_preserve_config | bool or
not nspawn_config_exists.stat.exists | bool
- nspawn_systemd_version | int > 219
- name: Copy container config (old)
template:
src: templates/container_config_old.nspawn.j2
dest: "/etc/systemd/system/systemd-nspawn@{{ systemd_escape.stdout }}.service"
owner: "root"
group: "root"
mode: "0644"
register: container_config_old
delegate_to: "{{ physical_host }}"
when:
- nspawn_systemd_version | int < 220
- name: Notice existing container config changed
debug:
msg: >-
The existing container config has changed. While this change has been
noticed, no restart has been performed. By not restarting the container
the system is preserving the state of the environment by not causing
unexpected downtime. For these changes to go into effect the container
must be restarted. This can be done using the following command,
`machinectl [poweroff|start] {{ inventory_hostname }}`. To disable the
configation saving set `nspawn_container_preserve_config` to false.
when:
- container_config_existing is changed
- name: Clone the base container image
command: machinectl clone "{{ container_image }}" "{{ inventory_hostname }}"
when:
- machinectl_container_image_status.rc != 0
register: machinectl_container_clone
retries: 3
delay: 2
until: machinectl_container_clone is success
delegate_to: "{{ physical_host }}"
tags:
- skip_ansible_lint
- name: Set the qgroup limits
block:
- name: Set the qgroup size|compression limits on machines
command: "btrfs qgroup limit {{ item }} /var/lib/machines/{{ inventory_hostname }}"
changed_when: false
delegate_to: "{{ physical_host }}"
with_items:
- "-e {{ nspawn_host_qgroup_space_limit }}"
- "-c {{ nspawn_host_qgroup_compression_limit }}"
when:
- not nspawn_host_machine_quota_disabled
rescue:
- name: Notice regarding quota system
debug:
msg: >-
There was an error processing the setup of qgroups. Check the system
to ensure they're available otherwise disable the quota system by
setting `nspawn_host_machine_quota_disabled` to true.
- name: Container directories
file:
path: "{{ item }}"
state: "directory"
with_items:
- "/openstack/{{ inventory_hostname }}"
- "/openstack/backup/{{ inventory_hostname }}"
- "/openstack/log/{{ inventory_hostname }}"
- "/var/lib/machines/{{ inventory_hostname }}/var/log/journal"
- "/var/lib/machines/{{ inventory_hostname }}/etc/systemd/network"
- "/var/lib/machines/{{ inventory_hostname }}/etc/systemd/nspawn"
- "/var/lib/machines/{{ inventory_hostname }}/var/lib/dbus"
delegate_to: "{{ physical_host }}"
- name: Container RO bind path cleanup
file:
path: "/var/lib/machines/{{ inventory_hostname }}{{ item.dest }}"
state: "absent"
with_items: "{{ nspawn_read_only_host_bindmount }}"
delegate_to: "{{ physical_host }}"
when:
- machinectl_container_status.rc != 0
- name: Container inner service directories
file:
path: "/var/lib/machines/{{ inventory_hostname }}/{{ item.bind_dir_path }}"
state: "directory"
with_items: "{{ container_default_bind_mounts | union(container_bind_mounts | default([])) }}"
delegate_to: "{{ physical_host }}"
- name: Container outer service directories
file:
path: "{{ item.mount_path }}"
state: "directory"
with_items: "{{ container_default_bind_mounts | union(container_bind_mounts | default([])) }}"
delegate_to: "{{ physical_host }}"
- name: Generate machine-id
command: "systemd-machine-id-setup --root=/var/lib/machines/{{ inventory_hostname }}"
args:
creates: "/var/lib/machines/{{ inventory_hostname }}/etc/machine-id"
register: machineid_set
retries: 3
delay: 2
until: machineid_set is success
delegate_to: "{{ physical_host }}"
tags:
- skip_ansible_lint
- name: Create dbus machine-id
copy:
src: "/var/lib/machines/{{ inventory_hostname }}/etc/machine-id"
dest: "/var/lib/machines/{{ inventory_hostname }}/var/lib/dbus/machine-id"
mode: "0444"
remote_src: "yes"
remote_user: root
delegate_to: "{{ physical_host }}"
- name: Create resolved link
file:
src: "/var/run/systemd/resolve/resolv.conf"
dest: "/var/lib/machines/{{ inventory_hostname }}/etc/resolv.conf"
force: true
state: link
delegate_to: "{{ physical_host }}"
when:
- nspawn_container_enable_resolved | bool
# Some distros do not have access to systemd-resolved. If the option
# `nspawn_container_enable_resolved` is disabled this will ensure functionality
# in the absence of modern systemd.
- name: Legacy resolvers
block:
- name: Check resolv.conf
stat:
path: "/var/lib/machines/{{ inventory_hostname }}/etc/resolv.conf"
delegate_to: "{{ physical_host }}"
register: nspawn_resolv_conf
- name: Remove resolv.conf link
file:
path: "/var/lib/machines/{{ inventory_hostname }}/etc/resolv.conf"
state: absent
delegate_to: "{{ physical_host }}"
when:
- nspawn_resolv_conf.stat.islnk is defined and
nspawn_resolv_conf.stat.islnk
- name: Place resolv.conf
copy:
content: |
nameserver {{ hostvars[physical_host]['ansible_mv_' + nspawn_networks['nspawn_address']['bridge']]['ipv4']['address'] }}
search {{ container_domain }}
dest: "/var/lib/machines/{{ inventory_hostname }}/etc/resolv.conf"
delegate_to: "{{ physical_host }}"
when:
- not nspawn_container_enable_resolved | bool
- name: Start new container (enable)
systemd:
daemon_reload: yes
name: "systemd-nspawn@{{ systemd_escape.stdout }}"
state: "{{ ((machinectl_container_clone is changed or container_config_new is changed or container_config_old is changed) | default(false)) | ternary('restarted', 'started') }}"
enabled: "{{ (nspawn_systemd_version | int > 219) | ternary('true', 'false') }}"
register: machinectl_start
retries: 5
delay: 2
until: machinectl_start is success
delegate_to: "{{ physical_host }}"
- name: Generate hostname
command: >-
hostnamectl --machine="{{ inventory_hostname }}" {{ item }} --pretty --static --transient
with_items:
- "set-hostname {{ inventory_hostname | replace('_', '-') }}.{{ container_domain }}"
- "set-location {{ physical_host }}"
- "set-chassis container"
- "set-deployment {{ container_domain }}"
- "set-icon-name container"
register: hostnamectl_set
retries: 3
delay: 2
until: hostnamectl_set is success
delegate_to: "{{ physical_host }}"
tags:
- skip_ansible_lint
# This point the container is running. Delegation should no longer be required.
# ==============================================================================
- name: Run the systemd-networkd role
include_role:
name: systemd_networkd
private: true
vars:
systemd_interface_cleanup: false
systemd_run_networkd: true
systemd_resolved_available: "{{ nspawn_container_enable_resolved }}"
systemd_resolved:
DNS: "{{ hostvars[physical_host]['ansible_mv_' + nspawn_networks['nspawn_address']['bridge']]['ipv4']['address'] }}"
Domains: "{{ container_domain }}"
systemd_networks: |-
{% set _networks = [] %}
{% for _, value in (container_networks | combine(nspawn_networks)).items() %}
{% if value.bridge is defined %}
{% set _network = {'interface': 'mv-mv-' + value.bridge.split('br-')[-1]} %}
{% else %}
{% set _network = {'interface': value.interface} %}
{% endif %}
{% if value.address is defined %}
{% set _ = _network.__setitem__('address', value.address) %}
{% if (value.netmask is defined) and (_network.address != 'dhcp') %}
{% set _ = _network.__setitem__('netmask', value.netmask) %}
{% set prefix = (value.address + '/' + value.netmask) | ipaddr('prefix') %}
{% set _ = _network.__setitem__('address', [value.address + '/' + prefix | string]) %}
{% endif %}
{% endif %}
{% set _ = _network.__setitem__('usedns', (value.usedns | default(true) | bool) | ternary('yes', 'no')) %}
{% set _ = _network.__setitem__('static_routes', value.static_routes | default([])) %}
{% if value.gateway is defined %}
{% set _ = _network.__setitem__('gateway', value.gateway) %}
{% endif %}
{% set _ = _network.__setitem__('mtu', value.mtu | default(1500 | string)) %}
{% set _ = _networks.append(_network) %}
{% endfor %}
{{ _networks | sort(attribute='interface') }}
tags:
- network-config
- name: Force all notified handlers now
meta: flush_handlers
- name: (RE)Gather facts post setup
setup: {}