From 6eacc2ad5539abf37dc90cd378b44320f7758869 Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Tue, 7 Jul 2020 22:09:19 +0200 Subject: refactor vm role names --- roles/vm/define/defaults/main.yml | 5 - roles/vm/define/tasks/main.yml | 50 ------ roles/vm/define/templates/libvirt-domain.xml.j2 | 102 ------------ roles/vm/grub/handlers/main.yml | 3 - roles/vm/grub/tasks/main.yml | 17 -- roles/vm/guest/base/defaults/main.yml | 6 + roles/vm/guest/base/handlers/main.yml | 8 + roles/vm/guest/base/tasks/main.yml | 61 +++++++ roles/vm/guest/defaults/main.yml | 6 - roles/vm/guest/define/defaults/main.yml | 5 + roles/vm/guest/define/tasks/main.yml | 50 ++++++ .../guest/define/templates/libvirt-domain.xml.j2 | 102 ++++++++++++ roles/vm/guest/handlers/main.yml | 4 - roles/vm/guest/install/library/wait_for_virt.py | 179 +++++++++++++++++++++ roles/vm/guest/install/tasks/installer-debian.yml | 21 +++ roles/vm/guest/install/tasks/installer-openbsd.yml | 19 +++ roles/vm/guest/install/tasks/main.yml | 90 +++++++++++ roles/vm/guest/network/handlers/main.yml | 3 + roles/vm/guest/network/tasks/main.yml | 40 +++++ roles/vm/guest/network/templates/interfaces.j2 | 56 +++++++ roles/vm/guest/network/templates/resolv.conf.j2 | 4 + roles/vm/guest/network/templates/systemd.link.j2 | 5 + roles/vm/guest/tasks/main.yml | 42 ----- roles/vm/host/base/handlers/main.yml | 5 + roles/vm/host/base/tasks/main.yml | 49 ++++++ roles/vm/host/base/tasks/zfs.yml | 20 +++ roles/vm/host/handlers/main.yml | 5 - roles/vm/host/network/tasks/network.yml | 22 +++ .../vm/host/network/templates/bridge-interfaces.j2 | 53 ++++++ roles/vm/host/tasks/main.yml | 53 ------ roles/vm/host/tasks/network.yml | 75 --------- roles/vm/host/tasks/zfs.yml | 20 --- roles/vm/install/library/wait_for_virt.py | 179 --------------------- roles/vm/install/tasks/installer-debian.yml | 21 --- roles/vm/install/tasks/installer-openbsd.yml | 19 --- roles/vm/install/tasks/main.yml | 88 ---------- roles/vm/network/handlers/main.yml | 3 - roles/vm/network/tasks/main.yml | 40 ----- roles/vm/network/templates/interfaces.j2 | 56 ------- roles/vm/network/templates/resolv.conf.j2 | 4 - roles/vm/network/templates/systemd.link.j2 | 5 - 41 files changed, 798 insertions(+), 797 deletions(-) delete mode 100644 roles/vm/define/defaults/main.yml delete mode 100644 roles/vm/define/tasks/main.yml delete mode 100644 roles/vm/define/templates/libvirt-domain.xml.j2 delete mode 100644 roles/vm/grub/handlers/main.yml delete mode 100644 roles/vm/grub/tasks/main.yml create mode 100644 roles/vm/guest/base/defaults/main.yml create mode 100644 roles/vm/guest/base/handlers/main.yml create mode 100644 roles/vm/guest/base/tasks/main.yml delete mode 100644 roles/vm/guest/defaults/main.yml create mode 100644 roles/vm/guest/define/defaults/main.yml create mode 100644 roles/vm/guest/define/tasks/main.yml create mode 100644 roles/vm/guest/define/templates/libvirt-domain.xml.j2 delete mode 100644 roles/vm/guest/handlers/main.yml create mode 100644 roles/vm/guest/install/library/wait_for_virt.py create mode 100644 roles/vm/guest/install/tasks/installer-debian.yml create mode 100644 roles/vm/guest/install/tasks/installer-openbsd.yml create mode 100644 roles/vm/guest/install/tasks/main.yml create mode 100644 roles/vm/guest/network/handlers/main.yml create mode 100644 roles/vm/guest/network/tasks/main.yml create mode 100644 roles/vm/guest/network/templates/interfaces.j2 create mode 100644 roles/vm/guest/network/templates/resolv.conf.j2 create mode 100644 roles/vm/guest/network/templates/systemd.link.j2 delete mode 100644 roles/vm/guest/tasks/main.yml create mode 100644 roles/vm/host/base/handlers/main.yml create mode 100644 roles/vm/host/base/tasks/main.yml create mode 100644 roles/vm/host/base/tasks/zfs.yml delete mode 100644 roles/vm/host/handlers/main.yml create mode 100644 roles/vm/host/network/tasks/network.yml create mode 100644 roles/vm/host/network/templates/bridge-interfaces.j2 delete mode 100644 roles/vm/host/tasks/main.yml delete mode 100644 roles/vm/host/tasks/network.yml delete mode 100644 roles/vm/host/tasks/zfs.yml delete mode 100644 roles/vm/install/library/wait_for_virt.py delete mode 100644 roles/vm/install/tasks/installer-debian.yml delete mode 100644 roles/vm/install/tasks/installer-openbsd.yml delete mode 100644 roles/vm/install/tasks/main.yml delete mode 100644 roles/vm/network/handlers/main.yml delete mode 100644 roles/vm/network/tasks/main.yml delete mode 100644 roles/vm/network/templates/interfaces.j2 delete mode 100644 roles/vm/network/templates/resolv.conf.j2 delete mode 100644 roles/vm/network/templates/systemd.link.j2 (limited to 'roles/vm') diff --git a/roles/vm/define/defaults/main.yml b/roles/vm/define/defaults/main.yml deleted file mode 100644 index f0bcc4fd..00000000 --- a/roles/vm/define/defaults/main.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -vm_define_autostart: "{{ not vm_define_installer and hostvars[install_hostname].install_cooked.vm.autostart | default(False) }}" -vm_define_start: yes - -vm_define_installer: no diff --git a/roles/vm/define/tasks/main.yml b/roles/vm/define/tasks/main.yml deleted file mode 100644 index d0790628..00000000 --- a/roles/vm/define/tasks/main.yml +++ /dev/null @@ -1,50 +0,0 @@ ---- -- name: check if vm already exists - virt: - name: "{{ install_hostname }}" - command: info - register: vmhost_info - -- name: remove old vm - when: install_hostname in vmhost_info - block: - - name: destroy exisiting vm - virt: - name: "{{ install_hostname }}" - state: destroyed - - - name: wait for vm to be destroyed - wait_for_virt: - name: "{{ install_hostname }}" - states: shutdown,crashed - timeout: 5 - - - name: undefining exisiting vm - virt: - name: "{{ install_hostname }}" - command: undefine - -- name: define vm - virt: - command: define - xml: "{{ lookup('template', 'libvirt-domain.xml.j2') }}" - -- name: start new vm - when: vm_define_start | bool - block: - - name: start vm - virt: - name: "{{ install_hostname }}" - state: running - - - name: wait for VM to start - wait_for_virt: - name: "{{ install_hostname }}" - states: running - timeout: 10 - -- name: mark vm as autostarted - virt: - name: "{{ install_hostname }}" - autostart: "{{ vm_define_autostart }}" - command: info ## virt module needs either command or state diff --git a/roles/vm/define/templates/libvirt-domain.xml.j2 b/roles/vm/define/templates/libvirt-domain.xml.j2 deleted file mode 100644 index ba0dcd5a..00000000 --- a/roles/vm/define/templates/libvirt-domain.xml.j2 +++ /dev/null @@ -1,102 +0,0 @@ - - {{ install_hostname }} - {{ ((hostvars[install_hostname].install_cooked.vm.memory | human_to_bytes) / 1024) | int }} - {{ ((hostvars[install_hostname].install_cooked.vm.memory | human_to_bytes) / 1024) | int }} - {{ hostvars[install_hostname].install_cooked.vm.numcpus }} - - hvm -{% if vm_define_installer %} -{% if install_distro == 'debian' or install_distro == 'ubuntu' %} - {{ installer_base_path }}/{{ install_distro }}-{{ install_codename }}/{{ hostvars[install_hostname].install_cooked.arch | default('amd64') }}-netboot/linux - {{ installer_tmpdir }}/initrd.{{ install_hostname }}.gz - console=ttyS0,115200n8 DEBCONF_DEBUG=5 - -{% elif install_distro == 'openbsd' %} - -{% endif %} -{% else %} - -{% endif %} - - - - - - - - destroy -{% if vm_define_installer %} - destroy - destroy -{% else %} - restart - restart -{% endif %} - - /usr/bin/kvm - - - - - /dev/random - - -{% if vm_define_installer and install_distro == 'openbsd' %} - - - - - - - -{% endif %} -{% if 'virtio' in hostvars[install_hostname].install_cooked.disks %} -{% for device, src in hostvars[install_hostname].install_cooked.disks.virtio.items() %} - - -{% if src.type == 'lvm' %} - -{% elif src.type == 'zfs' %} - -{% endif %} - - -{% endfor %} -{% endif %} - -{% if 'scsi' in hostvars[install_hostname].install_cooked.disks %} - -{% for device, src in hostvars[install_hostname].install_cooked.disks.scsi.items() %} - - -{% if src.type == 'lvm' %} - -{% elif src.type == 'zfs' %} - -{% endif %} - - -{% endfor %} -{% endif %} - -{% if hostvars[install_hostname].install_cooked.interfaces %} -{% for if in hostvars[install_hostname].install_cooked.interfaces %} - -{% if 'mac' in if %} - -{% endif %} - - -
- -{% endfor %} -{% endif %} - - - - - - - - - diff --git a/roles/vm/grub/handlers/main.yml b/roles/vm/grub/handlers/main.yml deleted file mode 100644 index 4bddbb14..00000000 --- a/roles/vm/grub/handlers/main.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -- name: update grub - command: /usr/sbin/update-grub diff --git a/roles/vm/grub/tasks/main.yml b/roles/vm/grub/tasks/main.yml deleted file mode 100644 index e663e808..00000000 --- a/roles/vm/grub/tasks/main.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- -- name: enable serial console in grub and for kernel - vars: - grub_options: - GRUB_TIMEOUT: 2 - GRUB_CMDLINE_LINUX: '"console=ttyS0,115200n8"' - GRUB_TERMINAL: serial - GRUB_SERIAL_COMMAND: >- - "serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1" - loop: "{{ grub_options | dict2items }}" - loop_control: - label: "{{ item.key }}" - lineinfile: - dest: /etc/default/grub - regexp: "^{{ item.key }}=" - line: "{{ item.key }}={{ item.value }}" - notify: update grub diff --git a/roles/vm/guest/base/defaults/main.yml b/roles/vm/guest/base/defaults/main.yml new file mode 100644 index 00000000..ce072e95 --- /dev/null +++ b/roles/vm/guest/base/defaults/main.yml @@ -0,0 +1,6 @@ +--- +vm_guest_rngd_config: + HRNGDEVICE: /dev/hwrng + RNGDOPTIONS: '"-s 256 -W 80%"' + +vm_guest_autologin_on_serial: yes diff --git a/roles/vm/guest/base/handlers/main.yml b/roles/vm/guest/base/handlers/main.yml new file mode 100644 index 00000000..2dfdddcb --- /dev/null +++ b/roles/vm/guest/base/handlers/main.yml @@ -0,0 +1,8 @@ +--- +- name: update grub + command: /usr/sbin/update-grub + +- name: restart rngd + service: + name: rng-tools + state: restarted diff --git a/roles/vm/guest/base/tasks/main.yml b/roles/vm/guest/base/tasks/main.yml new file mode 100644 index 00000000..b76ee762 --- /dev/null +++ b/roles/vm/guest/base/tasks/main.yml @@ -0,0 +1,61 @@ +--- +- name: install rngd + apt: + name: rng-tools + state: present + force_apt_get: yes + +- name: configure rngd [1/2] + loop: '{{ vm_guest_rngd_config | dict2items }}' + loop_control: + label: "{{ item.key }}" + lineinfile: + path: /etc/default/rng-tools + line: '{{ item.key }}={{ item.value }}' + regexp: '^#?{{ item.key }}=' + notify: restart rngd + +- name: configure rngd [2/2] + loop: '{{ vm_guest_rngd_config | dict2items }}' + loop_control: + label: "{{ item.key }}" + lineinfile: + path: /etc/default/rng-tools + regexp: '^{{ item.key }}=(?!{{ item.value }})' + state: absent + notify: restart rngd + + +- name: provide a root shell on the VM serial console + when: vm_guest_autologin_on_serial + block: + - name: create systemd override directory for gettyS0 + file: + path: /etc/systemd/system/serial-getty@ttyS0.service.d/ + state: directory + + - name: create autologin config for gettyS0 + copy: + dest: /etc/systemd/system/serial-getty@ttyS0.service.d/autologon.conf + content: | + [Service] + ExecStart= + ExecStart=-/sbin/agetty --keep-baud 115200,38400,9600 --noclear --autologin root --login-pause --host {{ vm_host_cooked.name }} %I $TERM + + +- name: enable serial console in grub and for kernel + vars: + grub_options: + GRUB_TIMEOUT: 2 + GRUB_CMDLINE_LINUX: '"console=ttyS0,115200n8"' + GRUB_TERMINAL: serial + GRUB_SERIAL_COMMAND: >- + "serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1" + loop: "{{ grub_options | dict2items }}" + loop_control: + label: "{{ item.key }}" + lineinfile: + dest: /etc/default/grub + regexp: "^{{ item.key }}=" + line: "{{ item.key }}={{ item.value }}" + notify: update grub diff --git a/roles/vm/guest/defaults/main.yml b/roles/vm/guest/defaults/main.yml deleted file mode 100644 index ce072e95..00000000 --- a/roles/vm/guest/defaults/main.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -vm_guest_rngd_config: - HRNGDEVICE: /dev/hwrng - RNGDOPTIONS: '"-s 256 -W 80%"' - -vm_guest_autologin_on_serial: yes diff --git a/roles/vm/guest/define/defaults/main.yml b/roles/vm/guest/define/defaults/main.yml new file mode 100644 index 00000000..f0bcc4fd --- /dev/null +++ b/roles/vm/guest/define/defaults/main.yml @@ -0,0 +1,5 @@ +--- +vm_define_autostart: "{{ not vm_define_installer and hostvars[install_hostname].install_cooked.vm.autostart | default(False) }}" +vm_define_start: yes + +vm_define_installer: no diff --git a/roles/vm/guest/define/tasks/main.yml b/roles/vm/guest/define/tasks/main.yml new file mode 100644 index 00000000..d0790628 --- /dev/null +++ b/roles/vm/guest/define/tasks/main.yml @@ -0,0 +1,50 @@ +--- +- name: check if vm already exists + virt: + name: "{{ install_hostname }}" + command: info + register: vmhost_info + +- name: remove old vm + when: install_hostname in vmhost_info + block: + - name: destroy exisiting vm + virt: + name: "{{ install_hostname }}" + state: destroyed + + - name: wait for vm to be destroyed + wait_for_virt: + name: "{{ install_hostname }}" + states: shutdown,crashed + timeout: 5 + + - name: undefining exisiting vm + virt: + name: "{{ install_hostname }}" + command: undefine + +- name: define vm + virt: + command: define + xml: "{{ lookup('template', 'libvirt-domain.xml.j2') }}" + +- name: start new vm + when: vm_define_start | bool + block: + - name: start vm + virt: + name: "{{ install_hostname }}" + state: running + + - name: wait for VM to start + wait_for_virt: + name: "{{ install_hostname }}" + states: running + timeout: 10 + +- name: mark vm as autostarted + virt: + name: "{{ install_hostname }}" + autostart: "{{ vm_define_autostart }}" + command: info ## virt module needs either command or state diff --git a/roles/vm/guest/define/templates/libvirt-domain.xml.j2 b/roles/vm/guest/define/templates/libvirt-domain.xml.j2 new file mode 100644 index 00000000..ba0dcd5a --- /dev/null +++ b/roles/vm/guest/define/templates/libvirt-domain.xml.j2 @@ -0,0 +1,102 @@ + + {{ install_hostname }} + {{ ((hostvars[install_hostname].install_cooked.vm.memory | human_to_bytes) / 1024) | int }} + {{ ((hostvars[install_hostname].install_cooked.vm.memory | human_to_bytes) / 1024) | int }} + {{ hostvars[install_hostname].install_cooked.vm.numcpus }} + + hvm +{% if vm_define_installer %} +{% if install_distro == 'debian' or install_distro == 'ubuntu' %} + {{ installer_base_path }}/{{ install_distro }}-{{ install_codename }}/{{ hostvars[install_hostname].install_cooked.arch | default('amd64') }}-netboot/linux + {{ installer_tmpdir }}/initrd.{{ install_hostname }}.gz + console=ttyS0,115200n8 DEBCONF_DEBUG=5 + +{% elif install_distro == 'openbsd' %} + +{% endif %} +{% else %} + +{% endif %} + + + + + + + + destroy +{% if vm_define_installer %} + destroy + destroy +{% else %} + restart + restart +{% endif %} + + /usr/bin/kvm + + + + + /dev/random + + +{% if vm_define_installer and install_distro == 'openbsd' %} + + + + + + + +{% endif %} +{% if 'virtio' in hostvars[install_hostname].install_cooked.disks %} +{% for device, src in hostvars[install_hostname].install_cooked.disks.virtio.items() %} + + +{% if src.type == 'lvm' %} + +{% elif src.type == 'zfs' %} + +{% endif %} + + +{% endfor %} +{% endif %} + +{% if 'scsi' in hostvars[install_hostname].install_cooked.disks %} + +{% for device, src in hostvars[install_hostname].install_cooked.disks.scsi.items() %} + + +{% if src.type == 'lvm' %} + +{% elif src.type == 'zfs' %} + +{% endif %} + + +{% endfor %} +{% endif %} + +{% if hostvars[install_hostname].install_cooked.interfaces %} +{% for if in hostvars[install_hostname].install_cooked.interfaces %} + +{% if 'mac' in if %} + +{% endif %} + + +
+ +{% endfor %} +{% endif %} + + + + + + + + + diff --git a/roles/vm/guest/handlers/main.yml b/roles/vm/guest/handlers/main.yml deleted file mode 100644 index 5b57f3bc..00000000 --- a/roles/vm/guest/handlers/main.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: restart rngd - service: - name: rng-tools - state: restarted diff --git a/roles/vm/guest/install/library/wait_for_virt.py b/roles/vm/guest/install/library/wait_for_virt.py new file mode 100644 index 00000000..6c49fae1 --- /dev/null +++ b/roles/vm/guest/install/library/wait_for_virt.py @@ -0,0 +1,179 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +import traceback +import time + +try: + import libvirt +except ImportError: + HAS_VIRT = False +else: + HAS_VIRT = True + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils._text import to_native + + +VIRT_FAILED = 1 +VIRT_SUCCESS = 0 +VIRT_UNAVAILABLE = 2 + +VIRT_STATE_NAME_MAP = { + 0: "running", + 1: "running", + 2: "running", + 3: "paused", + 4: "shutdown", + 5: "shutdown", + 6: "crashed" +} + + +class VMNotFound(Exception): + pass + + +class LibvirtConnection(object): + + def __init__(self, uri, module): + + self.module = module + + cmd = "uname -r" + rc, stdout, stderr = self.module.run_command(cmd) + + if "xen" in stdout: + conn = libvirt.open(None) + elif "esx" in uri: + auth = [[libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_NOECHOPROMPT], [], None] + conn = libvirt.openAuth(uri, auth) + else: + conn = libvirt.open(uri) + + if not conn: + raise Exception("hypervisor connection failure") + + self.conn = conn + + def find_vm(self, vmid): + """ + Extra bonus feature: vmid = -1 returns a list of everything + """ + conn = self.conn + + vms = [] + + # this block of code borrowed from virt-manager: + # get working domain's name + ids = conn.listDomainsID() + for id in ids: + vm = conn.lookupByID(id) + vms.append(vm) + # get defined domain + names = conn.listDefinedDomains() + for name in names: + vm = conn.lookupByName(name) + vms.append(vm) + + if vmid == -1: + return vms + + for vm in vms: + if vm.name() == vmid: + return vm + + raise VMNotFound("virtual machine %s not found" % vmid) + + def get_status(self, vmid): + state = self.find_vm(vmid).info()[0] + return VIRT_STATE_NAME_MAP.get(state, "unknown") + + +class Virt(object): + + def __init__(self, uri, module): + self.module = module + self.uri = uri + + def __get_conn(self): + self.conn = LibvirtConnection(self.uri, self.module) + return self.conn + + def status(self, vmid): + """ + Return a state suitable for server consumption. Aka, codes.py values, not XM output. + """ + self.__get_conn() + return self.conn.get_status(vmid) + + +def core(module): + + states = module.params.get('states', None) + guest = module.params.get('name', None) + uri = module.params.get('uri', None) + delay = module.params.get('delay', None) + sleep = module.params.get('sleep', None) + timeout = module.params.get('timeout', None) + + v = Virt(uri, module) + res = {'changed': False, 'failed': True} + + if delay > 0: + time.sleep(delay) + + for _ in range(0, timeout, sleep): + state = v.status(guest) + if state in states: + res['state'] = state + res['failed'] = False + res['msg'] = "guest '%s' has reached state: %s" % (guest, state) + return VIRT_SUCCESS, res + + time.sleep(sleep) + + res['msg'] = "timeout waiting for guest '%s' to reach one of states: %s" % (guest, ', '.join(states)) + return VIRT_FAILED, res + + +def main(): + + module = AnsibleModule(argument_spec=dict( + name=dict(aliases=['guest'], required=True), + states=dict(type='list', required=True), + uri=dict(default='qemu:///system'), + delay=dict(type='int', default=0), + sleep=dict(type='int', default=1), + timeout=dict(type='int', default=300), + )) + + if not HAS_VIRT: + module.fail_json( + msg='The `libvirt` module is not importable. Check the requirements.' + ) + + for state in module.params.get('states', None): + if state not in set(VIRT_STATE_NAME_MAP.values()): + module.fail_json( + msg="states contains invalid state '%s', must be one of %s" % (state, ', '.join(set(VIRT_STATE_NAME_MAP.values()))) + ) + + rc = VIRT_SUCCESS + try: + rc, result = core(module) + except Exception as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + if rc != 0: # something went wrong emit the msg + module.fail_json(rc=rc, msg=result) + else: + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/roles/vm/guest/install/tasks/installer-debian.yml b/roles/vm/guest/install/tasks/installer-debian.yml new file mode 100644 index 00000000..e0492969 --- /dev/null +++ b/roles/vm/guest/install/tasks/installer-debian.yml @@ -0,0 +1,21 @@ +--- +- name: fetch debian installer files + vars: + debian_installer_distro: "{{ install_distro }}" + debian_installer_codename: "{{ install_codename }}" + debian_installer_arch: "{{ hostvars[install_hostname].install_cooked.arch | default('amd64') }}" + debian_installer_variant: netboot + import_role: + name: installer/debian/fetch + +- name: generate host specific initial ramdisk + vars: + ssh_keys_root: "{{ hostvars[install_hostname].ssh_keys_root }}" + preseed_orig_initrd: "{{ installer_base_path }}/{{ install_distro }}-{{ install_codename }}/{{ hostvars[install_hostname].install_cooked.arch | default('amd64') }}-netboot/initrd.gz" + preseed_tmpdir: "{{ tmpdir.path }}" + preseed_virtual_machine: yes + preseed_force_net_ifnames_policy: path + preseed_no_netplan: yes + install_interface: enp1s1 + import_role: + name: installer/debian/preseed diff --git a/roles/vm/guest/install/tasks/installer-openbsd.yml b/roles/vm/guest/install/tasks/installer-openbsd.yml new file mode 100644 index 00000000..afa17c45 --- /dev/null +++ b/roles/vm/guest/install/tasks/installer-openbsd.yml @@ -0,0 +1,19 @@ +--- +- name: fetch openbsd installer files + vars: + openbsd_installer_version: "{{ install_codename }}" + openbsd_installer_arch: "{{ hostvars[install_hostname].install_cooked.arch | default('amd64') }}" + import_role: + name: installer/openbsd/fetch + +- name: generate host specific autoinstall iso + vars: + ssh_keys_root: "{{ hostvars[install_hostname].ssh_keys_root }}" + obsd_autoinstall_orig_iso: "{{ installer_base_path }}/openbsd-{{ install_codename }}/{{ hostvars[install_hostname].install_cooked.arch | default('amd64') }}/install{{ openbsd_installer_version_short }}.iso" + obsd_autoinstall_tmpdir: "{{ tmpdir.path }}" + obsd_autoinstall_version: "{{ install_codename }}" + obsd_autoinstall_arch: "{{ hostvars[install_hostname].install_cooked.arch | default('amd64') }}" + obsd_autoinstall_serial_device: com0 + install_interface: vio0 + import_role: + name: installer/openbsd/autoinstall diff --git a/roles/vm/guest/install/tasks/main.yml b/roles/vm/guest/install/tasks/main.yml new file mode 100644 index 00000000..21a13b4d --- /dev/null +++ b/roles/vm/guest/install/tasks/main.yml @@ -0,0 +1,90 @@ +--- +- name: create lvm-based disks for vm + loop: "{{ hostvars[install_hostname].install_cooked.disks.virtio | default({}) | combine(hostvars[install_hostname].install_cooked.disks.scsi | default({})) | dict2items | selectattr('value.type', 'eq', 'lvm') | list }}" + loop_control: + label: "{{ item.value.vg }} / {{ item.value.lv }} ({{ item.value.size }})" + lvol: + vg: "{{ item.value.vg }}" + lv: "{{ item.value.lv }}" + size: "{{ item.value.size }}" + state: present + +- name: create zfs base datasets for vm + loop: "{{ hostvars[install_hostname].install_cooked.disks.virtio | default({}) | combine(hostvars[install_hostname].install_cooked.disks.scsi | default({})) | dict2items | selectattr('value.type', 'eq', 'zfs') | map(attribute='value.backend') | map('default', 'default') | unique | list }}" + zfs: + name: "{{ vm_host_cooked.zfs[item].pool }}/{{ vm_host_cooked.zfs[item].name }}/{{ install_hostname }}" + state: present + extra_zfs_properties: + canmount: no + mountpoint: none + +- name: create zfs-based disk volumes for vm + loop: "{{ hostvars[install_hostname].install_cooked.disks.virtio | default({}) | combine(hostvars[install_hostname].install_cooked.disks.scsi | default({})) | dict2items | selectattr('value.type', 'eq', 'zfs') | list }}" + loop_control: + label: "{{ item.value.name }} on backend {{ item.value.backend | default('default') }} ({{ item.value.size }})" + zfs: + name: "{{ vm_host_cooked.zfs[item.value.backend | default('default')].pool }}/{{ vm_host_cooked.zfs[item.value.backend | default('default')].name }}/{{ install_hostname }}/{{ item.value.name }}" + state: present + extra_zfs_properties: "{{ item.value.properties | default({}) | combine({'volsize': item.value.size}) }}" + + +- block: + - name: create a temporary workdir + tempfile: + path: "{{ installer_base_path }}/" + prefix: ".{{ install_hostname }}." + state: directory + register: tmpdir + + - when: install_distro in ['debian', 'ubuntu'] + import_tasks: installer-debian.yml + + - when: install_distro in ['openbsd'] + import_tasks: installer-openbsd.yml + + - name: Make installer workdir readable by qemu + acl: + path: "{{ tmpdir.path }}" + state: present + entity: libvirt-qemu + etype: user + permissions: rx + + - name: define installer vm + vars: + vm_define_installer: yes + installer_tmpdir: "{{ tmpdir.path }}" + import_role: + name: vm/guest/define + + - debug: + msg: "you can check on the status of the installer running this command 'virsh console {{ install_hostname }}' on host {{ inventory_hostname }}." + + - when: installer_manual_steps_msg is defined + pause: + prompt: | + Mind that this installer needs manual steps to be performed: + + {{ installer_manual_steps_msg | indent(2) }} + + When done press enter to continue or Ctrl-C + 'A' to abort. + + - name: wait for installer to finish or crash + wait_for_virt: + name: "{{ install_hostname }}" + states: shutdown,crashed + timeout: 1800 + register: installer_result + failed_when: installer_result.failed or installer_result.state == "crashed" + + always: + - name: cleanup temporary workdir + file: + path: "{{ tmpdir.path }}" + state: absent + +- name: define vm + vars: + vm_define_installer: no + import_role: + name: vm/guest/define diff --git a/roles/vm/guest/network/handlers/main.yml b/roles/vm/guest/network/handlers/main.yml new file mode 100644 index 00000000..f967fa86 --- /dev/null +++ b/roles/vm/guest/network/handlers/main.yml @@ -0,0 +1,3 @@ +--- +- name: rebuild initramfs + command: update-initramfs -u diff --git a/roles/vm/guest/network/tasks/main.yml b/roles/vm/guest/network/tasks/main.yml new file mode 100644 index 00000000..27a7682a --- /dev/null +++ b/roles/vm/guest/network/tasks/main.yml @@ -0,0 +1,40 @@ +--- +- name: configure systemd link units + when: network_cooked.systemd_link is defined + block: + - name: remove legacy systemd.link units + loop: + - 50-virtio-kernel-names.link + - 99-default.link + file: + name: "/etc/systemd/network/{{ item }}" + state: absent + + - name: install systemd network link units + loop: "{{ network_cooked.systemd_link.interfaces }}" + loop_control: + label: "{{ item.name }}" + index_var: interface_index + template: + src: systemd.link.j2 + dest: "/etc/systemd/network/{{ '%02d' | format(interface_index + 11) }}-{{ item.name }}.link" + notify: rebuild initramfs + + +- name: install basic interface config + template: + src: interfaces.j2 + dest: /etc/network/interfaces + mode: 0644 + +- name: remove resolvconf package + apt: + name: resolvconf + state: absent + force_apt_get: yes + purge: yes + +- name: generate resolv.conf + template: + src: resolv.conf.j2 + dest: /etc/resolv.conf diff --git a/roles/vm/guest/network/templates/interfaces.j2 b/roles/vm/guest/network/templates/interfaces.j2 new file mode 100644 index 00000000..8c288669 --- /dev/null +++ b/roles/vm/guest/network/templates/interfaces.j2 @@ -0,0 +1,56 @@ +# This file describes the network interfaces available on your system +# and how to activate them. For more information, see interfaces(5). + +source /etc/network/interfaces.d/* + +# The loopback network interface +auto lo +iface lo inet loopback +{% for interface in network_cooked.interfaces %} + + +auto {{ interface.name }} +iface {{ interface.name }} inet static + pre-up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/accept_ra + pre-up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/autoconf + address {{ interface.address | ipaddr('address') }} + netmask {{ interface.address | ipaddr('netmask') }} +{% if 'overlay' in interface %} + up /bin/ip addr add dev $IFACE {{ interface.overlay }}/32 +{% for route in interface.static_routes | default([]) %} + up /bin/ip route add {{ route.destination }} via {{ route.gateway }} src {{ interface.overlay }} +{% endfor %} +{% if 'gateway' in interface %} + up /bin/ip route add default via {{ interface.gateway }} src {{ interface.overlay }} + down /bin/ip route del default via {{ interface.gateway }} src {{ interface.overlay }} +{% for route in interface.static_routes | default([]) | reverse %} + down /bin/ip route del {{ route.destination }} via {{ route.gateway }} src {{ interface.overlay }} +{% endfor %} +{% endif %} + down /bin/ip addr del dev $IFACE {{ interface.overlay }}/32 +{% else %} +{% if 'gateway' in interface %} + gateway {{ interface.gateway }} +{% endif %} +{% for route in interface.static_routes | default([]) %} + up /bin/ip route add {{ route.destination }} via {{ route.gateway }} +{% endfor %} +{% for route in interface.static_routes | default([]) | reverse %} + down /bin/ip route del {{ route.destination }} via {{ route.gateway }} +{% endfor %} +{% endif %} +{% if 'address6' in interface %} + +iface {{ interface.name }} inet6 static + address {{ interface.address6 }} +{% if 'gateway6' in interface %} + gateway {{ interface.gateway6 }} +{% endif %} +{% for route in interface.static_routes6 | default([]) %} + up /bin/ip -6 route add {{ route.destination }} via {{ route.gateway }} +{% endfor %} +{% for route in interface.static_routes6 | default([]) | reverse %} + down /bin/ip -6 route del {{ route.destination }} via {{ route.gateway }} +{% endfor %} +{% endif %} +{% endfor %} diff --git a/roles/vm/guest/network/templates/resolv.conf.j2 b/roles/vm/guest/network/templates/resolv.conf.j2 new file mode 100644 index 00000000..00aaafe3 --- /dev/null +++ b/roles/vm/guest/network/templates/resolv.conf.j2 @@ -0,0 +1,4 @@ +{% for nsrv in network_cooked.nameservers %} +nameserver {{ nsrv }} +{% endfor %} +search {{ network_cooked.domain }} diff --git a/roles/vm/guest/network/templates/systemd.link.j2 b/roles/vm/guest/network/templates/systemd.link.j2 new file mode 100644 index 00000000..7093e164 --- /dev/null +++ b/roles/vm/guest/network/templates/systemd.link.j2 @@ -0,0 +1,5 @@ +[Match] +Path=*pci-0000:01:{{ "%02d" | format(interface_index + 1) }}.0 + +[Link] +Name={{ item.name }} diff --git a/roles/vm/guest/tasks/main.yml b/roles/vm/guest/tasks/main.yml deleted file mode 100644 index e68f04df..00000000 --- a/roles/vm/guest/tasks/main.yml +++ /dev/null @@ -1,42 +0,0 @@ -- name: install rngd - apt: - name: rng-tools - state: present - force_apt_get: yes - -- name: configure rngd [1/2] - loop: '{{ vm_guest_rngd_config | dict2items }}' - loop_control: - label: "{{ item.key }}" - lineinfile: - path: /etc/default/rng-tools - line: '{{ item.key }}={{ item.value }}' - regexp: '^#?{{ item.key }}=' - notify: restart rngd - -- name: configure rngd [2/2] - loop: '{{ vm_guest_rngd_config | dict2items }}' - loop_control: - label: "{{ item.key }}" - lineinfile: - path: /etc/default/rng-tools - regexp: '^{{ item.key }}=(?!{{ item.value }})' - state: absent - notify: restart rngd - - -- name: provide a root shell on the VM serial console - when: vm_guest_autologin_on_serial - block: - - name: create systemd override directory for gettyS0 - file: - path: /etc/systemd/system/serial-getty@ttyS0.service.d/ - state: directory - - - name: create autologin config for gettyS0 - copy: - dest: /etc/systemd/system/serial-getty@ttyS0.service.d/autologon.conf - content: | - [Service] - ExecStart= - ExecStart=-/sbin/agetty --keep-baud 115200,38400,9600 --noclear --autologin root --login-pause --host {{ vm_host_cooked.name }} %I $TERM diff --git a/roles/vm/host/base/handlers/main.yml b/roles/vm/host/base/handlers/main.yml new file mode 100644 index 00000000..6541dd80 --- /dev/null +++ b/roles/vm/host/base/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: restart haveged + service: + name: haveged + state: restarted diff --git a/roles/vm/host/base/tasks/main.yml b/roles/vm/host/base/tasks/main.yml new file mode 100644 index 00000000..1a7cb7d8 --- /dev/null +++ b/roles/vm/host/base/tasks/main.yml @@ -0,0 +1,49 @@ +--- +- name: install dependencies + apt: + name: + - qemu-kvm + - # configuration package, pulls in libvirt-clients and libvirt-daemon + libvirt-daemon-system + - python-libvirt + - haveged + - bridge-utils + - acl + state: present + +- name: configure haveged + lineinfile: + regexp: "^#?DAEMON_ARGS" + line: 'DAEMON_ARGS="-w 3072"' + path: /etc/default/haveged + notify: restart haveged + +- name: prepare zfs volumes + when: "'zfs' in vm_host" + include_tasks: zfs.yml + +- name: create lvm-based disk for installers + when: installer_lvm is defined + block: + - name: create logical volume + lvol: + vg: "{{ installer_lvm.vg }}" + lv: "{{ installer_lvm.lv }}" + size: "{{ installer_lvm.size }}" + + - name: create filesystem + filesystem: + fstype: "{{ installer_lvm.fs }}" + dev: "/dev/mapper/{{ installer_lvm.vg | replace('-', '--') }}-{{ installer_lvm.lv | replace('-', '--') }}" + + - name: mount filesytem + mount: + src: "/dev/mapper/{{ installer_lvm.vg | replace('-', '--') }}-{{ installer_lvm.lv | replace('-', '--') }}" + path: "{{ installer_base_path }}" + fstype: "{{ installer_lvm.fs }}" + state: mounted + +- name: make sure installer directory exists + file: + name: "{{ installer_base_path }}" + state: directory diff --git a/roles/vm/host/base/tasks/zfs.yml b/roles/vm/host/base/tasks/zfs.yml new file mode 100644 index 00000000..b84f2d0d --- /dev/null +++ b/roles/vm/host/base/tasks/zfs.yml @@ -0,0 +1,20 @@ +--- +- name: create zfs base datasets + loop: "{{ lookup('dict', vm_host.zfs, wantlist=True) }}" + loop_control: + label: "{{ item.key }} -> {{ item.value.pool }}/{{ item.value.name }} ({{ (item.value.properties | default({})).items() | map('join', '=') | join(', ') }})" + vars: + default_properties: + canmount: no + mountpoint: none + zfs: + name: "{{ item.value.pool }}/{{ item.value.name }}" + state: present + extra_zfs_properties: "{{ default_properties | combine(item.value.properties | default({})) }}" + +- name: configure lvm to ignore zfs volumes + lineinfile: + path: /etc/lvm/lvm.conf + backrefs: yes + regexp: '^\s*#?\s*global_filter\s*=' + line: ' global_filter = [ "r|/dev/zd[0-9]+|" ]' diff --git a/roles/vm/host/handlers/main.yml b/roles/vm/host/handlers/main.yml deleted file mode 100644 index 6541dd80..00000000 --- a/roles/vm/host/handlers/main.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -- name: restart haveged - service: - name: haveged - state: restarted diff --git a/roles/vm/host/network/tasks/network.yml b/roles/vm/host/network/tasks/network.yml new file mode 100644 index 00000000..103ff194 --- /dev/null +++ b/roles/vm/host/network/tasks/network.yml @@ -0,0 +1,22 @@ +--- +- name: create network bridges + when: "'bridges' in vm_host.network" + block: + - name: generate bridge interface config + loop: "{{ vm_host.network.bridges | default({}) | dict2items }}" + loop_control: + label: "{{ item.key }}" + template: + src: bridge-interfaces.j2 + dest: "/etc/network/interfaces.d/br-{{ item.key }}" + register: vmhost_bridge_config + + ## We don't try to be to clever here: aka don't call ifdown before ifup because + ## if there are VMs running they would end up with a broken network + - name: bring up bridge interfaces + loop: "{{ vmhost_bridge_config.results }}" + loop_control: + label: "br-{{ item.item.key }}" + when: item is changed + command: "/sbin/ifup br-{{ item.item.key }}" + failed_when: false diff --git a/roles/vm/host/network/templates/bridge-interfaces.j2 b/roles/vm/host/network/templates/bridge-interfaces.j2 new file mode 100644 index 00000000..05144430 --- /dev/null +++ b/roles/vm/host/network/templates/bridge-interfaces.j2 @@ -0,0 +1,53 @@ +{% set bridge_name = 'br-'+item.key %} +{% set bridge = item.value %} +{% set interface = (network.interfaces | selectattr('name', 'eq', bridge_name) | first | default({})) %} +auto {{ bridge_name }} +{% if 'address' in interface %} +iface {{ bridge_name }} inet static + address {{ interface.address | ipaddr('address') }} + netmask {{ interface.address | ipaddr('netmask') }} +{% if 'gateway' in interface %} + gateway {{ interface.gateway }} +{% endif %} +{% else %} +iface {{ bridge_name }} inet manual +{% endif %} +{% if 'interfaces' in bridge and (bridge.interfaces | length) > 0 %} + bridge_ports {{ bridge.interfaces | join(' ') }} +{% else %} + bridge_ports none +{% endif %} + bridge_stp off + bridge_waitport 0 + bridge_fd 0 + up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/accept_ra + up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/autoconf + up modprobe br_netfilter + up /sbin/sysctl net.bridge.bridge-nf-call-iptables=0 + up /sbin/sysctl net.bridge.bridge-nf-call-ip6tables=0 + up /sbin/sysctl net.bridge.bridge-nf-call-arptables=0 +{% if 'address' in interface and 'prefix' in bridge %} +{% if 'nat' in bridge and bridge.nat %} + up echo 1 > /proc/sys/net/ipv4/conf/$IFACE/forwarding + up echo 1 > /proc/sys/net/ipv4/conf/{{ ansible_default_ipv4.interface }}/forwarding + up /sbin/iptables -t nat -A POSTROUTING -o {{ ansible_default_ipv4.interface }} -s {{ bridge.prefix }} -j SNAT --to {{ ansible_default_ipv4.address }} +{% endif %} +{% if 'overlay' in bridge %} +{% for dest, offset in (bridge.overlay.offsets | dictsort(by='value')) %} + up /bin/ip route add {{ (bridge.overlay.prefix | ipaddr(offset)).split('/')[0] }}/32 via {{ (bridge.prefix | ipaddr(bridge.offsets[dest])).split('/')[0] }} # {{ dest }} +{% endfor %} + up /bin/ip route add unreachable {{ bridge.overlay.prefix }} + down /sbin/ip route del {{ bridge.overlay.prefix }} +{% endif %} +{% if 'nat' in bridge and bridge.nat %} + down /sbin/iptables -t nat -D POSTROUTING -o {{ ansible_default_ipv4.interface }} -s {{ bridge.prefix }} -j SNAT --to {{ ansible_default_ipv4.address }} +{% endif %} +{% endif %} +{% if 'address6' in interface %} + +iface {{ bridge_name }} inet6 static + address {{ interface.address6 }} +{% if 'gateway6' in interface %} + gateway {{ interface.gateway6 }} +{% endif %} +{% endif %} diff --git a/roles/vm/host/tasks/main.yml b/roles/vm/host/tasks/main.yml deleted file mode 100644 index 4c29970d..00000000 --- a/roles/vm/host/tasks/main.yml +++ /dev/null @@ -1,53 +0,0 @@ ---- -- name: install dependencies - apt: - name: - - qemu-kvm - - # configuration package, pulls in libvirt-clients and libvirt-daemon - libvirt-daemon-system - - python-libvirt - - haveged - - bridge-utils - - acl - state: present - -- name: configure haveged - lineinfile: - regexp: "^#?DAEMON_ARGS" - line: 'DAEMON_ARGS="-w 3072"' - path: /etc/default/haveged - notify: restart haveged - -- name: install vm-host network - when: "'network' in vm_host" - include_tasks: network.yml - -- name: prepare zfs volumes - when: "'zfs' in vm_host" - include_tasks: zfs.yml - -- name: create lvm-based disk for installers - when: installer_lvm is defined - block: - - name: create logical volume - lvol: - vg: "{{ installer_lvm.vg }}" - lv: "{{ installer_lvm.lv }}" - size: "{{ installer_lvm.size }}" - - - name: create filesystem - filesystem: - fstype: "{{ installer_lvm.fs }}" - dev: "/dev/mapper/{{ installer_lvm.vg | replace('-', '--') }}-{{ installer_lvm.lv | replace('-', '--') }}" - - - name: mount filesytem - mount: - src: "/dev/mapper/{{ installer_lvm.vg | replace('-', '--') }}-{{ installer_lvm.lv | replace('-', '--') }}" - path: "{{ installer_base_path }}" - fstype: "{{ installer_lvm.fs }}" - state: mounted - -- name: make sure installer directory exists - file: - name: "{{ installer_base_path }}" - state: directory diff --git a/roles/vm/host/tasks/network.yml b/roles/vm/host/tasks/network.yml deleted file mode 100644 index 802ffd8b..00000000 --- a/roles/vm/host/tasks/network.yml +++ /dev/null @@ -1,75 +0,0 @@ ---- -- name: create network bridges - when: "'bridges' in vm_host.network" - block: - - name: generate bridge interface config - loop: "{{ vm_host.network.bridges | default({}) | dict2items }}" - loop_control: - label: "{{ item.key }}" - copy: - dest: "/etc/network/interfaces.d/br-{{ item.key }}" - content: | - {% set bridge_name = 'br-'+item.key %} - {% set bridge = item.value %} - {% set interface = (network.interfaces | selectattr('name', 'eq', bridge_name) | first | default({})) %} - auto {{ bridge_name }} - {% if 'address' in interface %} - iface {{ bridge_name }} inet static - address {{ interface.address | ipaddr('address') }} - netmask {{ interface.address | ipaddr('netmask') }} - {% if 'gateway' in interface %} - gateway {{ interface.gateway }} - {% endif %} - {% else %} - iface {{ bridge_name }} inet manual - {% endif %} - {% if 'interfaces' in bridge and (bridge.interfaces | length) > 0 %} - bridge_ports {{ bridge.interfaces | join(' ') }} - {% else %} - bridge_ports none - {% endif %} - bridge_stp off - bridge_waitport 0 - bridge_fd 0 - up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/accept_ra - up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/autoconf - up modprobe br_netfilter - up /sbin/sysctl net.bridge.bridge-nf-call-iptables=0 - up /sbin/sysctl net.bridge.bridge-nf-call-ip6tables=0 - up /sbin/sysctl net.bridge.bridge-nf-call-arptables=0 - {% if 'address' in interface and 'prefix' in bridge %} - {% if 'nat' in bridge and bridge.nat %} - up echo 1 > /proc/sys/net/ipv4/conf/$IFACE/forwarding - up echo 1 > /proc/sys/net/ipv4/conf/{{ ansible_default_ipv4.interface }}/forwarding - up /sbin/iptables -t nat -A POSTROUTING -o {{ ansible_default_ipv4.interface }} -s {{ bridge.prefix }} -j SNAT --to {{ ansible_default_ipv4.address }} - {% endif %} - {% if 'overlay' in bridge %} - {% for dest, offset in (bridge.overlay.offsets | dictsort(by='value')) %} - up /bin/ip route add {{ (bridge.overlay.prefix | ipaddr(offset)).split('/')[0] }}/32 via {{ (bridge.prefix | ipaddr(bridge.offsets[dest])).split('/')[0] }} # {{ dest }} - {% endfor %} - up /bin/ip route add unreachable {{ bridge.overlay.prefix }} - down /sbin/ip route del {{ bridge.overlay.prefix }} - {% endif %} - {% if 'nat' in bridge and bridge.nat %} - down /sbin/iptables -t nat -D POSTROUTING -o {{ ansible_default_ipv4.interface }} -s {{ bridge.prefix }} -j SNAT --to {{ ansible_default_ipv4.address }} - {% endif %} - {% endif %} - {% if 'address6' in interface %} - - iface {{ bridge_name }} inet6 static - address {{ interface.address6 }} - {% if 'gateway6' in interface %} - gateway {{ interface.gateway6 }} - {% endif %} - {% endif %} - register: vmhost_bridge_config - - ## We don't try to be to clever here: aka don't call ifdown before ifup because - ## if there are VMs running they would end up with a broken network - - name: bring up bridge interfaces - loop: "{{ vmhost_bridge_config.results }}" - loop_control: - label: "br-{{ item.item.key }}" - when: item is changed - command: "/sbin/ifup br-{{ item.item.key }}" - failed_when: false diff --git a/roles/vm/host/tasks/zfs.yml b/roles/vm/host/tasks/zfs.yml deleted file mode 100644 index b84f2d0d..00000000 --- a/roles/vm/host/tasks/zfs.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -- name: create zfs base datasets - loop: "{{ lookup('dict', vm_host.zfs, wantlist=True) }}" - loop_control: - label: "{{ item.key }} -> {{ item.value.pool }}/{{ item.value.name }} ({{ (item.value.properties | default({})).items() | map('join', '=') | join(', ') }})" - vars: - default_properties: - canmount: no - mountpoint: none - zfs: - name: "{{ item.value.pool }}/{{ item.value.name }}" - state: present - extra_zfs_properties: "{{ default_properties | combine(item.value.properties | default({})) }}" - -- name: configure lvm to ignore zfs volumes - lineinfile: - path: /etc/lvm/lvm.conf - backrefs: yes - regexp: '^\s*#?\s*global_filter\s*=' - line: ' global_filter = [ "r|/dev/zd[0-9]+|" ]' diff --git a/roles/vm/install/library/wait_for_virt.py b/roles/vm/install/library/wait_for_virt.py deleted file mode 100644 index 6c49fae1..00000000 --- a/roles/vm/install/library/wait_for_virt.py +++ /dev/null @@ -1,179 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -import traceback -import time - -try: - import libvirt -except ImportError: - HAS_VIRT = False -else: - HAS_VIRT = True - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils._text import to_native - - -VIRT_FAILED = 1 -VIRT_SUCCESS = 0 -VIRT_UNAVAILABLE = 2 - -VIRT_STATE_NAME_MAP = { - 0: "running", - 1: "running", - 2: "running", - 3: "paused", - 4: "shutdown", - 5: "shutdown", - 6: "crashed" -} - - -class VMNotFound(Exception): - pass - - -class LibvirtConnection(object): - - def __init__(self, uri, module): - - self.module = module - - cmd = "uname -r" - rc, stdout, stderr = self.module.run_command(cmd) - - if "xen" in stdout: - conn = libvirt.open(None) - elif "esx" in uri: - auth = [[libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_NOECHOPROMPT], [], None] - conn = libvirt.openAuth(uri, auth) - else: - conn = libvirt.open(uri) - - if not conn: - raise Exception("hypervisor connection failure") - - self.conn = conn - - def find_vm(self, vmid): - """ - Extra bonus feature: vmid = -1 returns a list of everything - """ - conn = self.conn - - vms = [] - - # this block of code borrowed from virt-manager: - # get working domain's name - ids = conn.listDomainsID() - for id in ids: - vm = conn.lookupByID(id) - vms.append(vm) - # get defined domain - names = conn.listDefinedDomains() - for name in names: - vm = conn.lookupByName(name) - vms.append(vm) - - if vmid == -1: - return vms - - for vm in vms: - if vm.name() == vmid: - return vm - - raise VMNotFound("virtual machine %s not found" % vmid) - - def get_status(self, vmid): - state = self.find_vm(vmid).info()[0] - return VIRT_STATE_NAME_MAP.get(state, "unknown") - - -class Virt(object): - - def __init__(self, uri, module): - self.module = module - self.uri = uri - - def __get_conn(self): - self.conn = LibvirtConnection(self.uri, self.module) - return self.conn - - def status(self, vmid): - """ - Return a state suitable for server consumption. Aka, codes.py values, not XM output. - """ - self.__get_conn() - return self.conn.get_status(vmid) - - -def core(module): - - states = module.params.get('states', None) - guest = module.params.get('name', None) - uri = module.params.get('uri', None) - delay = module.params.get('delay', None) - sleep = module.params.get('sleep', None) - timeout = module.params.get('timeout', None) - - v = Virt(uri, module) - res = {'changed': False, 'failed': True} - - if delay > 0: - time.sleep(delay) - - for _ in range(0, timeout, sleep): - state = v.status(guest) - if state in states: - res['state'] = state - res['failed'] = False - res['msg'] = "guest '%s' has reached state: %s" % (guest, state) - return VIRT_SUCCESS, res - - time.sleep(sleep) - - res['msg'] = "timeout waiting for guest '%s' to reach one of states: %s" % (guest, ', '.join(states)) - return VIRT_FAILED, res - - -def main(): - - module = AnsibleModule(argument_spec=dict( - name=dict(aliases=['guest'], required=True), - states=dict(type='list', required=True), - uri=dict(default='qemu:///system'), - delay=dict(type='int', default=0), - sleep=dict(type='int', default=1), - timeout=dict(type='int', default=300), - )) - - if not HAS_VIRT: - module.fail_json( - msg='The `libvirt` module is not importable. Check the requirements.' - ) - - for state in module.params.get('states', None): - if state not in set(VIRT_STATE_NAME_MAP.values()): - module.fail_json( - msg="states contains invalid state '%s', must be one of %s" % (state, ', '.join(set(VIRT_STATE_NAME_MAP.values()))) - ) - - rc = VIRT_SUCCESS - try: - rc, result = core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=traceback.format_exc()) - - if rc != 0: # something went wrong emit the msg - module.fail_json(rc=rc, msg=result) - else: - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/roles/vm/install/tasks/installer-debian.yml b/roles/vm/install/tasks/installer-debian.yml deleted file mode 100644 index e0492969..00000000 --- a/roles/vm/install/tasks/installer-debian.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -- name: fetch debian installer files - vars: - debian_installer_distro: "{{ install_distro }}" - debian_installer_codename: "{{ install_codename }}" - debian_installer_arch: "{{ hostvars[install_hostname].install_cooked.arch | default('amd64') }}" - debian_installer_variant: netboot - import_role: - name: installer/debian/fetch - -- name: generate host specific initial ramdisk - vars: - ssh_keys_root: "{{ hostvars[install_hostname].ssh_keys_root }}" - preseed_orig_initrd: "{{ installer_base_path }}/{{ install_distro }}-{{ install_codename }}/{{ hostvars[install_hostname].install_cooked.arch | default('amd64') }}-netboot/initrd.gz" - preseed_tmpdir: "{{ tmpdir.path }}" - preseed_virtual_machine: yes - preseed_force_net_ifnames_policy: path - preseed_no_netplan: yes - install_interface: enp1s1 - import_role: - name: installer/debian/preseed diff --git a/roles/vm/install/tasks/installer-openbsd.yml b/roles/vm/install/tasks/installer-openbsd.yml deleted file mode 100644 index afa17c45..00000000 --- a/roles/vm/install/tasks/installer-openbsd.yml +++ /dev/null @@ -1,19 +0,0 @@ ---- -- name: fetch openbsd installer files - vars: - openbsd_installer_version: "{{ install_codename }}" - openbsd_installer_arch: "{{ hostvars[install_hostname].install_cooked.arch | default('amd64') }}" - import_role: - name: installer/openbsd/fetch - -- name: generate host specific autoinstall iso - vars: - ssh_keys_root: "{{ hostvars[install_hostname].ssh_keys_root }}" - obsd_autoinstall_orig_iso: "{{ installer_base_path }}/openbsd-{{ install_codename }}/{{ hostvars[install_hostname].install_cooked.arch | default('amd64') }}/install{{ openbsd_installer_version_short }}.iso" - obsd_autoinstall_tmpdir: "{{ tmpdir.path }}" - obsd_autoinstall_version: "{{ install_codename }}" - obsd_autoinstall_arch: "{{ hostvars[install_hostname].install_cooked.arch | default('amd64') }}" - obsd_autoinstall_serial_device: com0 - install_interface: vio0 - import_role: - name: installer/openbsd/autoinstall diff --git a/roles/vm/install/tasks/main.yml b/roles/vm/install/tasks/main.yml deleted file mode 100644 index a4511459..00000000 --- a/roles/vm/install/tasks/main.yml +++ /dev/null @@ -1,88 +0,0 @@ ---- -- name: create lvm-based disks for vm - loop: "{{ hostvars[install_hostname].install_cooked.disks.virtio | default({}) | combine(hostvars[install_hostname].install_cooked.disks.scsi | default({})) | dict2items | selectattr('value.type', 'eq', 'lvm') | list }}" - loop_control: - label: "{{ item.value.vg }} / {{ item.value.lv }} ({{ item.value.size }})" - lvol: - vg: "{{ item.value.vg }}" - lv: "{{ item.value.lv }}" - size: "{{ item.value.size }}" - state: present - -- name: create zfs base datasets for vm - loop: "{{ hostvars[install_hostname].install_cooked.disks.virtio | default({}) | combine(hostvars[install_hostname].install_cooked.disks.scsi | default({})) | dict2items | selectattr('value.type', 'eq', 'zfs') | map(attribute='value.backend') | map('default', 'default') | unique | list }}" - zfs: - name: "{{ vm_host_cooked.zfs[item].pool }}/{{ vm_host_cooked.zfs[item].name }}/{{ install_hostname }}" - state: present - extra_zfs_properties: - canmount: no - mountpoint: none - -- name: create zfs-based disk volumes for vm - loop: "{{ hostvars[install_hostname].install_cooked.disks.virtio | default({}) | combine(hostvars[install_hostname].install_cooked.disks.scsi | default({})) | dict2items | selectattr('value.type', 'eq', 'zfs') | list }}" - loop_control: - label: "{{ item.value.name }} on backend {{ item.value.backend | default('default') }} ({{ item.value.size }})" - zfs: - name: "{{ vm_host_cooked.zfs[item.value.backend | default('default')].pool }}/{{ vm_host_cooked.zfs[item.value.backend | default('default')].name }}/{{ install_hostname }}/{{ item.value.name }}" - state: present - extra_zfs_properties: "{{ item.value.properties | default({}) | combine({'volsize': item.value.size}) }}" - - -- block: - - name: create a temporary workdir - tempfile: - path: "{{ installer_base_path }}/" - prefix: ".{{ install_hostname }}." - state: directory - register: tmpdir - - - when: install_distro in ['debian', 'ubuntu'] - import_tasks: installer-debian.yml - - - when: install_distro in ['openbsd'] - import_tasks: installer-openbsd.yml - - - name: Make installer workdir readable by qemu - acl: - path: "{{ tmpdir.path }}" - state: present - entity: libvirt-qemu - etype: user - permissions: rx - - - vars: - vm_define_installer: yes - installer_tmpdir: "{{ tmpdir.path }}" - import_role: - name: vm/define - - - debug: - msg: "you can check on the status of the installer running this command 'virsh console {{ install_hostname }}' on host {{ inventory_hostname }}." - - - when: installer_manual_steps_msg is defined - pause: - prompt: | - Mind that this installer needs manual steps to be performed: - - {{ installer_manual_steps_msg | indent(2) }} - - When done press enter to continue or Ctrl-C + 'A' to abort. - - - name: wait for installer to finish or crash - wait_for_virt: - name: "{{ install_hostname }}" - states: shutdown,crashed - timeout: 1800 - register: installer_result - failed_when: installer_result.failed or installer_result.state == "crashed" - - always: - - name: cleanup temporary workdir - file: - path: "{{ tmpdir.path }}" - state: absent - -- vars: - vm_define_installer: no - import_role: - name: vm/define diff --git a/roles/vm/network/handlers/main.yml b/roles/vm/network/handlers/main.yml deleted file mode 100644 index f967fa86..00000000 --- a/roles/vm/network/handlers/main.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -- name: rebuild initramfs - command: update-initramfs -u diff --git a/roles/vm/network/tasks/main.yml b/roles/vm/network/tasks/main.yml deleted file mode 100644 index 27a7682a..00000000 --- a/roles/vm/network/tasks/main.yml +++ /dev/null @@ -1,40 +0,0 @@ ---- -- name: configure systemd link units - when: network_cooked.systemd_link is defined - block: - - name: remove legacy systemd.link units - loop: - - 50-virtio-kernel-names.link - - 99-default.link - file: - name: "/etc/systemd/network/{{ item }}" - state: absent - - - name: install systemd network link units - loop: "{{ network_cooked.systemd_link.interfaces }}" - loop_control: - label: "{{ item.name }}" - index_var: interface_index - template: - src: systemd.link.j2 - dest: "/etc/systemd/network/{{ '%02d' | format(interface_index + 11) }}-{{ item.name }}.link" - notify: rebuild initramfs - - -- name: install basic interface config - template: - src: interfaces.j2 - dest: /etc/network/interfaces - mode: 0644 - -- name: remove resolvconf package - apt: - name: resolvconf - state: absent - force_apt_get: yes - purge: yes - -- name: generate resolv.conf - template: - src: resolv.conf.j2 - dest: /etc/resolv.conf diff --git a/roles/vm/network/templates/interfaces.j2 b/roles/vm/network/templates/interfaces.j2 deleted file mode 100644 index 8c288669..00000000 --- a/roles/vm/network/templates/interfaces.j2 +++ /dev/null @@ -1,56 +0,0 @@ -# This file describes the network interfaces available on your system -# and how to activate them. For more information, see interfaces(5). - -source /etc/network/interfaces.d/* - -# The loopback network interface -auto lo -iface lo inet loopback -{% for interface in network_cooked.interfaces %} - - -auto {{ interface.name }} -iface {{ interface.name }} inet static - pre-up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/accept_ra - pre-up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/autoconf - address {{ interface.address | ipaddr('address') }} - netmask {{ interface.address | ipaddr('netmask') }} -{% if 'overlay' in interface %} - up /bin/ip addr add dev $IFACE {{ interface.overlay }}/32 -{% for route in interface.static_routes | default([]) %} - up /bin/ip route add {{ route.destination }} via {{ route.gateway }} src {{ interface.overlay }} -{% endfor %} -{% if 'gateway' in interface %} - up /bin/ip route add default via {{ interface.gateway }} src {{ interface.overlay }} - down /bin/ip route del default via {{ interface.gateway }} src {{ interface.overlay }} -{% for route in interface.static_routes | default([]) | reverse %} - down /bin/ip route del {{ route.destination }} via {{ route.gateway }} src {{ interface.overlay }} -{% endfor %} -{% endif %} - down /bin/ip addr del dev $IFACE {{ interface.overlay }}/32 -{% else %} -{% if 'gateway' in interface %} - gateway {{ interface.gateway }} -{% endif %} -{% for route in interface.static_routes | default([]) %} - up /bin/ip route add {{ route.destination }} via {{ route.gateway }} -{% endfor %} -{% for route in interface.static_routes | default([]) | reverse %} - down /bin/ip route del {{ route.destination }} via {{ route.gateway }} -{% endfor %} -{% endif %} -{% if 'address6' in interface %} - -iface {{ interface.name }} inet6 static - address {{ interface.address6 }} -{% if 'gateway6' in interface %} - gateway {{ interface.gateway6 }} -{% endif %} -{% for route in interface.static_routes6 | default([]) %} - up /bin/ip -6 route add {{ route.destination }} via {{ route.gateway }} -{% endfor %} -{% for route in interface.static_routes6 | default([]) | reverse %} - down /bin/ip -6 route del {{ route.destination }} via {{ route.gateway }} -{% endfor %} -{% endif %} -{% endfor %} diff --git a/roles/vm/network/templates/resolv.conf.j2 b/roles/vm/network/templates/resolv.conf.j2 deleted file mode 100644 index 00aaafe3..00000000 --- a/roles/vm/network/templates/resolv.conf.j2 +++ /dev/null @@ -1,4 +0,0 @@ -{% for nsrv in network_cooked.nameservers %} -nameserver {{ nsrv }} -{% endfor %} -search {{ network_cooked.domain }} diff --git a/roles/vm/network/templates/systemd.link.j2 b/roles/vm/network/templates/systemd.link.j2 deleted file mode 100644 index 7093e164..00000000 --- a/roles/vm/network/templates/systemd.link.j2 +++ /dev/null @@ -1,5 +0,0 @@ -[Match] -Path=*pci-0000:01:{{ "%02d" | format(interface_index + 1) }}.0 - -[Link] -Name={{ item.name }} -- cgit v1.2.3