Skip to content

Use fcqn for all tasks #87

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @stackhpc/ansible
12 changes: 12 additions & 0 deletions .github/workflows/publish-role.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
name: Publish Ansible Role
'on':
push:
tags:
- "v?[0-9]+.[0-9]+.[0-9]+"
workflow_dispatch:
jobs:
publish_role:
uses: stackhpc/.github/.github/workflows/publish-role.yml@main
secrets:
GALAXY_API_KEY: ${{ secrets.GALAXY_API_KEY }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.idea
**/__pychache__
.cache
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ Role Variables
- `enable_spice`: If true enables SPICE listening for use with
Virtual Machine Manager and similar tools

- `enable_guest_virtio`: If true enables guest virtio device for use with
Qemu guest agent

- `volumes`: a list of volumes to attach to the VM. Each volume is
defined with the following dict:
- `type`: What type of backing volume does the instance use? All
Expand All @@ -120,6 +123,27 @@ Role Variables
- `dev`: (optional) Block device path when type is `block`.
- `remote_src`: (optional) When type is `file` or `block`, specify wether `image` points to a remote file (true) or a file local to the host that launched the playbook (false). Defaults to true.

- `usb_devices`: a list of usb devices to present to the vm from the host.

Each usb device is defined with the following dict:

- `vendor`: The vendor id of the USB device.
- `product`: The product id of the USB device.

Note - Libvirt will error if the VM is provisioned and the USB device is not attached.

To obtain the vendor id and product id of the usb device from the host running as sudo / root with the usb device plugged in
run `lsusb -v`. Example below with an attached Sandisk USB Memory Stick with vendor id: `0x0781` and product id: `0x5567`

```
lsusb -v | grep -A4 -i sandisk

idVendor 0x0781 SanDisk Corp.
idProduct 0x5567 Cruzer Blade
bcdDevice 1.00
iManufacturer 1
iProduct 2
```

- `interfaces`: a list of network interfaces to attach to the VM.
Each network interface is defined with the following dict:
Expand Down Expand Up @@ -231,6 +255,10 @@ Example Playbook

interfaces:
- network: 'br-datacentre'

usb_devices:
- vendor: '0x0781'
product: '0x5567'

- state: present
name: 'vm2'
Expand Down
18 changes: 9 additions & 9 deletions tasks/autodetect.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
- name: Detect the virtualisation engine
block:
- name: Load the kvm kernel module
modprobe:
community.general.modprobe:
name: kvm
become: true
failed_when: false

- name: Check for the KVM device
stat:
ansible.builtin.stat:
path: /dev/kvm
register: stat_kvm

- name: Set a fact containing the virtualisation engine
set_fact:
ansible.builtin.set_fact:
libvirt_vm_engine: >-
{%- if ansible_facts.architecture != libvirt_vm_arch -%}
{# Virtualisation instructions are generally available only for the host
Expand All @@ -32,7 +32,7 @@
block:
- block:
- name: Detect the KVM emulator binary path
stat:
ansible.builtin.stat:
path: "{{ item }}"
register: kvm_emulator_result
with_items:
Expand All @@ -49,12 +49,12 @@

- block:
- name: Detect the QEMU emulator binary path
stat:
ansible.builtin.stat:
path: /usr/libexec/qemu-kvm
register: kvm_emulator_result

- name: Set a fact containing the QEMU emulator binary path
set_fact:
ansible.builtin.set_fact:
libvirt_vm_emulator: "{{ kvm_emulator_result.stat.path }}"
when: kvm_emulator_result.stat.exists
when:
Expand All @@ -64,20 +64,20 @@

- block:
- name: Detect the QEMU emulator binary path
shell: which qemu-system-{{ libvirt_vm_arch }}
ansible.builtin.command: 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:
ansible.builtin.set_fact:
libvirt_vm_emulator: "{{ qemu_emulator_result.stdout }}"

when:
- libvirt_vm_engine == 'qemu'
- ansible_facts.os_family != 'RedHat' or ansible_facts.distribution_major_version | int == 7

- name: Fail if unable to detect the emulator
fail:
ansible.builtin.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
4 changes: 2 additions & 2 deletions tasks/check-interface.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
- name: Check network interface has a network name
fail:
ansible.builtin.fail:
msg: >
The interface definition {{ interface }} has type 'network', but does not have
a network name defined.
Expand All @@ -10,7 +10,7 @@
- interface.network is not defined

- name: Check direct interface has an interface device name
fail:
ansible.builtin.fail:
msg: >
The interface definition {{ interface }} has type 'direct', but does not have
a host source device defined.
Expand Down
15 changes: 15 additions & 0 deletions tasks/check-usb-devices.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
- name: List USB hardware
ansible.builtin.command: lsusb -d {{ usb_device.vendor }}:{{ usb_device.product }}
register: host_attached_usb_device
become: true
changed_when: false
failed_when: false

- name: Check USB device is present on Host system
ansible.builtin.fail:
msg: >
The USB Device with Vendor ID:{{ usb_device.vendor }} and Product ID:{{ usb_device.product }} is not seen on host system
Is the USB device plugged in correctly ?
when:
- host_attached_usb_device.rc != 0
12 changes: 6 additions & 6 deletions tasks/destroy-vm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,34 @@
# The destroyed state does not seem to be idempotent, so check whether the VM
# exists before destroying it.
- name: Check the VM's status
virt:
community.libvirt.virt:
name: "{{ vm.name }}"
command: list_vms
uri: "{{ libvirt_vm_uri | default(omit, true) }}"
register: result
become: yes
become: true

- block:
- name: Ensure the VM is absent
virt:
community.libvirt.virt:
name: "{{ vm.name }}"
state: destroyed
uri: "{{ libvirt_vm_uri | default(omit, true) }}"
become: yes
become: true

# note(wszumski): the virt module does not seem to support
# removing vms with nvram defined - as a workaround, use the
# virsh cli directly. It may be better to detect if dumpxml
# actually contains an nvram element rather than relying on
# boot_firmware having the correct value.
- name: Ensure the VM is undefined
command:
ansible.builtin.command:
cmd: >-
virsh
{% if libvirt_vm_uri %}-c {{ libvirt_vm_uri }}{% endif %}
undefine
{% if boot_firmware == 'efi' %} --nvram{% endif %}
{{ vm.name }}
become: yes
become: true
changed_when: true
when: vm.name in result.list_vms
4 changes: 2 additions & 2 deletions tasks/destroy-volumes.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
- name: Ensure the VM volumes do not exist
script: >
ansible.builtin.script: >
destroy_virt_volume.sh
{{ item.name }}
{{ item.pool | default('default') }}
Expand All @@ -11,4 +11,4 @@
changed_when:
- volume_result is success
- (volume_result.stdout | from_json).changed | default(True)
become: yes
become: true
16 changes: 9 additions & 7 deletions tasks/main.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
- name: Gather os specific variables
include_vars: "{{ item }}"
ansible.builtin.include_vars: "{{ item }}"
with_first_found:
- files:
- "{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_major_version }}.yml"
- "{{ ansible_facts.distribution }}.yml"
- "{{ ansible_facts.os_family }}.yml"
tags: vars

- include_tasks: autodetect.yml
- ansible.builtin.include_tasks: autodetect.yml
# We don't need to know the engine and emulator if we're not creating any new
# VMs.
when: >-
Expand All @@ -17,20 +17,20 @@

# Libvirt requires qemu-img to create qcow2 files.
- name: Ensure qemu-img is installed
package:
ansible.builtin.package:
name: "{{ 'qemu-img' if ansible_facts.os_family == 'RedHat' else 'qemu-utils' }}"
update_cache: "{{ True if ansible_facts.pkg_mgr == 'apt' else omit }}"
become: true

- include_tasks: volumes.yml
- ansible.builtin.include_tasks: volumes.yml
vars:
volumes: "{{ vm.volumes | default([], true) }}"
with_items: "{{ libvirt_vms }}"
loop_control:
loop_var: vm
when: (vm.state | default('present', true)) == 'present'

- include_tasks: vm.yml
- ansible.builtin.include_tasks: vm.yml
vars:
console_log_enabled: "{{ vm.console_log_enabled | default(false) }}"
console_log_path: >-
Expand All @@ -41,25 +41,27 @@
cpu_mode: "{{ vm.cpu_mode | default(libvirt_cpu_mode_default) }}"
volumes: "{{ vm.volumes | default([], true) }}"
interfaces: "{{ vm.interfaces | default([], true) }}"
usb_devices: "{{ vm.usb_devices | default([], false) }}"
start: "{{ vm.start | default(true) }}"
autostart: "{{ vm.autostart | default(true) }}"
enable_vnc: "{{ vm.enable_vnc | default(false) }}"
enable_spice: "{{ vm.enable_spice | default(false) }}"
enable_guest_virtio: "{{ vm.enable_guest_virtio | default(false) }}"
boot_firmware: "{{ vm.boot_firmware | default('bios', true) | lower }}"
with_items: "{{ libvirt_vms }}"
loop_control:
loop_var: vm
when: (vm.state | default('present', true)) == 'present'

- include_tasks: destroy-vm.yml
- ansible.builtin.include_tasks: destroy-vm.yml
vars:
boot_firmware: "{{ vm.boot_firmware | default('bios', true) | lower }}"
with_items: "{{ libvirt_vms }}"
loop_control:
loop_var: vm
when: (vm.state | default('present', true)) == 'absent'

- include_tasks: destroy-volumes.yml
- ansible.builtin.include_tasks: destroy-volumes.yml
vars:
volumes: "{{ vm.volumes | default([], true) }}"
with_items: "{{ libvirt_vms }}"
Expand Down
15 changes: 11 additions & 4 deletions tasks/vm.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
- name: Ensure the VM console log directory exists
file:
ansible.builtin.file:
path: "{{ console_log_path | dirname }}"
state: directory
owner: "{{ libvirt_vm_log_owner }}"
Expand All @@ -11,20 +11,27 @@
become: "{{ libvirt_vm_sudo }}"

- name: Validate VM interfaces
include_tasks: check-interface.yml
ansible.builtin.include_tasks: check-interface.yml
vars:
interface: "{{ item }}"
with_items: "{{ interfaces }}"

- name: Validate Host USB Devices
ansible.builtin.include_tasks: check-usb-devices.yml
vars:
usb_device: "{{ item }}"
with_items: "{{ usb_devices }}"

- name: Ensure the VM is defined
virt:
community.libvirt.virt:
name: "{{ vm.name }}"
command: define
xml: "{{ lookup('template', vm.xml_file | default('vm.xml.j2')) }}"
uri: "{{ libvirt_vm_uri | default(omit, true) }}"
become: "{{ libvirt_vm_sudo }}"

- name: Ensure the VM is running and started at boot
virt:
community.libvirt.virt:
name: "{{ vm.name }}"
autostart: "{{ autostart | bool }}"
state: "{{ 'running' if (start | bool) else 'shutdown' }}"
Expand Down
8 changes: 4 additions & 4 deletions tasks/volumes.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
- name: Ensure remote images are downloaded
get_url:
ansible.builtin.get_url:
url: "{{ item.image }}"
dest: "{{ libvirt_vm_image_cache_path }}/{{ item.image | basename }}"
checksum: "{{ item.checksum | default(omit) }}"
with_items: "{{ volumes | selectattr('image', 'defined') | list }}"
when: "'http' in item.image"

- name: Ensure local images are copied
copy:
ansible.builtin.copy:
src: "{{ item.image }}"
dest: "{{ libvirt_vm_image_cache_path }}/{{ item.image | basename }}"
checksum: "{{ item.checksum | default(omit) }}"
Expand All @@ -17,7 +17,7 @@
when: "'http' not in item.image"

- name: Ensure the VM disk volumes exist
script: >
ansible.builtin.script: >
virt_volume.sh
-n {{ item.name }}
-p {{ item.pool |default('default') }}
Expand All @@ -40,7 +40,7 @@
become: true

- name: Ensure the VM network volumes exist
command: qemu-img create -f {{ item.source.protocol }} {{ item.source.protocol }}:{{ item.source.name }} {{ item.capacity }}
ansible.builtin.command: qemu-img create -f {{ item.source.protocol }} {{ item.source.protocol }}:{{ item.source.name }} {{ item.capacity }}
with_items: "{{ volumes }}"
when: item.type | default(libvirt_volume_default_type) == 'network'
register: volume_result_network
Expand Down
Loading