371 lines
13 KiB
YAML
371 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:
|
|
gather_subset: "network,hardware,virtual"
|