diff options
Diffstat (limited to 'roles/vm')
-rw-r--r-- | roles/vm/grub/handlers/main.yml | 3 | ||||
-rw-r--r-- | roles/vm/grub/tasks/main.yml | 12 | ||||
-rw-r--r-- | roles/vm/host/defaults/main.yml | 7 | ||||
-rw-r--r-- | roles/vm/host/handlers/main.yml | 5 | ||||
-rw-r--r-- | roles/vm/host/tasks/main.yml | 54 | ||||
-rw-r--r-- | roles/vm/install/library/wait_for_virt.py | 179 | ||||
-rw-r--r-- | roles/vm/install/tasks/main.yml | 123 | ||||
-rw-r--r-- | roles/vm/install/templates/libvirt-domain.xml.j2 | 70 | ||||
-rw-r--r-- | roles/vm/install/templates/preseed_debian-stretch.cfg.j2 | 105 | ||||
-rw-r--r-- | roles/vm/network/handlers/main.yml | 3 | ||||
-rw-r--r-- | roles/vm/network/tasks/lan.yml | 6 | ||||
-rw-r--r-- | roles/vm/network/tasks/main.yml | 9 | ||||
-rw-r--r-- | roles/vm/network/tasks/public.yml | 33 | ||||
-rw-r--r-- | roles/vm/network/tasks/systemd-link.yml | 15 | ||||
-rw-r--r-- | roles/vm/network/templates/firewall.sh_public.j2 | 49 | ||||
-rw-r--r-- | roles/vm/network/templates/interfaces_lan.j2 | 17 | ||||
-rw-r--r-- | roles/vm/network/templates/interfaces_public.j2 | 63 | ||||
-rw-r--r-- | roles/vm/network/templates/systemd.link.j2 | 5 |
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 }} |