Move libvirt-host and libvirt-vm to Ansible Galaxy roles

This commit is contained in:
Stig Telfer 2017-12-05 15:57:11 +00:00
parent 7c9378d0bc
commit bf608b1177
23 changed files with 5 additions and 494 deletions

View File

@ -1,61 +0,0 @@
Libvirt Host
============
This role configures a host as a Libvirt/KVM hypervisor. It can also configure
storage pools and networks on the host.
Requirements
------------
The host should have Virtualization Technology (VT) enabled.
Role Variables
--------------
`libvirt_host_networks` is a list of pools to define and start. Each item
should be a dict containing the following items:
- `name` The name of the pool.
- `type` The type of the pool, currently only `dir` is supported.
- `capacity` The capacity, in bytes, of the pool.
- `path` The absolute path to the pool's backing directory.
- `mode` The access mode of the pool.
- `owner` The owner of the pool.
- `group` The group of the pool.
`libvirt_host_networks` is a list of networks to define and start. Each item
should be a dict containing the following items:
- `name` The name of the network.
- `mode` The forwarding mode of the network, currently only `bridge` is
supported.
- bridge` The name of the bridge interface for this network.
Dependencies
------------
None
Example Playbook
----------------
---
- name: Ensure that Libvirt is configured
hosts: all
roles:
- role: libvirt-host
libvirt_host_pools:
- name: my-pool
type: dir
capacity: 1024
path: /path/to/pool
mode: 0755
owner: my-user
group: my-group
libvirt_host_networks:
- name: br-example
mode: bridge
bridge: br-example
Author Information
------------------
- Mark Goddard (<mark@stackhpc.com>)

View File

@ -1,19 +0,0 @@
---
# List of pools to define and start.
# Each item should be a dict containing the following items:
# name: The name of the pool.
# type: The type of the pool, currently only 'dir' is supported.
# capacity: The capacity, in bytes, of the pool.
# path: The absolute path to the pool's backing directory.
# mode: The access mode of the pool.
# owner: The owner of the pool.
# group: The group of the pool.
libvirt_host_pools: []
# List of networks to define and start.
# Each item should be a dict containing the following items:
# name: The name of the network.
# mode: The forwarding mode of the network, currently only 'bridge' is
# supported.
# bridge: The name of the bridge interface for this network.
libvirt_host_networks: []

View File

@ -1,19 +0,0 @@
---
galaxy_info:
author: Mark Goddard
description: >
Role to install and configure a host as a Libvirt/KVM hypervisor
company: StackHPC Ltd
license: Apache2
min_ansible_version: 2.0
platforms:
- name: EL
versions:
- 7
galaxy_tags:
- cloud
- kvm
- libvirt
- vm
dependencies: []

View File

@ -1,19 +0,0 @@
---
- name: Ensure the libvirt package is installed
yum:
name: "{{ item }}"
state: installed
with_items:
- libvirt
- libvirt-daemon-kvm
- libvirt-python
- python-lxml
- qemu-kvm
become: True
- name: Ensure the libvirt daemon is started and enabled
service:
name: libvirtd
state: running
enabled: yes
become: True

View File

@ -1,5 +0,0 @@
---
- include: validate.yml
- include: install.yml
- include: pools.yml
- include: networks.yml

View File

@ -1,22 +0,0 @@
---
- name: Ensure libvirt networks are defined
virt_net:
name: "{{ item.name }}"
command: define
xml: "{{ item.xml | default(lookup('template', 'network.xml.j2')) }}"
with_items: "{{ libvirt_host_networks }}"
become: True
- name: Ensure libvirt networks are active
virt_net:
name: "{{ item.name }}"
state: active
with_items: "{{ libvirt_host_networks }}"
become: True
- name: Ensure libvirt networks are started on boot
virt_net:
name: "{{ item.name }}"
autostart: yes
with_items: "{{ libvirt_host_networks }}"
become: True

View File

@ -1,32 +0,0 @@
---
- name: Ensure libvirt storage pool directories exist
file:
path: "{{ item.path }}"
owner: "{{ item.owner }}"
group: "{{ item.group }}"
mode: "{{ item.mode|int(base=8) }}"
state: directory
with_items: "{{ libvirt_host_pools }}"
become: True
- name: Ensure libvirt storage pools are defined
virt_pool:
name: "{{ item.name }}"
command: define
xml: "{{ item.xml | default(lookup('template', 'pool.xml.j2')) }}"
with_items: "{{ libvirt_host_pools }}"
become: True
- name: Ensure libvirt storage pools are active
virt_pool:
name: "{{ item.name }}"
state: active
with_items: "{{ libvirt_host_pools }}"
become: True
- name: Ensure libvirt storage pools are started on boot
virt_pool:
name: "{{ item.name }}"
autostart: yes
with_items: "{{ libvirt_host_pools }}"
become: True

View File

@ -1,13 +0,0 @@
---
- name: Verify that Virtualization Technology (VT) is enabled
command: grep -c -E 'svm|vmx' /proc/cpuinfo
changed_when: False
failed_when: False
register: result
- name: Fail if Virtualization Technology (VT) is disabled
fail:
msg: >
Virtualization Technology (VT) is currently disabled. Please enable VT
before running this role again.
when: result.rc != 0

View File

@ -1,5 +0,0 @@
<network connections='1'>
<name>{{ item.name }}</name>
<forward mode='{{ item.mode }}'/>
<bridge name='{{ item.bridge }}'/>
</network>

View File

@ -1,7 +0,0 @@
<pool type='{{ item.type }}'>
<name>{{ item.name }}</name>
<capacity unit='bytes'>{{ item.capacity }}</capacity>
<target>
<path>{{ item.path }}</path>
</target>
</pool>

View File

@ -1,24 +0,0 @@
---
# State of the VM. May be 'present' or 'absent'.
libvirt_vm_state: present
# Name of the VM.
libvirt_vm_name:
# Memory in MB.
libvirt_vm_memory_mb:
# Number of vCPUs.
libvirt_vm_vcpus:
# List of volumes.
libvirt_vm_volumes: []
# List of network interfaces.
libvirt_vm_interfaces: []
# Path to cache downloaded images.
libvirt_vm_image_cache_path:
# List of authorized SSH public keys.
#libvirt_vm_public_keys: []

View File

@ -1,52 +0,0 @@
#!/bin/bash
# Copyright (c) 2017 StackHPC Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Ensure that a libvirt volume does not exists.
# On success, output a JSON object with a 'changed' item.
if [[ $# -ne 2 ]]; then
echo "Usage: $0 <name> <pool>"
exit 1
fi
NAME=$1
POOL=$2
# Check whether a volume with this name exists.
output=$(virsh vol-info --pool $POOL --vol $NAME 2>&1)
result=$?
if [[ $result -ne 0 ]]; then
if echo "$output" | grep 'Storage volume not found' >/dev/null 2>&1; then
echo '{"changed": false}'
exit 0
else
echo "Unexpected error while getting volume info"
echo "$output"
exit $result
fi
fi
# Delete the volume.
output=$(virsh vol-delete --pool $POOL --vol $NAME 2>&1)
result=$?
if [[ $result -ne 0 ]]; then
echo "Failed to delete volume"
echo "$output"
exit $result
fi
echo '{"changed": true}'
exit 0

View File

@ -1,96 +0,0 @@
#!/bin/bash
# Copyright (c) 2017 StackHPC Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Ensure that a libvirt volume exists, optionally uploading an image.
# On success, output a JSON object with a 'changed' item.
if [[ $# -ne 4 ]] && [[ $# -ne 5 ]]; then
echo "Usage: $0 <name> <pool> <capacity> <format> [<image>]"
exit 1
fi
NAME=$1
POOL=$2
CAPACITY=$3
FORMAT=$4
IMAGE=$5
# Check whether a volume with this name exists.
output=$(virsh vol-info --pool $POOL --vol $NAME 2>&1)
result=$?
if [[ $result -eq 0 ]]; then
echo '{"changed": false}'
exit 0
elif ! echo "$output" | grep 'Storage volume not found' >/dev/null 2>&1; then
echo "Unexpected error while getting volume info"
echo "$output"
exit $result
fi
# Create the volume.
output=$(virsh vol-create-as --pool $POOL --name $NAME --capacity $CAPACITY --format $FORMAT 2>&1)
result=$?
if [[ $result -ne 0 ]]; then
echo "Failed to create volume"
echo "$output"
exit $result
fi
# Determine the path to the volume file.
output=$(virsh vol-key --pool $POOL --vol $NAME 2>&1)
result=$?
if [[ $result -ne 0 ]]; then
echo "Failed to get volume file path"
echo "$output"
virsh vol-delete --pool $POOL --vol $NAME
exit $result
fi
# Change the ownership of the volume to qemu. Without doing this libvirt cannot
# access the volume.
output=$(chown qemu:qemu $output 2>1)
result=$?
if [[ $result -ne 0 ]]; then
echo "Failed to change ownership of the volume to qemu"
echo "$output"
virsh vol-delete --pool $POOL --vol $NAME
exit $result
fi
if [[ -n $IMAGE ]]; then
# Upload an image to the volume.
output=$(virsh vol-upload --pool $POOL --vol $NAME --file $IMAGE 2>&1)
result=$?
if [[ $result -ne 0 ]]; then
echo "Failed to upload image $IMAGE to volume $NAME"
echo "$output"
virsh vol-delete --pool $POOL --vol $NAME
exit $result
fi
# Resize the volume to the requested capacity.
output=$(virsh vol-resize --pool $POOL --vol $NAME --capacity $CAPACITY 2>&1)
result=$?
if [[ $result -ne 0 ]]; then
echo "Failed to resize volume $VOLUME to $CAPACITY"
echo "$output"
virsh vol-delete --pool $POOL --vol $NAME
exit $result
fi
fi
echo '{"changed": true}'
exit 0

View File

@ -1,20 +0,0 @@
---
# 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:
name: "{{ libvirt_vm_name }}"
command: list_vms
register: result
- block:
- name: Ensure the VM is absent
virt:
name: "{{ libvirt_vm_name }}"
state: destroyed
- name: Ensure the VM is undefined
virt:
name: "{{ libvirt_vm_name }}"
command: undefine
when: libvirt_vm_name in result.list_vms

View File

@ -1,11 +0,0 @@
---
- name: Ensure the VM volumes do not exist
script: >
destroy_virt_volume.sh
{{ item.name }}
{{ item.pool }}
with_items: "{{ libvirt_vm_volumes }}"
register: volume_result
changed_when:
- volume_result | success
- (volume_result.stdout | from_json).changed | default(True)

View File

@ -1,10 +0,0 @@
---
- block:
- include: volumes.yml
- include: vm.yml
when: libvirt_vm_state == 'present'
- block:
- include: destroy-volumes.yml
- include: destroy-vm.yml
when: libvirt_vm_state == 'absent'

View File

@ -1,16 +0,0 @@
---
- name: Ensure the VM is defined
virt:
name: "{{ libvirt_vm_name }}"
command: define
xml: "{{ lookup('template', 'vm.xml.j2') }}"
- name: Ensure the VM is running
virt:
name: "{{ libvirt_vm_name }}"
state: running
- name: Ensure the VM is started at boot
virt:
name: "{{ libvirt_vm_name }}"
command: autostart

View File

@ -1,30 +0,0 @@
---
- name: Ensure remote images are downloaded
get_url:
url: "{{ item }}"
dest: "{{ libvirt_vm_image_cache_path }}/{{ item | basename }}"
with_items: "{{ libvirt_vm_volumes | selectattr('image', 'defined') | map(attribute='image') | list }}"
when: "'http' in item"
- name: Ensure local images are copied
copy:
src: "{{ item }}"
dest: "{{ libvirt_vm_image_cache_path }}/{{ item | basename }}"
with_items: "{{ libvirt_vm_volumes | selectattr('image', 'defined') | map(attribute='image') | list }}"
when: "'http' not in item"
- name: Ensure the VM volumes exist
script: >
virt_volume.sh
{{ item.name }}
{{ item.pool }}
{{ item.capacity }}
{{ item.format | default('qcow2') }}
{% if item.image is defined %}
{{ libvirt_vm_image_cache_path }}/{{ item.image | basename }}
{% endif %}
with_items: "{{ libvirt_vm_volumes }}"
register: volume_result
changed_when:
- volume_result | success
- (volume_result.stdout | from_json).changed | default(True)

View File

@ -1,30 +0,0 @@
<domain type='kvm'>
<name>{{ libvirt_vm_name }}</name>
<memory>{{ libvirt_vm_memory_mb | int * 1024 }}</memory>
<vcpu>{{ libvirt_vm_vcpus }}</vcpu>
<clock sync="localtime"/>
<os>
<type arch='x86_64'>hvm</type>
</os>
<devices>
{% for volume in libvirt_vm_volumes %}
<disk type='volume' device='{{ volume.device | default('disk') }}'>
<driver name='qemu' type='{{ volume.format }}'/>
<source pool='{{ volume.pool }}' volume='{{ volume.name }}'/>
<target dev='vd{{ 'abcdefghijklmnopqrstuvwxyz'[loop.index] }}'/>
</disk>
{% endfor %}
{% for interface in libvirt_vm_interfaces %}
<interface type='network'>
<source network='{{ interface.network }}'/>
<model type='virtio'/>
</interface>
{% endfor %}
<serial type='pty'>
<target port='0'/>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
</devices>
</domain>

View File

@ -2,6 +2,6 @@
- name: Ensure the libvirt daemon is configured
hosts: seed-hypervisor
roles:
- role: libvirt-host
- role: stackhpc.libvirt-host
libvirt_host_pools: "{{ seed_hypervisor_libvirt_pools }}"
libvirt_host_networks: "{{ seed_hypervisor_libvirt_networks }}"

View File

@ -5,7 +5,7 @@
seed_host: "{{ groups['seed'][0] }}"
seed_hostvars: "{{ hostvars[seed_host] }}"
roles:
- role: libvirt-vm
- role: stackhpc.libvirt-vm
seed_vm_configdrive_volume:
name: "{{ seed_hostvars.seed_vm_name }}-configdrive"
pool: "{{ seed_hostvars.seed_vm_pool }}"

View File

@ -92,7 +92,7 @@
register: stat_result
roles:
- role: libvirt-vm
- role: stackhpc.libvirt-vm
seed_vm_configdrive_volume:
name: "{{ seed_hostvars.seed_vm_name }}-configdrive"
pool: "{{ seed_hostvars.seed_vm_pool }}"

View File

@ -10,6 +10,8 @@
name: singleplatform-eng.users
- src: stackhpc.drac
- src: stackhpc.drac-facts
- src: stackhpc.libvirt-host
- src: stackhpc.libvirt-vm
- src: stackhpc.os-flavors
- src: stackhpc.os-images
- src: stackhpc.os-networks