From c2771d7c0e84513c619ecd903e95da14d86447bb Mon Sep 17 00:00:00 2001
From: Mark Goddard <mark@stackhpc.com>
Date: Wed, 26 Jul 2017 18:26:24 +0000
Subject: [PATCH] Add libvirt-host role

Configures a host as a Libvirt/KVM hypervisor. It can also create pools and networks
---
 ansible/roles/libvirt-host/README.md          | 61 +++++++++++++++++++
 ansible/roles/libvirt-host/defaults/main.yml  | 19 ++++++
 ansible/roles/libvirt-host/meta/main.yml      | 19 ++++++
 ansible/roles/libvirt-host/tasks/install.yml  | 19 ++++++
 ansible/roles/libvirt-host/tasks/main.yml     |  5 ++
 ansible/roles/libvirt-host/tasks/networks.yml | 22 +++++++
 ansible/roles/libvirt-host/tasks/pools.yml    | 32 ++++++++++
 ansible/roles/libvirt-host/tasks/validate.yml | 13 ++++
 .../libvirt-host/templates/network.xml.j2     |  5 ++
 .../roles/libvirt-host/templates/pool.xml.j2  |  7 +++
 10 files changed, 202 insertions(+)
 create mode 100644 ansible/roles/libvirt-host/README.md
 create mode 100644 ansible/roles/libvirt-host/defaults/main.yml
 create mode 100644 ansible/roles/libvirt-host/meta/main.yml
 create mode 100644 ansible/roles/libvirt-host/tasks/install.yml
 create mode 100644 ansible/roles/libvirt-host/tasks/main.yml
 create mode 100644 ansible/roles/libvirt-host/tasks/networks.yml
 create mode 100644 ansible/roles/libvirt-host/tasks/pools.yml
 create mode 100644 ansible/roles/libvirt-host/tasks/validate.yml
 create mode 100644 ansible/roles/libvirt-host/templates/network.xml.j2
 create mode 100644 ansible/roles/libvirt-host/templates/pool.xml.j2

diff --git a/ansible/roles/libvirt-host/README.md b/ansible/roles/libvirt-host/README.md
new file mode 100644
index 000000000..5ad74d447
--- /dev/null
+++ b/ansible/roles/libvirt-host/README.md
@@ -0,0 +1,61 @@
+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>)
diff --git a/ansible/roles/libvirt-host/defaults/main.yml b/ansible/roles/libvirt-host/defaults/main.yml
new file mode 100644
index 000000000..25d3e13fa
--- /dev/null
+++ b/ansible/roles/libvirt-host/defaults/main.yml
@@ -0,0 +1,19 @@
+---
+# 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: []
diff --git a/ansible/roles/libvirt-host/meta/main.yml b/ansible/roles/libvirt-host/meta/main.yml
new file mode 100644
index 000000000..b85c6d29e
--- /dev/null
+++ b/ansible/roles/libvirt-host/meta/main.yml
@@ -0,0 +1,19 @@
+---
+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: []
diff --git a/ansible/roles/libvirt-host/tasks/install.yml b/ansible/roles/libvirt-host/tasks/install.yml
new file mode 100644
index 000000000..16898b1f9
--- /dev/null
+++ b/ansible/roles/libvirt-host/tasks/install.yml
@@ -0,0 +1,19 @@
+---
+- 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
diff --git a/ansible/roles/libvirt-host/tasks/main.yml b/ansible/roles/libvirt-host/tasks/main.yml
new file mode 100644
index 000000000..8bc226887
--- /dev/null
+++ b/ansible/roles/libvirt-host/tasks/main.yml
@@ -0,0 +1,5 @@
+---
+- include: validate.yml
+- include: install.yml
+- include: pools.yml
+- include: networks.yml
diff --git a/ansible/roles/libvirt-host/tasks/networks.yml b/ansible/roles/libvirt-host/tasks/networks.yml
new file mode 100644
index 000000000..aa4c7fa35
--- /dev/null
+++ b/ansible/roles/libvirt-host/tasks/networks.yml
@@ -0,0 +1,22 @@
+---
+- 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
diff --git a/ansible/roles/libvirt-host/tasks/pools.yml b/ansible/roles/libvirt-host/tasks/pools.yml
new file mode 100644
index 000000000..23e74910f
--- /dev/null
+++ b/ansible/roles/libvirt-host/tasks/pools.yml
@@ -0,0 +1,32 @@
+---
+- 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
diff --git a/ansible/roles/libvirt-host/tasks/validate.yml b/ansible/roles/libvirt-host/tasks/validate.yml
new file mode 100644
index 000000000..e0af95efc
--- /dev/null
+++ b/ansible/roles/libvirt-host/tasks/validate.yml
@@ -0,0 +1,13 @@
+---
+- 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
diff --git a/ansible/roles/libvirt-host/templates/network.xml.j2 b/ansible/roles/libvirt-host/templates/network.xml.j2
new file mode 100644
index 000000000..830e70527
--- /dev/null
+++ b/ansible/roles/libvirt-host/templates/network.xml.j2
@@ -0,0 +1,5 @@
+<network connections='1'>
+  <name>{{ item.name }}</name>
+  <forward mode='{{ item.mode }}'/>
+  <bridge name='{{ item.bridge }}'/>
+</network>
diff --git a/ansible/roles/libvirt-host/templates/pool.xml.j2 b/ansible/roles/libvirt-host/templates/pool.xml.j2
new file mode 100644
index 000000000..5916fdfa8
--- /dev/null
+++ b/ansible/roles/libvirt-host/templates/pool.xml.j2
@@ -0,0 +1,7 @@
+<pool type='{{ item.type }}'>
+  <name>{{ item.name }}</name>
+  <capacity unit='bytes'>{{ item.capacity }}</capacity>
+  <target>
+    <path>{{ item.path }}</path>
+  </target>
+</pool>