From 68157859a7f6a0cdc9fc177f42102d42b165dccf Mon Sep 17 00:00:00 2001 From: Kostiantyn Kalynovskyi Date: Thu, 2 Jan 2020 23:53:38 +0000 Subject: [PATCH] Add ansible roles for sushy and libvirt This commit adds simple roles to manage: - libvirt service, domains, volumes, networks and pools. - redfish-emulator role installs sushy-tools from pip, together with support packages Please note, that libvirt roles are not meant to be completely idempotent, their main job is deploy temporary resources that for ci and gating purposes, to be tore down afterwards. Roles are specifically made to be simple to debug, and don't contain any complex logic to make them portable, flexible or idempotent. Change-Id: I2ff0138b5c95bea3445e242a2e5061651498f1ab --- examples/playbooks/libvirt/create-network.yml | 36 ++++ examples/playbooks/libvirt/create-pool.yml | 8 + examples/playbooks/libvirt/create-vm.yml | 32 ++++ examples/playbooks/libvirt/create-volume.yml | 22 +++ examples/playbooks/libvirt/install.yaml | 4 + examples/playbooks/redfish/install-sushy.yaml | 3 + roles/libvirt-domain/defaults/main.yml | 173 ++++++++++++++++++ roles/libvirt-domain/tasks/autodetect.yml | 65 +++++++ .../libvirt-domain/tasks/check-interface.yml | 21 +++ roles/libvirt-domain/tasks/domain.yml | 28 +++ roles/libvirt-domain/tasks/main.yaml | 16 ++ roles/libvirt-domain/templates/domain.xml.j2 | 91 +++++++++ roles/libvirt-domain/tests/main.yml | 39 ++++ roles/libvirt-domain/tests/vars.yml | 44 +++++ roles/libvirt-install/tasks/main.yaml | 38 ++++ roles/libvirt-network/defaults/main.yml | 153 ++++++++++++++++ .../libvirt-network/tasks/add_dhcp_hosts.yml | 32 ++++ roles/libvirt-network/tasks/create.yml | 73 ++++++++ roles/libvirt-network/tasks/main.yaml | 1 + roles/libvirt-network/tasks/rebuild.yml | 17 ++ .../libvirt-network/templates/network.xml.j2 | 110 +++++++++++ roles/libvirt-network/tests/main.yml | 139 ++++++++++++++ roles/libvirt-network/tests/vars.yml | 32 ++++ roles/libvirt-pool/defaults/main.yml | 14 ++ roles/libvirt-pool/tasks/create.yml | 24 +++ roles/libvirt-pool/tasks/main.yml | 1 + roles/libvirt-pool/templates/pool.xml.j2 | 9 + roles/libvirt-pool/tests/main.yml | 22 +++ roles/libvirt-pool/tests/vars.yml | 3 + roles/libvirt-volume/defaults/main.yml | 5 + roles/libvirt-volume/tasks/cleanup.yml | 4 + roles/libvirt-volume/tasks/create.yml | 58 ++++++ roles/libvirt-volume/tasks/main.yml | 1 + roles/libvirt-volume/tests/main.yml | 33 ++++ roles/libvirt-volume/tests/vars.yml | 14 ++ roles/redfish-emulator/defaults/main.yml | 3 + roles/redfish-emulator/handlers/main.yml | 11 ++ roles/redfish-emulator/tasks/install.yml | 37 ++++ roles/redfish-emulator/tasks/main.yml | 1 + .../templates/sushy-tools.service.j2 | 15 ++ roles/redfish-emulator/tests/main.yml | 40 ++++ roles/redfish-emulator/tests/vars.yml | 44 +++++ tests/ansible/{lint.yaml => lint.yml} | 9 +- tests/ansible/role-test-runner.yml | 16 ++ zuul.d/jobs.yaml | 15 +- zuul.d/project.yaml | 2 + 46 files changed, 1551 insertions(+), 7 deletions(-) create mode 100644 examples/playbooks/libvirt/create-network.yml create mode 100644 examples/playbooks/libvirt/create-pool.yml create mode 100644 examples/playbooks/libvirt/create-vm.yml create mode 100644 examples/playbooks/libvirt/create-volume.yml create mode 100644 examples/playbooks/libvirt/install.yaml create mode 100644 examples/playbooks/redfish/install-sushy.yaml create mode 100644 roles/libvirt-domain/defaults/main.yml create mode 100644 roles/libvirt-domain/tasks/autodetect.yml create mode 100644 roles/libvirt-domain/tasks/check-interface.yml create mode 100644 roles/libvirt-domain/tasks/domain.yml create mode 100644 roles/libvirt-domain/tasks/main.yaml create mode 100644 roles/libvirt-domain/templates/domain.xml.j2 create mode 100644 roles/libvirt-domain/tests/main.yml create mode 100644 roles/libvirt-domain/tests/vars.yml create mode 100644 roles/libvirt-install/tasks/main.yaml create mode 100644 roles/libvirt-network/defaults/main.yml create mode 100644 roles/libvirt-network/tasks/add_dhcp_hosts.yml create mode 100644 roles/libvirt-network/tasks/create.yml create mode 100644 roles/libvirt-network/tasks/main.yaml create mode 100644 roles/libvirt-network/tasks/rebuild.yml create mode 100644 roles/libvirt-network/templates/network.xml.j2 create mode 100644 roles/libvirt-network/tests/main.yml create mode 100644 roles/libvirt-network/tests/vars.yml create mode 100644 roles/libvirt-pool/defaults/main.yml create mode 100644 roles/libvirt-pool/tasks/create.yml create mode 100644 roles/libvirt-pool/tasks/main.yml create mode 100644 roles/libvirt-pool/templates/pool.xml.j2 create mode 100644 roles/libvirt-pool/tests/main.yml create mode 100644 roles/libvirt-pool/tests/vars.yml create mode 100644 roles/libvirt-volume/defaults/main.yml create mode 100644 roles/libvirt-volume/tasks/cleanup.yml create mode 100644 roles/libvirt-volume/tasks/create.yml create mode 100644 roles/libvirt-volume/tasks/main.yml create mode 100644 roles/libvirt-volume/tests/main.yml create mode 100644 roles/libvirt-volume/tests/vars.yml create mode 100644 roles/redfish-emulator/defaults/main.yml create mode 100644 roles/redfish-emulator/handlers/main.yml create mode 100644 roles/redfish-emulator/tasks/install.yml create mode 100644 roles/redfish-emulator/tasks/main.yml create mode 100644 roles/redfish-emulator/templates/sushy-tools.service.j2 create mode 100644 roles/redfish-emulator/tests/main.yml create mode 100644 roles/redfish-emulator/tests/vars.yml rename tests/ansible/{lint.yaml => lint.yml} (85%) create mode 100644 tests/ansible/role-test-runner.yml diff --git a/examples/playbooks/libvirt/create-network.yml b/examples/playbooks/libvirt/create-network.yml new file mode 100644 index 0000000..9615a88 --- /dev/null +++ b/examples/playbooks/libvirt/create-network.yml @@ -0,0 +1,36 @@ +- hosts: primary + roles: + - role: libvirt-network + become: true + vars: + network_action: create + libvirt_network: + name: provision-network + spec: + forward: + mode: nat + nat: + port: + - start: 1024 + end: 65535 + bridge: + name: "prov-net-br" + stp: 'on' + delay: '0' + ip: + address: "172.22.0.1" + netmask: "255.255.255.0" + - role: libvirt-network + become: true + vars: + network_action: rebuild + libvirt_network: + name: oob-net + spec: + bridge: + name: oob-net + stp: 'on' + delay: '0' + ip: + address: "10.23.22.1" + netmask: "255.255.255.0" diff --git a/examples/playbooks/libvirt/create-pool.yml b/examples/playbooks/libvirt/create-pool.yml new file mode 100644 index 0000000..6e560a5 --- /dev/null +++ b/examples/playbooks/libvirt/create-pool.yml @@ -0,0 +1,8 @@ +- hosts: primary + roles: + - role: libvirt-pool + become: true + vars: + libvirt_pool: + path: /var/lib/libvirt/airship + name: airship \ No newline at end of file diff --git a/examples/playbooks/libvirt/create-vm.yml b/examples/playbooks/libvirt/create-vm.yml new file mode 100644 index 0000000..6ac7498 --- /dev/null +++ b/examples/playbooks/libvirt/create-vm.yml @@ -0,0 +1,32 @@ +- hosts: primary + roles: + - role: libvirt-domain + become: true + vars: + libvirt_domain: + state: running + name: 'vm1' + memory_mb: 512 + vcpus: 1 + volumes: + - name: 'volume-1' + device: 'disk' + format: 'qcow2' + pool: 'airship' + interfaces: + - network: 'provision-network' + - role: libvirt-domain + become: true + vars: + libvirt_domain: + state: running + name: 'vm2' + memory_mb: 512 + vcpus: 1 + volumes: + - name: 'volume-2' + device: 'disk' + format: 'qcow2' + pool: 'airship' + interfaces: + - network: 'provision-network' diff --git a/examples/playbooks/libvirt/create-volume.yml b/examples/playbooks/libvirt/create-volume.yml new file mode 100644 index 0000000..84eea36 --- /dev/null +++ b/examples/playbooks/libvirt/create-volume.yml @@ -0,0 +1,22 @@ +- hosts: primary + tasks: + - name: Create defined volumes + include_role: + name: libvirt-volume + with_items: + - name: volume-1 + image: https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2 + size: 10G + pool: airship + action: create + - name: volume-2 + image: https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2 + size: 10G + pool: airship + action: create + vars: + libvirt_volume: "{{ vol }}" + volume_action: "{{ vol.action }}" + ansible_become: true + loop_control: + loop_var: vol \ No newline at end of file diff --git a/examples/playbooks/libvirt/install.yaml b/examples/playbooks/libvirt/install.yaml new file mode 100644 index 0000000..7d72189 --- /dev/null +++ b/examples/playbooks/libvirt/install.yaml @@ -0,0 +1,4 @@ +--- +- hosts: primary + roles: + - role: libvirt-install diff --git a/examples/playbooks/redfish/install-sushy.yaml b/examples/playbooks/redfish/install-sushy.yaml new file mode 100644 index 0000000..591c030 --- /dev/null +++ b/examples/playbooks/redfish/install-sushy.yaml @@ -0,0 +1,3 @@ +- hosts: primary + roles: + - role: redfish-emulator \ No newline at end of file diff --git a/roles/libvirt-domain/defaults/main.yml b/roles/libvirt-domain/defaults/main.yml new file mode 100644 index 0000000..8141f1e --- /dev/null +++ b/roles/libvirt-domain/defaults/main.yml @@ -0,0 +1,173 @@ +--- + +# The default directory in which to store VM console logs, if a VM-specific log +# file path is not given. +libvirt_vm_default_console_log_dir: "/var/log/libvirt-consoles/" + +# The default location for libvirt images +libvirt_volume_default_images_path: '/var/lib/libvirt/images' + +# Default type for Libvirt volumes +libvirt_volume_default_type: volume + +# The default format for Libvirt volumes. +libvirt_volume_default_format: qcow2 + +# The default device for Libvirt volumes. +libvirt_volume_default_device: disk + +# CPU architecture. +libvirt_vm_arch: x86_64 + +# Virtualisation engine. If not set, the role will attempt to auto-detect the +# optimal engine to use. +libvirt_vm_engine: + +# Path to emulator binary. If not set, the role will attempt to auto-detect the +# correct emulator to use. +libvirt_vm_emulator: + +# Default value for clock syncing. The default (false) uses +# to configure the instances clock synchronisation. Change to a timezone to make +# configuration use +libvirt_vm_clock_offset: False + +# A list of specifications of VMs to be created. +# For backwards compatibility, libvirt_vms defaults to a singleton list using +# the values of the deprecated variables below. +# See README.md or tasks/main.yml for these attributes' defaults. +libvirt_domain: + # State of the VM. May be 'present' or 'absent'. + state: "{{ libvirt_vm_state }}" + + # Name of the VM. + name: "{{ libvirt_vm_name }}" + + # Memory in MB. + memory_mb: "{{ libvirt_vm_memory_mb }}" + + # Number of vCPUs. + vcpus: "{{ libvirt_vm_vcpus }}" + + # Virtual machine type. + machine: "{{ libvirt_vm_machine }}" + + # Virtual machine CPU mode. + cpu_mode: "{{ libvirt_vm_cpu_mode | default(libvirt_cpu_mode_default, true) }}" + + # List of volumes. + volumes: "{{ libvirt_vm_volumes }}" + + # What time should the clock be synced to on boot (utc/localtime/timezone/variable) + clock_offset: "localtime" + + # List of network interfaces. + interfaces: "{{ libvirt_vm_interfaces }}" + + # Path to console log file. + console_log_path: "{{ libvirt_vm_console_log_path }}" + + # XML template file to source domain definition + xml_file: vm.xml.j2 + +# Variables to add to the enviroment that is used to execute virsh commands +libvirt_vm_virsh_default_env: "{{ { 'LIBVIRT_DEFAULT_URI': libvirt_vm_uri } if libvirt_vm_uri else {} }}" + +# Override for the libvirt connection uri. Leave unset to use the default. +libvirt_vm_uri: "" + +# Default CPU mode if libvirt_vm_cpu_mode or vm.cpu_mode is undefined +libvirt_cpu_mode_default: "{{ 'host-passthrough' if libvirt_vm_engine == 'kvm' else 'host-model' }}" + +libvirt_domain_template_default: | + + {{ libvirt_domain.name }} + {{ libvirt_domain.memory_mb | int * 1024 }} + {{ libvirt_domain.vcpus }} + {% if libvirt_domain.clock_offset |default( libvirt_vm_clock_offset ) %} + + {% else %} + + {% endif %} + destroy + restart + destroy + + hvm + + + + + + + + + + + + {% if cpu_mode %} + + + + {% endif %} + + {{ libvirt_vm_emulator }} + {% for volume in volumes %} + + + {% if volume.type | default(libvirt_volume_default_type) == 'file' %} + + {% else %} + + {% endif %} + {% if volume.target is undefined %} + + {% else %} + + {% endif %} + + {% endfor %} + {% for interface in interfaces %} + {% if interface.type is defined and interface.type == 'direct' %} + + + {% elif interface.type is defined and interface.type == 'bridge' %} + + + {% elif interface.type is not defined or interface.type == 'network' %} + + + {% endif %} + {% if interface.mac is defined %} + + {% endif %} + {# if the network configuration is invalid this can still appear in the xml #} + {# (say you enter 'bond' instead of 'bridge' in your variables) #} + + + {% endfor %} + {% if console_log_enabled | bool %} + + + + + + + + + {% else %} + + + + + + + {% endif %} + {% if enable_vnc |bool %} + + + + {% endif %} + /dev/urandom + + diff --git a/roles/libvirt-domain/tasks/autodetect.yml b/roles/libvirt-domain/tasks/autodetect.yml new file mode 100644 index 0000000..e7cc39e --- /dev/null +++ b/roles/libvirt-domain/tasks/autodetect.yml @@ -0,0 +1,65 @@ +--- +- name: Detect the virtualisation engine + block: + - name: Load the kvm kernel module + modprobe: + name: kvm + become: true + failed_when: false + + - name: Check for the KVM device + stat: + path: /dev/kvm + register: stat_kvm + + - name: Set a fact containing the virtualisation engine + set_fact: + libvirt_vm_engine: >- + {%- if ansible_architecture != libvirt_vm_arch -%} + {# Virtualisation instructions are generally available only for the host + architecture. Ideally we would test for virtualisation instructions, eg. vt-d + as it is possible that another architecture could support these even + if the emulated cpu architecture is not the same. #} + qemu + {%- elif stat_kvm.stat.exists -%} + kvm + {%- else -%} + qemu + {%- endif -%} + when: libvirt_vm_engine is none or libvirt_vm_engine | length == 0 + +- name: Detect the virtualisation emulator + block: + - block: + - name: Detect the KVM emulator binary path + stat: + path: "{{ item }}" + register: kvm_emulator_result + with_items: + - /usr/bin/kvm + - /usr/bin/qemu-kvm + - /usr/libexec/qemu-kvm + + - name: Set a fact containing the KVM emulator binary path + set_fact: + libvirt_vm_emulator: "{{ item.item }}" + with_items: "{{ kvm_emulator_result.results }}" + when: item.stat.exists + when: libvirt_vm_engine == 'kvm' + + - block: + - name: Detect the QEMU emulator binary path + shell: which qemu-system-{{ libvirt_vm_arch }} + register: qemu_emulator_result + changed_when: false + + - name: Set a fact containing the QEMU emulator binary path + set_fact: + libvirt_vm_emulator: "{{ qemu_emulator_result.stdout }}" + when: libvirt_vm_engine == 'qemu' + + - name: Fail if unable to detect the emulator + fail: + msg: Unable to detect emulator for engine {{ libvirt_vm_engine }}. + when: libvirt_vm_emulator is none + when: libvirt_vm_emulator is none or libvirt_vm_emulator | length == 0 \ No newline at end of file diff --git a/roles/libvirt-domain/tasks/check-interface.yml b/roles/libvirt-domain/tasks/check-interface.yml new file mode 100644 index 0000000..cdf009a --- /dev/null +++ b/roles/libvirt-domain/tasks/check-interface.yml @@ -0,0 +1,21 @@ +--- +- name: Check network interface has a network name + fail: + msg: > + The interface definition {{ interface }} has type 'network', but does not have + a network name defined. + when: + - interface.type is not defined or + interface.type == 'network' + - interface.network is not defined + +- name: Check direct interface has an interface device name + fail: + msg: > + The interface definition {{ interface }} has type 'direct', but does not have + a host source device defined. + when: + - interface.type is defined + - interface.type == 'direct' + - interface.source is not defined or + interface.source.dev is not defined \ No newline at end of file diff --git a/roles/libvirt-domain/tasks/domain.yml b/roles/libvirt-domain/tasks/domain.yml new file mode 100644 index 0000000..4945a09 --- /dev/null +++ b/roles/libvirt-domain/tasks/domain.yml @@ -0,0 +1,28 @@ +--- +- name: Ensure the VM console log directory exists + file: + path: "{{ libvirt_domain.console_log_path | dirname }}" + state: directory + owner: "{{ libvirt_domain.libvirt_vm_log_owner }}" + group: "{{ libvirt_domain.libvirt_vm_log_owner }}" + recurse: true + mode: 0770 + when: "libvirt_domain.console_log_enabled | default('false') | bool" + +- name: Validate VM interfaces + include_tasks: check-interface.yml + vars: + interface: "{{ item }}" + with_items: "{{ libvirt_domain.interfaces }}" + +- name: Ensure the VM is defined + virt: + name: "{{ libvirt_domain.name }}" + command: define + xml: "{{ libvirt_domain.xml | default(libvirt_domain_template_default) }}" + +- name: Ensure the VM is started at boot + virt: + name: "{{ libvirt_domain.name }}" + autostart: "{{ libvirt_domain.autostart | default(false) }}" + state: "{{ libvirt_domain.state | default('running') }}" diff --git a/roles/libvirt-domain/tasks/main.yaml b/roles/libvirt-domain/tasks/main.yaml new file mode 100644 index 0000000..96bc4c6 --- /dev/null +++ b/roles/libvirt-domain/tasks/main.yaml @@ -0,0 +1,16 @@ +- include_tasks: autodetect.yml + +- include_tasks: domain.yml + vars: + console_log_enabled: "{{ libvirt_domain.console_log_enabled | default(false) }}" + console_log_path: >- + {{ libvirt_domain.console_log_path | + default(libvirt_vm_default_console_log_dir + '/' + libvirt_domain.name + '-console.log', true) }} + machine_default: "{{ none if libvirt_vm_engine == 'kvm' else 'pc-1.0' }}" + machine: "{{ libvirt_domain.machine | default(machine_default, true) }}" + cpu_mode: "{{ libvirt_domain.cpu_mode | default(libvirt_cpu_mode_default) }}" + volumes: "{{ libvirt_domain.volumes | default([], true) }}" + interfaces: "{{ libvirt_domain.interfaces | default([], true) }}" + start: "{{ libvirt_domain.start | default(true) }}" + autostart: "{{ libvirt_domain.autostart | default(true) }}" + enable_vnc: "{{ libvirt_domain.enable_vnc | default(false) }}" diff --git a/roles/libvirt-domain/templates/domain.xml.j2 b/roles/libvirt-domain/templates/domain.xml.j2 new file mode 100644 index 0000000..0dca8cf --- /dev/null +++ b/roles/libvirt-domain/templates/domain.xml.j2 @@ -0,0 +1,91 @@ + + {{ libvirt_domain.name }} + {{ libvirt_domain.memory_mb | int * 1024 }} + {{ libvirt_domain.vcpus }} + {% if libvirt_domain.clock_offset |default( libvirt_vm_clock_offset ) %} + + {% else %} + + {% endif %} + destroy + restart + destroy + + hvm + + + + + + + + + + + + {% if cpu_mode %} + + + + {% endif %} + + {{ libvirt_vm_emulator }} +{% for volume in volumes %} + + + {% if volume.type | default(libvirt_volume_default_type) == 'file' %} + + {% else %} + + {% endif %} + {% if volume.target is undefined %} + + {% else %} + + {% endif %} + +{% endfor %} +{% for interface in interfaces %} +{% if interface.type is defined and interface.type == 'direct' %} + + +{% elif interface.type is defined and interface.type == 'bridge' %} + + +{% elif interface.type is not defined or interface.type == 'network' %} + + +{% endif %} + {% if interface.mac is defined %} + + {% endif %} + {# if the network configuration is invalid this can still appear in the xml #} + {# (say you enter 'bond' instead of 'bridge' in your variables) #} + + +{% endfor %} +{% if console_log_enabled | bool %} + + + + + + + + +{% else %} + + + + + + +{% endif %} +{% if enable_vnc |bool %} + + + +{% endif %} + /dev/urandom + + diff --git a/roles/libvirt-domain/tests/main.yml b/roles/libvirt-domain/tests/main.yml new file mode 100644 index 0000000..c0cb9d7 --- /dev/null +++ b/roles/libvirt-domain/tests/main.yml @@ -0,0 +1,39 @@ +- name: Include test variables. + include_vars: + file: vars.yml +- name: install libvirt + include_role: + name: libvirt-install +- name: create pool + include_role: + name: libvirt-pool + vars: + ansible_become: true +- name: Create defined volumes + include_role: + name: libvirt-volume + with_items: "{{ libvirt_volumes }}" + vars: + libvirt_volume: "{{ vol }}" + volume_action: "{{ vol.action }}" + ansible_become: true + loop_control: + loop_var: vol +- name: create libvirt domains + include_role: + name: libvirt-domain + vars: + ansible_become: true +- name: save information about domain + virt: + command: info + name: "{{ libvirt_domain.name }}" + register: domain_info + become: true +- name: debug domain-info + debug: + var: domain_info +- name: make sure that vm is in correct state + assert: + that: + - domain_info[libvirt_domain.name].state == libvirt_domain.state diff --git a/roles/libvirt-domain/tests/vars.yml b/roles/libvirt-domain/tests/vars.yml new file mode 100644 index 0000000..11b9852 --- /dev/null +++ b/roles/libvirt-domain/tests/vars.yml @@ -0,0 +1,44 @@ +libvirt_pool: + path: /var/lib/libvirt/airship + name: airship + +libvirt_volumes: + - name: volume-1 + image: https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2 + size: 10G + pool: "{{ libvirt_pool.name }}" + action: create + - name: volume-2 + size: 10G + pool: "{{ libvirt_pool.name }}" + action: create + +libvirt_domain: + state: running + name: 'vm1' + memory_mb: 2048 + vcpus: 1 + volumes: + - name: 'volume-1' + device: 'disk' + format: 'qcow2' + pool: 'airship' + interfaces: + - network: 'provision-network' + +libvirt_network: + name: provision-network + spec: + forward: + mode: nat + nat: + port: + - start: 1024 + end: 65535 + bridge: + name: "prov-net-br" + stp: 'on' + delay: '0' + ip: + address: "172.22.0.1" + netmask: "255.255.255.0" \ No newline at end of file diff --git a/roles/libvirt-install/tasks/main.yaml b/roles/libvirt-install/tasks/main.yaml new file mode 100644 index 0000000..67c09e9 --- /dev/null +++ b/roles/libvirt-install/tasks/main.yaml @@ -0,0 +1,38 @@ +--- +- block: + - name: Ensuring Libvirt, Qemu and support packages are present + become: true + when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux' + yum: + name: + - libguestfs-tools + - libvirt + - libvirt-devel + - libvirt-daemon-kvm + - qemu-kvm + - virt-install + state: present + - name: Ensuring Libvirt, Qemu and support packages are present + become: true + when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu' + apt: + name: + - qemu + - libvirt-bin + - libguestfs-tools + - qemu-kvm + - virtinst + - python-lxml + - python3-lxml + - python3-libvirt + - python-libvirt + - dnsmasq + - ebtables + state: present + - name: Start libvirtd + service: + name: libvirtd + state: started + enabled: true + become: true + diff --git a/roles/libvirt-network/defaults/main.yml b/roles/libvirt-network/defaults/main.yml new file mode 100644 index 0000000..31c73d0 --- /dev/null +++ b/roles/libvirt-network/defaults/main.yml @@ -0,0 +1,153 @@ +# libvirt_network: +# name: provision-network +# spec: +# forward: +# mode: nat +# nat: +# port: +# - start: 1024 +# end: 65535 +# bridge: +# name: "prov-net-br" +# stp: 'on' +# delay: '0' +# ip: +# address: "172.22.0.1" +# netmask: "255.255.255.0" +# libvirt_network: +# name: "{{ bm_net_name }}" +# persistent: true +# autostart: true +# spec: +# forward: +# mode: nat +# nat: +# port: +# - start: 1024 +# end: 65535 +# bridge: +# name: "{{ bm_net_name }}" +# stp: 'on' +# delay: '0' +# domain: +# name: 'tests.baremetal.net' +# localOnly: 'yes' +# dns: +# - forwarder: +# domain: 'apps.tests.baremetal.net' +# addr: '127.0.0.1' +# - forwarder: +# domain: 'services.tests.baremetal.net' +# addr: '127.0.0.1' +# ip: "{{ bm_net_0_ip_cfg }}" + +libvirt_network_template_default: | + + {{ net_yaml.name }} + {% if net_yaml.forward is defined %} + {% if net_yaml.forward.mode is defined %} + + {% else %} + + {% endif %} + + {% if net_yaml.forward.nat is defined %} + + {% if net_yaml.forward.nat.port is defined %} + {% for port in net_yaml.forward.nat.port %} + + {% endfor %} + {% endif %} + + {% endif %} + + {% endif %} + {% if net_yaml.bridge is defined %} + + {% endif %} + {% if net_yaml.mac is defined %} + + {% endif %} + {% if net_yaml.domain is defined %} + + {% endif %} + {% if net_yaml.dns is defined %} + + {% if net_yaml.dns | list %} + {% for dns_item in net_yaml.dns %} + {% if dns_item.forwarder is defined %} + + {% endif %} + {% endfor %} + {% endif %} + + {% endif %} + {% if net_yaml.ip is defined %} + + {% if net_yaml.ip.dhcp is defined %} + + {% for dhcp_item in net_yaml.ip.dhcp %} + {% if dhcp_item.range is defined %} + + {% endif %} + {% if dhcp_item.host is defined %} + + {% endif %} + {% endfor %} + + {% endif %} + + {% endif %} + diff --git a/roles/libvirt-network/tasks/add_dhcp_hosts.yml b/roles/libvirt-network/tasks/add_dhcp_hosts.yml new file mode 100644 index 0000000..2acacd0 --- /dev/null +++ b/roles/libvirt-network/tasks/add_dhcp_hosts.yml @@ -0,0 +1,32 @@ +# Description: +# Add given hosts to existing libvirt network +# +# Inputs: +# network_action: "add_dhcp_hosts" +# network_args: +# name: +# hosts: +# - name: +# mac: +# ip: +# - name: +# mac: +# ip: + +- name: Validate input + assert: + that: + - "network_args is defined" + - "network_args.name is defined" + - "network_args.hosts is defined" + - "network_args.hosts | list" + +- name: add dhcp hosts to network + shell: >- + virsh net-update {{ network_args.name }} \ + add --section ip-dhcp-host \ + --xml "" \ + --config --live + loop: "{{ network_args.hosts }}" + loop_control: + loop_var: single_dhcp_host diff --git a/roles/libvirt-network/tasks/create.yml b/roles/libvirt-network/tasks/create.yml new file mode 100644 index 0000000..ea24f87 --- /dev/null +++ b/roles/libvirt-network/tasks/create.yml @@ -0,0 +1,73 @@ +# Description: +# Creates a libvirt network. libvirt_network are +# exactly converted to XML from YAML so there +# is no validation whether the arguments are +# correct or not. Caller must ensure that yaml +# is formulated correctly. +# +# Inputs: +# network_action: "create" +# libvirt_network: +# name: +# persistent: +# autostart: +# recreate: +# spec: +# forward: +# mode: +# nat: +# port: +# - start: +# end: +# bridge: +# name: +# stp: +# delay: +# domain: +# name: +# localOnly: +# dns: +# forwarder: +# domain: +# addr: +# mac: +# address: +# ip: +# address: +# netmask: +# dhcp: +# - range: +# start: +# end: + +- name: Validate input + assert: + that: + - "libvirt_network is defined" + - "libvirt_network.name is defined" + - "libvirt_network.spec is defined" + +- name: Create yaml for template + set_fact: + net_yaml: >- + {{ + libvirt_network.spec + | combine({'name': libvirt_network.name}, recursive=True) + }} + +- name: "Define network" + virt_net: + command: define +# If libvirt_network.xml is defined, spec will be ignored. + xml: "{{ libvirt_network.xml | default(libvirt_network_template_default) }}" + name: "{{ libvirt_network.name }}" + +- name: "Start network" + virt_net: + state: active + name: "{{ libvirt_network.name }}" + +- name: "Autostart network" + virt_net: + name: "{{ libvirt_network.name }}" + autostart: "{{ libvirt_network.autostart |default(true) }}" diff --git a/roles/libvirt-network/tasks/main.yaml b/roles/libvirt-network/tasks/main.yaml new file mode 100644 index 0000000..175f17d --- /dev/null +++ b/roles/libvirt-network/tasks/main.yaml @@ -0,0 +1 @@ +- include_tasks: "{{ network_action }}.yml" diff --git a/roles/libvirt-network/tasks/rebuild.yml b/roles/libvirt-network/tasks/rebuild.yml new file mode 100644 index 0000000..ab08c5d --- /dev/null +++ b/roles/libvirt-network/tasks/rebuild.yml @@ -0,0 +1,17 @@ +- name: "Remove network" + virt_net: + state: absent + name: "{{ libvirt_network.name }}" + +- name: Create yaml for template + set_fact: + net_yaml: >- + {{ + libvirt_network.spec + | combine({'name': libvirt_network.name}, recursive=True) + }} + +- name: "create network" + include_tasks: "{{ network_action }}.yml" + vars: + network_action: create diff --git a/roles/libvirt-network/templates/network.xml.j2 b/roles/libvirt-network/templates/network.xml.j2 new file mode 100644 index 0000000..00e78db --- /dev/null +++ b/roles/libvirt-network/templates/network.xml.j2 @@ -0,0 +1,110 @@ + + {{ net_yaml.name }} + {% if net_yaml.forward is defined %} + {% if net_yaml.forward.mode is defined %} + + {% else %} + + {% endif %} + + {% if net_yaml.forward.nat is defined %} + + {% if net_yaml.forward.nat.port is defined %} + {% for port in net_yaml.forward.nat.port %} + + {% endfor %} + {% endif %} + + {% endif %} + + {% endif %} + {% if net_yaml.bridge is defined %} + + {% endif %} + {% if net_yaml.mac is defined %} + + {% endif %} + {% if net_yaml.domain is defined %} + + {% endif %} + {% if net_yaml.dns is defined %} + + {% if net_yaml.dns | list %} + {% for dns_item in net_yaml.dns %} + {% if dns_item.forwarder is defined %} + + {% endif %} + {% endfor %} + {% endif %} + + {% endif %} + {% if net_yaml.ip is defined %} + + {% if net_yaml.ip.dhcp is defined %} + + {% for dhcp_item in net_yaml.ip.dhcp %} + {% if dhcp_item.range is defined %} + + {% endif %} + {% if dhcp_item.host is defined %} + + {% endif %} + {% endfor %} + + {% endif %} + + {% endif %} + + diff --git a/roles/libvirt-network/tests/main.yml b/roles/libvirt-network/tests/main.yml new file mode 100644 index 0000000..1e977a6 --- /dev/null +++ b/roles/libvirt-network/tests/main.yml @@ -0,0 +1,139 @@ +- name: Include test variables. + include_vars: + file: vars.yml +- name: install libvirt + include_role: + name: libvirt-install +- name: create networks + include_role: + name: libvirt-network + with_items: "{{ libvirt_networks }}" + loop_control: + loop_var: libvirt_network + vars: + ansible_become: true + network_action: "{{ libvirt_network.network_action }}" +- name: install required packages + apt: + name: + - bridge-utils + state: present + become: true +- name: gather network info + virt_net: + command: info + register: libvirt_networks_info + become: true + +- name: debug network list + debug: + var: libvirt_networks_info + +- name: check if network is present + assert: + that: + - "'oob-net' in libvirt_networks_info.networks" + - "'provision-network' in libvirt_networks_info.networks" + +## this is needed because dashes '-', are not proccessed in expected way to ansible +- name: Assign networks to separate variables + set_fact: + oob_net: "{{ libvirt_networks_info.networks['oob-net'] }}" + provision_network: "{{ libvirt_networks_info.networks['provision-network'] }}" + +- name: Verify oob network is in correct state + assert: + that: + - "oob_net.autostart == 'no'" + - "oob_net.bridge == 'oob-net'" + - "oob_net.state == 'active'" + +- name: register ip address of the oob-net interface + command: ip -4 a show dev oob-net + register: oob_net_device + changed_when: false + +- name: debug oob-net interface + debug: + var: oob_net_device.stdout + +- name: verify oob-net bridge has correct address + assert: + that: "'10.23.22.1/24' in oob_net_device.stdout" + +- name: Verify provision-network is in correct state + assert: + that: + - "provision_network.autostart == 'yes'" + - "provision_network.bridge == 'prov-net-br'" + - "provision_network.state == 'active'" + - "provision_network.forward_mode == 'nat'" + +- name: register ip address of the oob-net interface + command: ip -4 a show dev prov-net-br + register: prov_net_br_device + changed_when: false + +- name: debug prov-net-br interface + debug: + var: prov_net_br_device.stdout + +- name: verify provision-network bridge has correct address + assert: + that: "'172.22.0.1/24' in prov_net_br_device.stdout" + +- name: Create virtual ethernet interface + command: ip link add name air02 type veth peer name air01 + become: true + changed_when: + - "create_veth_command.rc != 2" + - "'RTNETLINK answers: File exists' not in (create_veth_command.stderr | default(''))" + register: create_veth_command + failed_when: + - "create_veth_command.rc != 0" + - "'RTNETLINK answers: File exists' not in (create_veth_command.stderr | default(''))" +- name: set interface up + become: true + command: ip link set up dev air02 + # This makes task never report to be changed, it is a workaround + # because if device is already up there is no command output or different RC + changed_when: false + +- name: set interface up + become: true + command: ip link set up dev air01 + # This makes task never report to be changed, it is a workaround + # because if device is already up there is no command output or different RC + changed_when: false + +- name: set interface already in bridge variable + set_fact: + already_in_bridge: device air02 is already a member of a bridge; can't enslave it to bridge oob-net. + +- name: Add interface to libvirt managed linux bridge with dhcp + become: true + command: brctl addif oob-net air02 + changed_when: + - add_if_command.rc != 1 + - already_in_bridge not in (dd_if_command.stderr | default('')) + failed_when: + - add_if_command.rc != 0 + - already_in_bridge not in add_if_command.stderr | default('') + register: add_if_command + +- name: send dhcp request over the interface + become: true + command: timeout 20s dhclient air01 + changed_when: false + +- name: register ip address of the air01 interface + command: ip -4 a show dev air01 + register: air01_device + changed_when: false + +## this simple test checks if ip address is present in interface description +## TODO filter out the address, derive subnet and compare to expected subnet +- name: verify air02 interface has address in correct network + assert: + that: + - "'10.23.22.' in air01_device.stdout" diff --git a/roles/libvirt-network/tests/vars.yml b/roles/libvirt-network/tests/vars.yml new file mode 100644 index 0000000..4365646 --- /dev/null +++ b/roles/libvirt-network/tests/vars.yml @@ -0,0 +1,32 @@ +libvirt_networks: + - network_action: create + autostart: false + name: oob-net + spec: + bridge: + name: oob-net + stp: 'on' + delay: '0' + ip: + address: "10.23.22.1" + netmask: "255.255.255.0" + dhcp: + - range: + start: 10.23.22.100 + end: 10.23.22.199 + - network_action: create + name: provision-network + spec: + forward: + mode: nat + nat: + port: + - start: 1024 + end: 65535 + bridge: + name: "prov-net-br" + stp: 'on' + delay: '0' + ip: + address: "172.22.0.1" + netmask: "255.255.255.0" \ No newline at end of file diff --git a/roles/libvirt-pool/defaults/main.yml b/roles/libvirt-pool/defaults/main.yml new file mode 100644 index 0000000..0905699 --- /dev/null +++ b/roles/libvirt-pool/defaults/main.yml @@ -0,0 +1,14 @@ +libvirt_pool: + name: airship + path: "/var/lib/airship" +pool_action: create +libvirt_pool_template_default: | + + {{ libvirt_pool.name }} + {% if 'capacity' in libvirt_pool %} + {{ libvirt_pool.capacity }} + {% endif %} + + {{ libvirt_pool.path | default('placeholder_value') }} + + \ No newline at end of file diff --git a/roles/libvirt-pool/tasks/create.yml b/roles/libvirt-pool/tasks/create.yml new file mode 100644 index 0000000..366ce58 --- /dev/null +++ b/roles/libvirt-pool/tasks/create.yml @@ -0,0 +1,24 @@ +--- +- name: Ensure libvirt dir storage pool directories exist + file: + path: "{{ libvirt_pool.path }}" + owner: "{{ libvirt_pool.owner | default(omit) }}" + group: "{{ libvirt_pool.group | default(omit) }}" + mode: "{{ libvirt_pool.mode | default(omit) }}" + state: directory + +- name: Ensure libvirt storage pools are defined + virt_pool: + name: "{{ libvirt_pool.name }}" + command: define + xml: "{{ libvirt_pool.xml | default(libvirt_pool_template_default) }}" + +- name: Ensure libvirt storage pools are active + virt_pool: + name: "{{ libvirt_pool.name }}" + state: active + +- name: Ensure libvirt storage pools are started on boot + virt_pool: + name: "{{ libvirt_pool.name }}" + autostart: yes diff --git a/roles/libvirt-pool/tasks/main.yml b/roles/libvirt-pool/tasks/main.yml new file mode 100644 index 0000000..c073e40 --- /dev/null +++ b/roles/libvirt-pool/tasks/main.yml @@ -0,0 +1 @@ +- include_tasks: "{{ pool_action }}.yml" diff --git a/roles/libvirt-pool/templates/pool.xml.j2 b/roles/libvirt-pool/templates/pool.xml.j2 new file mode 100644 index 0000000..36a1983 --- /dev/null +++ b/roles/libvirt-pool/templates/pool.xml.j2 @@ -0,0 +1,9 @@ + + {{ libvirt_pool.name }} + {% if 'capacity' in libvirt_pool %} + {{ libvirt_pool.capacity }} + {% endif %} + + {{ libvirt_pool.path | default('placeholder_value') }} + + \ No newline at end of file diff --git a/roles/libvirt-pool/tests/main.yml b/roles/libvirt-pool/tests/main.yml new file mode 100644 index 0000000..8542b22 --- /dev/null +++ b/roles/libvirt-pool/tests/main.yml @@ -0,0 +1,22 @@ +- name: Include test variables. + include_vars: + file: vars.yml +- name: install libvirt + include_role: + name: libvirt-install +- name: create pool + include_role: + name: libvirt-pool + vars: + ansible_become: true +- name: get pool information + virt_pool: + command: info + become: true + register: storage_pools + +- name: check if pool is available and is at given directory + assert: + that: + - "storage_pools.pools.test_pool.path == '/var/lib/libvirt/my-pool'" + - "storage_pools.pools.test_pool.status == 'running'" diff --git a/roles/libvirt-pool/tests/vars.yml b/roles/libvirt-pool/tests/vars.yml new file mode 100644 index 0000000..8ca7450 --- /dev/null +++ b/roles/libvirt-pool/tests/vars.yml @@ -0,0 +1,3 @@ +libvirt_pool: + path: /var/lib/libvirt/my-pool + name: test_pool \ No newline at end of file diff --git a/roles/libvirt-volume/defaults/main.yml b/roles/libvirt-volume/defaults/main.yml new file mode 100644 index 0000000..ed9089c --- /dev/null +++ b/roles/libvirt-volume/defaults/main.yml @@ -0,0 +1,5 @@ +libvirt_remote_scheme_list: + - http + - https +libvirt_image_cleanup_cache: false +libvirt_image_cache_path: /tmp/airship \ No newline at end of file diff --git a/roles/libvirt-volume/tasks/cleanup.yml b/roles/libvirt-volume/tasks/cleanup.yml new file mode 100644 index 0000000..82a769e --- /dev/null +++ b/roles/libvirt-volume/tasks/cleanup.yml @@ -0,0 +1,4 @@ +- name: Clean up cache directory + file: + path: "{{ libvirt_image_cache_path }}" + state: absent diff --git a/roles/libvirt-volume/tasks/create.yml b/roles/libvirt-volume/tasks/create.yml new file mode 100644 index 0000000..17a96d4 --- /dev/null +++ b/roles/libvirt-volume/tasks/create.yml @@ -0,0 +1,58 @@ +- name: Get Scheme + set_fact: + image_scheme: "{{ libvirt_volume.image | urlsplit('scheme') }}" + when: "libvirt_volume.image is defined" + + +- name: Get Scheme + set_fact: + image_dest: "{{ libvirt_image_cache_path }}/{{ libvirt_volume.image | basename }}" + when: "libvirt_volume.image is defined" + + +- name: Ensure cache directories exist + file: + path: "{{ libvirt_image_cache_path }}" + state: directory + +- name: Ensure remote images are downloaded + get_url: + url: "{{ libvirt_volume.image }}" + dest: "{{ image_dest }}" + checksum: "{{ libvirt_volume.checksum | default(omit) }}" + when: "image_scheme in libvirt_remote_scheme_list and libvirt_volume.image is defined" + +- name: Ensure local images are copied + copy: + src: "{{ libvirt_volume.image }}" + dest: "{{ image_dest }}" + when: "image_scheme not in libvirt_remote_scheme_list and libvirt_volume.image is defined" + +- name: "Create volume" + command: >- + virsh vol-create-as "{{ libvirt_volume.pool }}" \ + --name "{{ libvirt_volume.name }}" \ + --capacity "{{ libvirt_volume.size }}" \ + --format "{{ libvirt_volume.format | default('qcow2') }}" + register: libvirt_create_volume + failed_when: + - "libvirt_create_volume.rc != 0" + - "'Failed to create vol' in libvirt_create_volume.stdout" + - "'exists already' not in libvirt_create_volume.stdout" + changed_when: + - "libvirt_create_volume.rc != 1" + - "'exists already' not in libvirt_create_volume.stdout" + +- name: "Upload volume from downloaded image" + command: >- + virsh vol-upload --pool "{{ libvirt_volume.pool }}" --vol "{{ libvirt_volume.name }}" --file "{{ image_dest }}" + when: + - "libvirt_volume.image is defined" + - "libvirt_create_volume.rc == 0" + +- name: "Resize volume after uploading from image" + command: >- + virsh vol-resize --vol "{{ libvirt_volume.name }}" --pool "{{ libvirt_volume.pool }}" --capacity "{{ libvirt_volume.size }}" + when: + - "libvirt_create_volume.rc == 0" + - "libvirt_volume.image is defined" diff --git a/roles/libvirt-volume/tasks/main.yml b/roles/libvirt-volume/tasks/main.yml new file mode 100644 index 0000000..80cfb44 --- /dev/null +++ b/roles/libvirt-volume/tasks/main.yml @@ -0,0 +1 @@ +- include_tasks: "{{ volume_action }}.yml" diff --git a/roles/libvirt-volume/tests/main.yml b/roles/libvirt-volume/tests/main.yml new file mode 100644 index 0000000..467b499 --- /dev/null +++ b/roles/libvirt-volume/tests/main.yml @@ -0,0 +1,33 @@ +- name: Include test variables. + include_vars: + file: vars.yml +- name: install libvirt + include_role: + name: libvirt-install +- name: create pool + include_role: + name: libvirt-pool + vars: + ansible_become: true +- name: Create defined volumes + include_role: + name: libvirt-volume + with_items: "{{ libvirt_volumes }}" + vars: + libvirt_volume: "{{ vol }}" + volume_action: "{{ vol.action }}" + ansible_become: true + loop_control: + loop_var: vol +- name: save volume list + command: virsh vol-list --pool {{ libvirt_pool.name }} + register: libvirt_pool_list + changed_when: false + become: true +- name: verify volumes exist + assert: + that: + - "vol.name in libvirt_pool_list.stdout" + with_items: "{{ libvirt_volumes }}" + loop_control: + loop_var: vol \ No newline at end of file diff --git a/roles/libvirt-volume/tests/vars.yml b/roles/libvirt-volume/tests/vars.yml new file mode 100644 index 0000000..2024f0f --- /dev/null +++ b/roles/libvirt-volume/tests/vars.yml @@ -0,0 +1,14 @@ +libvirt_pool: + path: /var/lib/libvirt/airship + name: airship + +libvirt_volumes: + - name: volume-1 + image: https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2 + size: 10G + pool: "{{ libvirt_pool.name }}" + action: create + - name: volume-2 + size: 10G + pool: "{{ libvirt_pool.name }}" + action: create \ No newline at end of file diff --git a/roles/redfish-emulator/defaults/main.yml b/roles/redfish-emulator/defaults/main.yml new file mode 100644 index 0000000..93d0cba --- /dev/null +++ b/roles/redfish-emulator/defaults/main.yml @@ -0,0 +1,3 @@ +redfish_action: install +redfish_emulator_bind_ip: 127.0.0.1 +redfish_emulator_bind_port: 8000 \ No newline at end of file diff --git a/roles/redfish-emulator/handlers/main.yml b/roles/redfish-emulator/handlers/main.yml new file mode 100644 index 0000000..3c2f75f --- /dev/null +++ b/roles/redfish-emulator/handlers/main.yml @@ -0,0 +1,11 @@ +- name: reload systemd configuration + become: yes + systemd: + daemon_reload: yes + +- name: restart sushy-emulator + become: yes + service: + name: sushy-tools + state: restarted + enabled: true \ No newline at end of file diff --git a/roles/redfish-emulator/tasks/install.yml b/roles/redfish-emulator/tasks/install.yml new file mode 100644 index 0000000..f7e6582 --- /dev/null +++ b/roles/redfish-emulator/tasks/install.yml @@ -0,0 +1,37 @@ +- block: + - name: Ensuring python3-pip and support packages are present + when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux' + fail: + msg: "CentoOS or RHEL is not currently supported" + + - name: Ensuring python3-pip and support packages are present + become: true + when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu' + apt: + name: + - python3-pip + - python3-libvirt + - python-libvirt + state: present + + - name: Install sushy-tools + pip: + name: sushy-tools + executable: pip3 + become: true + +- name: install systemd sushy service unit + become: true + template: + src: sushy-tools.service.j2 + dest: /etc/systemd/system/sushy-tools.service + notify: + - reload systemd configuration + - restart sushy-emulator + +- name: start sushy-emulator service + become: true + service: + name: sushy-tools + state: started + enabled: true diff --git a/roles/redfish-emulator/tasks/main.yml b/roles/redfish-emulator/tasks/main.yml new file mode 100644 index 0000000..ef84389 --- /dev/null +++ b/roles/redfish-emulator/tasks/main.yml @@ -0,0 +1 @@ +- include_tasks: "{{ redfish_action }}.yml" diff --git a/roles/redfish-emulator/templates/sushy-tools.service.j2 b/roles/redfish-emulator/templates/sushy-tools.service.j2 new file mode 100644 index 0000000..db13202 --- /dev/null +++ b/roles/redfish-emulator/templates/sushy-tools.service.j2 @@ -0,0 +1,15 @@ +# This file is part of sushy-emulator (redfish). +# + +[Unit] +Description=Sushy Libvirt emulator +After=syslog.target + +[Service] +Type=simple +ExecStart=/usr/local/bin/sushy-emulator -i {{ redfish_emulator_bind_ip }} -p {{ redfish_emulator_bind_port }} --libvirt-uri "qemu:///system" +StandardOutput=syslog +StandardError=syslog + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/redfish-emulator/tests/main.yml b/roles/redfish-emulator/tests/main.yml new file mode 100644 index 0000000..46988f4 --- /dev/null +++ b/roles/redfish-emulator/tests/main.yml @@ -0,0 +1,40 @@ +- name: Include test variables. + include_vars: + file: vars.yml +- name: install libvirt + include_role: + name: libvirt-install +- name: create pool + include_role: + name: libvirt-pool + vars: + ansible_become: true +- name: Create defined volumes + include_role: + name: libvirt-volume + with_items: "{{ libvirt_volumes }}" + vars: + libvirt_volume: "{{ vol }}" + volume_action: "{{ vol.action }}" + ansible_become: true + loop_control: + loop_var: vol +- name: create libvirt domains + include_role: + name: libvirt-domain +- name: install sushy-tools + include_role: + name: redfish-emulator +- name: query redfish to make sure it has runnig domains + uri: + url: http://localhost:8000/redfish/v1/Systems?format=json + method: GET + return_content: yes + register: sushy_response +- name: debug redfish machines + debug: + var: sushy_response +- name: verify that virtual machine is present in sushy tools + assert: + that: + - sushy_response.json["Members@odata.count"] == 1 diff --git a/roles/redfish-emulator/tests/vars.yml b/roles/redfish-emulator/tests/vars.yml new file mode 100644 index 0000000..11b9852 --- /dev/null +++ b/roles/redfish-emulator/tests/vars.yml @@ -0,0 +1,44 @@ +libvirt_pool: + path: /var/lib/libvirt/airship + name: airship + +libvirt_volumes: + - name: volume-1 + image: https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2 + size: 10G + pool: "{{ libvirt_pool.name }}" + action: create + - name: volume-2 + size: 10G + pool: "{{ libvirt_pool.name }}" + action: create + +libvirt_domain: + state: running + name: 'vm1' + memory_mb: 2048 + vcpus: 1 + volumes: + - name: 'volume-1' + device: 'disk' + format: 'qcow2' + pool: 'airship' + interfaces: + - network: 'provision-network' + +libvirt_network: + name: provision-network + spec: + forward: + mode: nat + nat: + port: + - start: 1024 + end: 65535 + bridge: + name: "prov-net-br" + stp: 'on' + delay: '0' + ip: + address: "172.22.0.1" + netmask: "255.255.255.0" \ No newline at end of file diff --git a/tests/ansible/lint.yaml b/tests/ansible/lint.yml similarity index 85% rename from tests/ansible/lint.yaml rename to tests/ansible/lint.yml index f62ef67..95bf322 100644 --- a/tests/ansible/lint.yaml +++ b/tests/ansible/lint.yml @@ -14,20 +14,19 @@ state: present when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu' - - name: find files to lint find: paths: - - "{{ src_dir| default('../..') }}/playbooks" - - "{{ src_dir| default('../..') }}/roles" + - "{{ zuul.project.src_dir }}/playbooks" + - "{{ zuul.project.src_dir }}/roles" patterns: - "*.yaml" - "*.yml" + recurse: true register: files_to_lint # TODO (kkalynovskyi) develop suitable ansible-lint configuration - name: run ansible-lint against found files command: "ansible-lint {{ item.path }}" with_items: "{{ files_to_lint.files }}" - - + changed_when: false diff --git a/tests/ansible/role-test-runner.yml b/tests/ansible/role-test-runner.yml new file mode 100644 index 0000000..bb14bf1 --- /dev/null +++ b/tests/ansible/role-test-runner.yml @@ -0,0 +1,16 @@ +--- +- hosts: primary + tasks: + - name: set default roles + set_fact: + test_subject_roles_default: + - libvirt-network + - libvirt-pool + - libvirt-volume + - libvirt-domain + - redfish-emulator + - name: run tests against defined roles + include_tasks: "../../roles/{{ role_name }}/tests/main.yml" + with_items: "{{ test_subject_roles | default(test_subject_roles_default) }}" + loop_control: + loop_var: role_name diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml index 7764817..cae4d1f 100644 --- a/zuul.d/jobs.yaml +++ b/zuul.d/jobs.yaml @@ -12,5 +12,16 @@ - job: name: ansible-lint-airship - run: tests/ansible/lint.yaml - nodeset: ubuntu-single-airship \ No newline at end of file + run: tests/ansible/lint.yml + nodeset: ubuntu-single-airship + +- job: + name: zuul-airship-roles-test-libvirt + run: tests/ansible/role-test-runner.yml + vars: + test_subject_roles: + - libvirt-network + - libvirt-pool + - libvirt-volume + - libvirt-domain + nodeset: ubuntu-single-airship diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml index 0e5189b..67f4915 100644 --- a/zuul.d/project.yaml +++ b/zuul.d/project.yaml @@ -2,6 +2,8 @@ check: jobs: - ansible-lint-airship + - zuul-airship-roles-test-libvirt gate: jobs: - ansible-lint-airship + - zuul-airship-roles-test-libvirt