summaryrefslogtreecommitdiff
path: root/roles/vm
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2018-05-24 23:40:30 +0200
committerChristian Pointner <equinox@spreadspace.org>2018-05-24 23:40:30 +0200
commit79c40fec07d7ea906cf1375fa93a4b202766ba79 (patch)
tree11266d83065f2507da0d1f118a8d832be82a13c2 /roles/vm
parentsome cleanups (diff)
move vm roles to subdir
Diffstat (limited to 'roles/vm')
-rw-r--r--roles/vm/grub/handlers/main.yml3
-rw-r--r--roles/vm/grub/tasks/main.yml12
-rw-r--r--roles/vm/host/defaults/main.yml7
-rw-r--r--roles/vm/host/handlers/main.yml5
-rw-r--r--roles/vm/host/tasks/main.yml54
-rw-r--r--roles/vm/install/library/wait_for_virt.py179
-rw-r--r--roles/vm/install/tasks/main.yml123
-rw-r--r--roles/vm/install/templates/libvirt-domain.xml.j270
-rw-r--r--roles/vm/install/templates/preseed_debian-stretch.cfg.j2105
-rw-r--r--roles/vm/network/handlers/main.yml3
-rw-r--r--roles/vm/network/tasks/lan.yml6
-rw-r--r--roles/vm/network/tasks/main.yml9
-rw-r--r--roles/vm/network/tasks/public.yml33
-rw-r--r--roles/vm/network/tasks/systemd-link.yml15
-rw-r--r--roles/vm/network/templates/firewall.sh_public.j249
-rw-r--r--roles/vm/network/templates/interfaces_lan.j217
-rw-r--r--roles/vm/network/templates/interfaces_public.j263
-rw-r--r--roles/vm/network/templates/systemd.link.j25
18 files changed, 758 insertions, 0 deletions
diff --git a/roles/vm/grub/handlers/main.yml b/roles/vm/grub/handlers/main.yml
new file mode 100644
index 00000000..4bddbb14
--- /dev/null
+++ b/roles/vm/grub/handlers/main.yml
@@ -0,0 +1,3 @@
+---
+- name: update grub
+ command: /usr/sbin/update-grub
diff --git a/roles/vm/grub/tasks/main.yml b/roles/vm/grub/tasks/main.yml
new file mode 100644
index 00000000..bd48a470
--- /dev/null
+++ b/roles/vm/grub/tasks/main.yml
@@ -0,0 +1,12 @@
+---
+- name: enable serial console in grub and for kernel
+ lineinfile:
+ dest: /etc/default/grub
+ regexp: "{{ item.regexp }}"
+ line: "{{ item.line }}"
+ with_items:
+ - { regexp: '^GRUB_TIMEOUT=', line: 'GRUB_TIMEOUT=2' }
+ - { regexp: '^GRUB_CMDLINE_LINUX=', line: 'GRUB_CMDLINE_LINUX="console=ttyS0,115200n8"' }
+ - { regexp: '^GRUB_TERMINAL=', line: 'GRUB_TERMINAL=serial' }
+ - { regexp: '^GRUB_SERIAL_COMMAND=', line: 'GRUB_SERIAL_COMMAND="serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1"' }
+ notify: update grub
diff --git a/roles/vm/host/defaults/main.yml b/roles/vm/host/defaults/main.yml
new file mode 100644
index 00000000..0e3cddf1
--- /dev/null
+++ b/roles/vm/host/defaults/main.yml
@@ -0,0 +1,7 @@
+---
+vm_host_force_download_installer: False
+vm_host_installer_url:
+ # debian: "{{ debian_mirror.packages | default('http://deb.debian.org/debian') }}"
+ # ubuntu: "{{ ubuntu_mirror | default('http://archive.ubuntu.com/ubuntu') }}"
+ debian: "http://deb.debian.org/debian"
+ ubuntu: "http://archive.ubuntu.com/ubuntu"
diff --git a/roles/vm/host/handlers/main.yml b/roles/vm/host/handlers/main.yml
new file mode 100644
index 00000000..158f4dcd
--- /dev/null
+++ b/roles/vm/host/handlers/main.yml
@@ -0,0 +1,5 @@
+---
+- name: restart inetd
+ service:
+ name: openbsd-inetd
+ state: restarted
diff --git a/roles/vm/host/tasks/main.yml b/roles/vm/host/tasks/main.yml
new file mode 100644
index 00000000..a5e98fa9
--- /dev/null
+++ b/roles/vm/host/tasks/main.yml
@@ -0,0 +1,54 @@
+---
+- name: install tftpd and python-libvirt
+ with_items:
+ - atftpd
+ - openbsd-inetd
+ - qemu-kvm
+ - libvirt-bin
+ - python-libvirt
+ apt:
+ name: "{{ item }}"
+ state: present
+
+- name: configure tftpd via inetd
+ lineinfile:
+ regexp: "^#?({{ vm_host.network.ip }}:)?tftp"
+ line: "{{ vm_host.network.ip }}:tftp dgram udp4 wait nobody /usr/sbin/tcpd /usr/sbin/in.tftpd --tftpd-timeout 300 --retry-timeout 5 --maxthread 10 --verbose=5 {{ vm_host.installer.preseed_path }}"
+ path: /etc/inetd.conf
+ notify: restart inetd
+
+- name: make sure installer directories exists
+ with_items:
+ - "{{ vm_host.installer.path }}"
+ - "{{ vm_host.installer.preseed_path }}"
+ file:
+ name: "{{ item }}"
+ state: directory
+
+- name: prepare directories for installer images
+ with_subelements:
+ - "{{ vm_host.installer.distros }}"
+ - arch
+ file:
+ name: "{{ vm_host.installer.path }}/{{ item.0.distro }}-{{ item.0.codename }}/{{ item.1 }}"
+ state: directory
+
+- name: download installer kernel images
+ with_subelements:
+ - "{{ vm_host.installer.distros }}"
+ - arch
+ get_url:
+ url: "{{ vm_host_installer_url[item.0.distro] }}/dists/{{ item.0.codename }}/main/installer-{{ item.1 }}/current/images/netboot/{{ item.0.distro }}-installer/{{ item.1 }}/linux"
+ dest: "{{ vm_host.installer.path }}/{{ item.0.distro }}-{{ item.0.codename }}/{{ item.1 }}/linux"
+ mode: 0644
+ force: "{{ vm_host_force_download_installer }}"
+
+- name: download installer initrd.gz
+ with_subelements:
+ - "{{ vm_host.installer.distros }}"
+ - arch
+ get_url:
+ url: "{{ vm_host_installer_url[item.0.distro] }}/dists/{{ item.0.codename }}/main/installer-{{ item.1 }}/current/images/netboot/{{ item.0.distro }}-installer/{{ item.1 }}/initrd.gz"
+ dest: "{{ vm_host.installer.path }}/{{ item.0.distro }}-{{ item.0.codename }}/{{ item.1 }}/initrd.gz"
+ mode: 0644
+ force: "{{ vm_host_force_download_installer }}"
diff --git a/roles/vm/install/library/wait_for_virt.py b/roles/vm/install/library/wait_for_virt.py
new file mode 100644
index 00000000..6c49fae1
--- /dev/null
+++ b/roles/vm/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/install/tasks/main.yml b/roles/vm/install/tasks/main.yml
new file mode 100644
index 00000000..22a6a351
--- /dev/null
+++ b/roles/vm/install/tasks/main.yml
@@ -0,0 +1,123 @@
+---
+- name: generate preseed file
+ template:
+ src: "preseed_{{ vmdistro }}-{{ vmdistcodename }}.cfg.j2"
+ dest: "{{ hostvars[vm_install.host].vm_host.installer.preseed_path }}/vm-{{ inventory_hostname }}-{{ vmdistro }}-{{ vmdistcodename }}.cfg"
+ delegate_to: "{{ vm_install.host }}"
+
+- name: create disks for vm
+ with_dict: "{{ vm_install.disks.virtio | default({}) | combine(vm_install.disks.scsi | default({})) }}"
+ lvol:
+ vg: "{{ item.value.vg }}"
+ lv: "{{ item.value.lv }}"
+ size: "{{ item.value.size }}"
+ delegate_to: "{{ vm_install.host }}"
+
+- name: check if vm already exists
+ virt:
+ name: "{{ inventory_hostname }}"
+ command: info
+ delegate_to: "{{ vm_install.host }}"
+ register: vmhost_info
+
+- name: destroy exisiting vm
+ virt:
+ name: "{{ inventory_hostname }}"
+ state: destroyed
+ delegate_to: "{{ vm_install.host }}"
+ when: inventory_hostname in vmhost_info
+
+- name: wait for vm to be destroyed
+ wait_for_virt:
+ name: "{{ inventory_hostname }}"
+ states: shutdown,crashed
+ timeout: 5
+ delegate_to: "{{ vm_install.host }}"
+ when: inventory_hostname in vmhost_info
+
+- name: undefining exisiting vm
+ virt:
+ name: "{{ inventory_hostname }}"
+ command: undefine
+ delegate_to: "{{ vm_install.host }}"
+ when: inventory_hostname in vmhost_info
+
+- name: enable installer in VM config
+ set_fact:
+ run_installer: True
+
+- name: define new installer vm
+ virt:
+ name: "{{ inventory_hostname }}"
+ command: define
+ xml: "{{ lookup('template', 'libvirt-domain.xml.j2') }}"
+ delegate_to: "{{ vm_install.host }}"
+
+- name: start vm
+ virt:
+ name: "{{ inventory_hostname }}"
+ state: running
+ delegate_to: "{{ vm_install.host }}"
+
+- name: wait for installer to start
+ wait_for_virt:
+ name: "{{ inventory_hostname }}"
+ states: running
+ timeout: 10
+ delegate_to: "{{ vm_install.host }}"
+
+- debug:
+ msg: "you can check on the status of the installer running this command 'virsh console {{ inventory_hostname }}' on host {{ vm_install.host }}."
+
+- name: wait for installer to finish or crash
+ wait_for_virt:
+ name: "{{ inventory_hostname }}"
+ states: shutdown,crashed
+ timeout: 900
+ delegate_to: "{{ vm_install.host }}"
+ register: installer_result
+ failed_when: installer_result.failed or installer_result.state == "crashed"
+
+- name: undefining installer vm
+ virt:
+ name: "{{ inventory_hostname }}"
+ command: undefine
+ delegate_to: "{{ vm_install.host }}"
+
+- name: disable installer in VM config
+ set_fact:
+ run_installer: False
+
+- name: define new production vm
+ virt:
+ name: "{{ inventory_hostname }}"
+ command: define
+ xml: "{{ lookup('template', 'libvirt-domain.xml.j2') }}"
+ delegate_to: "{{ vm_install.host }}"
+
+- name: start vm
+ virt:
+ name: "{{ inventory_hostname }}"
+ state: running
+ delegate_to: "{{ vm_install.host }}"
+
+- name: mark vm as autostarted
+ virt:
+ name: "{{ inventory_hostname }}"
+ autostart: "{{ vm_install.autostart }}"
+ command: info ## virt module needs either command or state
+ delegate_to: "{{ vm_install.host }}"
+ when: vm_install.autostart is defined
+
+- name: disable ssh StrictHostKeyChecking for the next step
+ set_fact:
+ ansible_ssh_extra_args: -o StrictHostKeyChecking=no
+
+- name: wait for vm to start up
+ wait_for_connection:
+ delay: 5
+ timeout: 120
+
+- name: reenable StrictHostKeyChecking
+ set_fact:
+ ansible_ssh_extra_args: ""
diff --git a/roles/vm/install/templates/libvirt-domain.xml.j2 b/roles/vm/install/templates/libvirt-domain.xml.j2
new file mode 100644
index 00000000..c84b1045
--- /dev/null
+++ b/roles/vm/install/templates/libvirt-domain.xml.j2
@@ -0,0 +1,70 @@
+<domain type='kvm'>
+ <name>{{ inventory_hostname }}</name>
+ <memory>{{ vm_install.mem * 1024 }}</memory>
+ <currentMemory>{{ vm_install.mem * 1024 }}</currentMemory>
+ <vcpu>{{ vm_install.numcpu }}</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc-0.12'>hvm</type>
+{% if run_installer %}
+ <kernel>{{ hostvars[vm_install.host].vm_host.installer.path }}/{{ vmdistro }}-{{ vmdistcodename }}/{{ vm_install.arch | default('amd64') }}/linux</kernel>
+ <initrd>{{ hostvars[vm_install.host].vm_host.installer.path }}/{{ vmdistro }}-{{ vmdistcodename }}/{{ vm_install.arch | default('amd64') }}/initrd.gz</initrd>
+ <cmdline>console=ttyS0,115200n8 auto=true interface=auto url=tftp://{{ hostvars[vm_install.host]['ansible_' + hostvars[vm_install.host].vm_host.installer.net_if].ipv4.address }}/vm-{{ inventory_hostname }}-{{ vmdistro }}-{{ vmdistcodename }}.cfg netcfg/choose_interface=enp1s1 netcfg/disable_autoconfig=true netcfg/get_ipaddress={{ vm_network.primary.ip }} netcfg/get_netmask={{ vm_network.primary.mask }} netcfg/get_gateway={{ vm_network.primary.gateway }} netcfg/get_nameservers="{{ vm_network.primary.nameservers | join(' ') }}" netcfg/confirm_static=true netcfg/get_hostname={{ inventory_hostname }} netcfg/get_domain={{ vm_network.primary.domain }}</cmdline>
+{% endif %}
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <pae/>
+ </features>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+{% if run_installer %}
+ <on_reboot>destroy</on_reboot>
+ <on_crash>destroy</on_crash>
+{% else %}
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+{% endif %}
+ <devices>
+ <emulator>/usr/bin/kvm</emulator>
+
+{% if 'virtio' in vm_install.disks %}
+{% for device, lv in vm_install.disks.virtio.items() %}
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='raw' cache='none' discard='unmap'/>
+ <source dev='/dev/mapper/{{ lv.vg | replace('-', '--') }}-{{ lv.lv | replace('-', '--') }}'/>
+ <target dev='{{ device }}' bus='virtio'/>
+ </disk>
+{% endfor %}
+{% endif %}
+
+{% if 'scsi' in vm_install.disks %}
+ <controller type='scsi' index='0' model='virtio-scsi'/>
+{% for device, lv in vm_install.disks.scsi.items() %}
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='raw' cache='none' discard='unmap'/>
+ <source dev='/dev/mapper/{{ lv.vg | replace('-', '--') }}-{{ lv.lv | replace('-', '--') }}'/>
+ <target dev='{{ device }}' bus='scsi'/>
+ </disk>
+{% endfor %}
+{% endif %}
+
+{% if vm_install.interfaces %}
+{% for if in vm_install.interfaces %}
+ <interface type='bridge'>
+ <source bridge='{{ if.bridge }}'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x01' slot='0x0{{ if.idx }}' function='0x0'/>
+ </interface>
+{% endfor %}
+{% endif %}
+
+ <serial type='pty'>
+ <target port='0'/>
+ </serial>
+ <console type='pty'>
+ <target type='serial' port='0'/>
+ </console>
+ </devices>
+</domain>
diff --git a/roles/vm/install/templates/preseed_debian-stretch.cfg.j2 b/roles/vm/install/templates/preseed_debian-stretch.cfg.j2
new file mode 100644
index 00000000..55ddbfc2
--- /dev/null
+++ b/roles/vm/install/templates/preseed_debian-stretch.cfg.j2
@@ -0,0 +1,105 @@
+#########################################################################
+# spreadspace preseed file for Debian stretch based VMs
+#########################################################################
+
+d-i debian-installer/language string en
+d-i debian-installer/country string AT
+d-i debian-installer/locale string de_AT.UTF-8
+d-i keyboard-configuration/xkb-keymap select de
+
+
+#d-i netcfg/choose_interface select enp1s1
+#d-i netcfg/disable_autoconfig boolean false
+#d-i netcfg/get_ipaddress string {{ vm_network.primary.ip }}
+#d-i netcfg/get_netmask string {{ vm_network.primary.mask }}
+#d-i netcfg/get_gateway string {{ vm_network.primary.gateway }}
+#d-i netcfg/get_nameservers string {{ vm_network.primary.nameservers | join(' ') }}
+#d-i netcfg/confirm_static boolean true
+
+d-i netcfg/get_hostname string {{ inventory_hostname }}
+d-i netcfg/get_domain string {{ vm_network.primary.domain }}
+d-i netcfg/wireless_wep string
+
+
+d-i mirror/country string manual
+d-i mirror/http/hostname string deb.debian.org
+d-i mirror/http/directory string /debian
+d-i mirror/http/proxy string
+
+
+d-i passwd/make-user boolean false
+d-i passwd/root-password password this-very-very-secure-password-will-be-removed-by-latecommand
+d-i passwd/root-password-again password this-very-very-secure-password-will-be-removed-by-latecommand
+
+
+d-i clock-setup/utc boolean true
+d-i time/zone string Europe/Vienna
+d-i clock-setup/ntp boolean false
+
+
+d-i partman-auto/disk string /dev/{{ vm_install.disks.primary }}
+d-i partman-auto/method string lvm
+d-i partman-lvm/device_remove_lvm boolean true
+d-i partman-md/device_remove_md boolean true
+
+d-i partman-lvm/confirm boolean true
+d-i partman-lvm/confirm_nooverwrite boolean true
+
+d-i partman-auto/expert_recipe string \
+ boot-root :: \
+ 1000 10000 -1 ext4 \
+ $defaultignore{ } $primary{ } $bootable{ } \
+ method{ lvm } vg_name{ {{ inventory_hostname }} } \
+ . \
+ 2048 10000 2560 ext4 \
+ $lvmok{ } in_vg{ {{ inventory_hostname }} } \
+ method{ format } format{ } \
+ use_filesystem{ } filesystem{ ext4 } \
+ mountpoint{ / } \
+ . \
+ 1024 11000 1280 ext4 \
+ $lvmok{ } in_vg{ {{ inventory_hostname }} } \
+ method{ format } format{ } \
+ use_filesystem{ } filesystem{ ext4 } \
+ mountpoint{ /var } \
+ . \
+ 768 10000 768 ext4 \
+ $lvmok{ } in_vg{ {{ inventory_hostname }} } \
+ method{ format } format{ } \
+ use_filesystem{ } filesystem{ ext4 } \
+ mountpoint{ /var/log } \
+ options/nodev{ nodev } options/noatime{ noatime } \
+ options/noexec{ noexec } \
+ . \
+ 16 20000 -1 ext4 \
+ $lvmok{ } in_vg{ {{ inventory_hostname }} } \
+ method( keep } lv_name{ dummy } \
+ .
+
+d-i partman-auto-lvm/no_boot boolean true
+d-i partman-basicfilesystems/no_swap true
+d-i partman-partitioning/confirm_write_new_label boolean true
+d-i partman/choose_partition select finish
+d-i partman/confirm boolean true
+d-i partman/confirm_nooverwrite boolean true
+
+
+d-i base-installer/install-recommends boolean false
+d-i apt-setup/security_host string deb.debian.org
+
+tasksel tasksel/first multiselect
+d-i pkgsel/include string openssh-server python
+d-i pkgsel/upgrade select safe-upgrade
+popularity-contest popularity-contest/participate boolean false
+
+d-i grub-installer/choose_bootdev string /dev/{{ vm_install.disks.primary }}
+d-i grub-installer/only_debian boolean true
+d-i grub-installer/with_other_os boolean false
+
+d-i finish-install/reboot_in_progress note
+
+
+d-i preseed/late_command string \
+ lvremove -f {{ inventory_hostname }}/dummy; \
+ in-target bash -c "apt-get update -q && apt-get full-upgrade -y -q"; \
+ in-target bash -c "passwd -d root; passwd -l root; umask 077; mkdir -p /root/.ssh/; echo -e '{{ sshserver_root_keys }}' > /root/.ssh/authorized_keys"
diff --git a/roles/vm/network/handlers/main.yml b/roles/vm/network/handlers/main.yml
new file mode 100644
index 00000000..f967fa86
--- /dev/null
+++ b/roles/vm/network/handlers/main.yml
@@ -0,0 +1,3 @@
+---
+- name: rebuild initramfs
+ command: update-initramfs -u
diff --git a/roles/vm/network/tasks/lan.yml b/roles/vm/network/tasks/lan.yml
new file mode 100644
index 00000000..ec436e9b
--- /dev/null
+++ b/roles/vm/network/tasks/lan.yml
@@ -0,0 +1,6 @@
+---
+- name: install interface config (LAN only)
+ template:
+ src: interfaces_lan.j2
+ dest: /etc/network/interfaces
+ mode: 0644
diff --git a/roles/vm/network/tasks/main.yml b/roles/vm/network/tasks/main.yml
new file mode 100644
index 00000000..222a350b
--- /dev/null
+++ b/roles/vm/network/tasks/main.yml
@@ -0,0 +1,9 @@
+---
+- import_tasks: systemd-link.yml
+ when: srv_network.systemd_link is defined
+
+- import_tasks: public.yml
+ when: srv_network.public is defined
+
+- import_tasks: lan.yml
+ when: srv_network.public is not defined
diff --git a/roles/vm/network/tasks/public.yml b/roles/vm/network/tasks/public.yml
new file mode 100644
index 00000000..8b0e317a
--- /dev/null
+++ b/roles/vm/network/tasks/public.yml
@@ -0,0 +1,33 @@
+---
+- name: set routing table names
+ with_items:
+ - { regexp: '^89\s', line: '89 mur-default' }
+ - { regexp: '^212\s', line: '212 upc-default' }
+ lineinfile:
+ regexp: "{{ item.regexp }}"
+ line: "{{ item.line }}"
+ dest: /etc/iproute2/rt_tables
+
+- name: calculate address lists
+ set_fact:
+ srv_network_public_firewall_ipv4:
+ - "{{ srv_network.public.ip_mur }}"
+ - "{{ srv_network.public.ip_upc }}"
+ srv_network_public_firewall_ipv6:
+ - "{{ srv_network.public.ip_mur6 }}"
+
+- name: install firewall scripts
+ with_items:
+ - 4
+ - 6
+ template:
+ src: firewall.sh_public.j2
+ dest: "/etc/network/firewall{{ item }}.sh"
+ mode: 0755
+ when: srv_network.public.firewall is defined
+
+- name: install interface config (Public)
+ template:
+ src: interfaces_public.j2
+ dest: /etc/network/interfaces
+ mode: 0644
diff --git a/roles/vm/network/tasks/systemd-link.yml b/roles/vm/network/tasks/systemd-link.yml
new file mode 100644
index 00000000..ad12cd37
--- /dev/null
+++ b/roles/vm/network/tasks/systemd-link.yml
@@ -0,0 +1,15 @@
+---
+- name: remove legacy systemd.link units
+ file:
+ name: "/etc/systemd/network/{{ item }}"
+ state: absent
+ with_items:
+ - 50-virtio-kernel-names.link
+ - 99-default.link
+
+- name: install systemd network link units
+ template:
+ src: systemd.link.j2
+ dest: "/etc/systemd/network/{{ '%02d' | format(item.idx + 10) }}-{{ item.name }}.link"
+ with_items: "{{ srv_network.systemd_link.interfaces }}"
+ notify: rebuild initramfs
diff --git a/roles/vm/network/templates/firewall.sh_public.j2 b/roles/vm/network/templates/firewall.sh_public.j2
new file mode 100644
index 00000000..df5b1373
--- /dev/null
+++ b/roles/vm/network/templates/firewall.sh_public.j2
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+PUBLIC_IPS="{% if item == 4 %}{{ srv_network_public_firewall_ipv4 | join(' ') }}{% else %}{{ srv_network_public_firewall_ipv6 | join(' ') }}{% endif %}"
+PUBLIC_IF="$2"
+TCP_PORTS="{{ srv_network.public.firewall.tcp_ports | default([]) | join(' ') }}"
+UDP_PORTS="{{ srv_network.public.firewall.udp_ports | default([]) | join(' ') }}"
+
+#####
+IPTABLES="/sbin/ip{% if item == 6 %}6{% endif %}tables"
+ICMP="icmp{% if item == 6 %}v6{% endif %}"
+
+case "$1" in
+ start)
+ $IPTABLES -A INPUT -i $PUBLIC_IF -p $ICMP -j ACCEPT
+ $IPTABLES -A INPUT -i $PUBLIC_IF -m state --state related,established -j ACCEPT
+ for port in $TCP_PORTS; do
+ for ip in $PUBLIC_IPS; do
+ $IPTABLES -A INPUT -i $PUBLIC_IF -d $ip -p tcp --dport $port -j ACCEPT
+ done
+ done
+ for port in $UDP_PORTS; do
+ for ip in $PUBLIC_IPS; do
+ $IPTABLES -A INPUT -i $PUBLIC_IF -d $ip -p udp --dport $port -j ACCEPT
+ done
+ done
+ $IPTABLES -A INPUT -i $PUBLIC_IF -j DROP
+ ;;
+ stop)
+ $IPTABLES -D INPUT -i $PUBLIC_IF -j DROP
+ for port in $UDP_PORTS; do
+ for ip in $PUBLIC_IPS; do
+ $IPTABLES -D INPUT -i $PUBLIC_IF -d $ip -p udp --dport $port -j ACCEPT
+ done
+ done
+ for port in $TCP_PORTS; do
+ for ip in $PUBLIC_IPS; do
+ $IPTABLES -D INPUT -i $PUBLIC_IF -d $ip -p tcp --dport $port -j ACCEPT
+ done
+ done
+ $IPTABLES -D INPUT -i $PUBLIC_IF -m state --state related,established -j ACCEPT
+ $IPTABLES -D INPUT -i $PUBLIC_IF -p $ICMP -j ACCEPT
+ ;;
+ *)
+ echo "Usage: $0 (start|stop)"
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/roles/vm/network/templates/interfaces_lan.j2 b/roles/vm/network/templates/interfaces_lan.j2
new file mode 100644
index 00000000..36ae2883
--- /dev/null
+++ b/roles/vm/network/templates/interfaces_lan.j2
@@ -0,0 +1,17 @@
+# 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
+
+# The internal network interface
+auto {{ srv_network.internal.interface }}
+iface {{ srv_network.internal.interface }} inet static
+ address {{ srv_network.internal.ip }}
+ netmask 255.255.255.0
+ gateway 192.168.1.254
+ pre-up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/accept_ra
+ pre-up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/autoconf
diff --git a/roles/vm/network/templates/interfaces_public.j2 b/roles/vm/network/templates/interfaces_public.j2
new file mode 100644
index 00000000..2e8583ab
--- /dev/null
+++ b/roles/vm/network/templates/interfaces_public.j2
@@ -0,0 +1,63 @@
+# 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
+
+# The internal network interface
+auto {{ srv_network.internal.interface }}
+iface {{ srv_network.internal.interface }} inet static
+ address {{ srv_network.internal.ip }}
+ netmask 255.255.255.0
+ pre-up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/accept_ra
+ pre-up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/autoconf
+ up ip route add default via 192.168.1.254 table default
+ up ip rule add pref 42000 lookup default
+ up ip rule del pref 32767
+ down ip rule add pref 32767 lookup default
+ down ip rule del pref 42000
+ down ip route del default via 192.168.1.254 table default
+
+
+# The public network interface
+auto {{ srv_network.public.interface }}
+iface {{ srv_network.public.interface }} inet static
+ address {{ srv_network.public.ip }}
+ netmask 255.255.255.0
+ pre-up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/accept_ra
+ pre-up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/autoconf
+ ## mur.at
+ up ip addr add dev $IFACE {{ srv_network.public.ip_mur }}/28
+ up ip route add default via 89.106.215.14 src {{ srv_network.public.ip_mur }} table mur-default
+ up ip rule add pref 33000 from {{ srv_network.public.ip_mur }} lookup mur-default
+ ## upc
+ up ip addr add dev $IFACE {{ srv_network.public.ip_upc }}/32
+ up ip route add default via 192.168.3.254 src {{ srv_network.public.ip_upc }} table upc-default
+ up ip rule add pref 35000 from {{ srv_network.public.ip_upc }} lookup upc-default
+ ### firewall
+ up /etc/network/firewall4.sh start $IFACE
+ ##########
+ down /etc/network/firewall4.sh stop $IFACE
+ ## upc
+ down ip rule del pref 35000
+ down ip route del default via 192.168.3.254 src {{ srv_network.public.ip_upc }} table upc-default
+ down ip addr del dev $IFACE {{ srv_network.public.ip_upc }}/32
+ ## mur.at
+ down ip rule del pref 33000
+ down ip route del default via 89.106.215.14 src {{ srv_network.public.ip_mur }} table mur-default
+ down ip addr del dev $IFACE {{ srv_network.public.ip_mur }}/28
+
+iface {{ srv_network.public.interface }} inet6 static
+ address {{ srv_network.public.ip_mur6 }}
+ netmask 64
+ pre-up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/accept_ra
+ pre-up echo 0 > /proc/sys/net/ipv6/conf/$IFACE/autoconf
+ up ip -6 route add default via 2a02:3e0:2003::e src {{ srv_network.public.ip_mur6 }} table mur-default
+ up ip -6 rule add pref 33000 from {{ srv_network.public.ip_mur6 }} lookup mur-default
+ up /etc/network/firewall6.sh start $IFACE
+ down /etc/network/firewall6.sh stop $IFACE
+ down ip -6 rule del pref 33000
+ down ip -6 route del default via 2a02:3e0:2003::e src {{ srv_network.public.ip_mur6 }} table mur-default
diff --git a/roles/vm/network/templates/systemd.link.j2 b/roles/vm/network/templates/systemd.link.j2
new file mode 100644
index 00000000..753fd586
--- /dev/null
+++ b/roles/vm/network/templates/systemd.link.j2
@@ -0,0 +1,5 @@
+[Match]
+Path=pci-0000:01:{{ "%02d" | format(item.idx) }}.0
+
+[Link]
+Name={{ item.name }}