Use Ansible to create test VMs

this patch moves logic for preparing libvirt environment
and creating test VMs out of bash script to Ansible tasks
using virt_* modules available since Ansible 2.0.

The only virsh command left is volume creation as Ansible still
lacks modules for libvirt volume management.

As a consequence, many variables hidden in the bash script are now
explicitly defined in defaults of 'bifrost-create-vm-nodes' role and can
be redefined by standard Ansible means.

Although the libvirt connection string can be redefined too,
it was not tested with any other than default value (local qemu connection).

Change-Id: Idaca6b5f502e0e2391af92651f30ab9dcd2fbb3b
Related-Bug: #1659876
This commit is contained in:
Pavlo Shchelokovskyy 2017-01-31 11:12:16 +02:00
parent 4733aa3b37
commit f888748d4e
14 changed files with 492 additions and 334 deletions

View File

@ -11,8 +11,20 @@ The following packages are required and ensured to be present:
- qemu-utils - qemu-utils
- qemu-kvm - qemu-kvm
- sgabios - sgabios
- python-libvirt
- python-lxml
Warning
-------
For backward compatibility some variables listed below may default to values
of corresponding shell variables on the management host (where
ansible-playbook is launched) as described.
This behavior is deprecated and will be removed in the Queens release.
Non-default values for these variables should be passed to ansible-playbook
as extra-vars instead.
Role Variables Role Variables
-------------- --------------
@ -32,6 +44,113 @@ test_vm_num_nodes: Tunable setting to allow a user to define the number of
test VMs that will be created. They will all be created test VMs that will be created. They will all be created
with same settings. with same settings.
test_vm_arch: Defines the architecture of VM to create.
Defaults to "x86_64".
The value of this variable is passed directly to libvirt
when creating VMs.
Generally users should not need to modify this setting.
Any other than default value is untested.
test_vm_disk_gib: Disk size for VMs to be created, in GiB.
Defaults to shell variable 'VM_DISK' or,
if that is not set, to 10.
test_vm_cpu_count: Number of CPUs to create the VMs with.
Defaults to shell variable 'VM_CPU', or,
if that is not set, to 1.
test_vm_disk_cache: Disk cache mode to use by VMs disk.
Defaults to shell variable 'VM_DISK_CACHE', or,
if that is not set, to 'writeback'.
test_vm_node_names: Space-separated names for nodes to be created.
Defaults to shell variable 'TEST_VM_NODE_NAMES'.
If not set, VM names will be autogenerated.
Note that independent on the number of names in this list,
at most 'test_vm_num_nodes' VMs will be created.
test_vm_node_name_base: Base name to generate VM names when names
are not explicitly set.
Defaults to shell variable 'NODEBASE', or,
if that is not set, to 'testvm'.
test_vm_network: Name of the libvirt network to create the nodes on.
Defaults to shell variable 'VM_NET_BRIDGE', or,
if that is not set, to 'default'.
test_vm_storage_pool: Name of the libvirt storage pool to create disks
for VMs in.
Defaults to shell variable 'LIBVIRT_STORAGE_POOL', or,
if that is not set, to 'default'.
If absent, this pool will be created.
test_vm_storage_pool_path: Path used by the libvirt storage pool
'test_vm_storage_pool' if it has to be created.
Defaults to "/var/lib/libvirt/images".
test_vm_logdir: Folder where to store VM logs.
Defaults to "/var/log/libvirt/baremetal_logs".
test_vm_emulator: Path to emulator executable used to define VMs in libvirt.
Defaults to "/usr/bin/qemu-system-x86_64".
Generally users should not need to modify this setting,
as it is OS-specific and is overwritten by
os/distribution-specific defaults in this role when needed.
test_vm_machine: Type of the VM to define in libvirt.
Defaults to "pc-1.0".
Generally users should not need to modify this setting,
as it is OS-specific and is overwritten by
os/distribution-specific defaults in this role when needed.
test_vm_libvirt_uri: URI to connect to libvirt for networks, storage and VM
related actions.
Defaults to shell variable 'LIBVIRT_CONNECT_URI', or,
if that is not set, to 'qemu:///system'.
Note that currently connecting to remote libvirt is
not tested and is unsupported.
test_vm_network: Name of the libvirt network to create for VMs.
Defaults to shell variable 'VM_NET_BRIDGE', or, if that is
not set, to 'default'.
The network is created only if it does not already exist.
network_interface: Name of the bridge to create when creating
'test_vm_network' libvirt network.
Defaults to "virbr0".
Name and default of this option are chosen to be the same
as in 'bifrost-ironic-install' role.
test_vm_network_ip: IP for the 'network_interface' bridge.
Defaults to '192.168.122.1'.
This setting is applied only when 'test_vm_network'
was absent and is created from scratch.
test_vm_network_netmask: Subnet mask for 'network_interface' bridge.
Defaults to '255.255.255.0'.
This setting is applied only when 'test_vm_network'
was absent and is created from scratch.
test_vm_network_enable_dhcp: Whether to enable DHCP on 'test_vm_network'.
Defaults to 'true'.
This setting is applied only when
'test_vm_network' was absent and is created
from scratch.
test_vm_network_dhcp_start: Start of DHCP range for 'test_vm_network'.
Defaults to '192.168.122.2'.
This setting is applied only when
'test_vm_network' was absent and is created
from scratch and when
'test_vm_network_enable_dhcp' is enabled.
test_vm_network_dhcp_end: End of of DHCP range for 'test_vm_network'.
Defaults to '192.168.122.254'.
This setting is applied only when
'test_vm_network' was absent and is created
from scratch and when
'test_vm_network_enable_dhcp' is enabled.
Dependencies Dependencies
------------ ------------

View File

@ -2,5 +2,31 @@
# defaults file for bifrost-create-vm-nodes # defaults file for bifrost-create-vm-nodes
baremetal_csv_file: "/tmp/baremetal.csv" baremetal_csv_file: "/tmp/baremetal.csv"
test_vm_memory_size: "3072" test_vm_memory_size: "3072"
test_vm_num_nodes: "1" test_vm_num_nodes: 1
test_vm_domain_type: "qemu" test_vm_domain_type: "qemu"
test_vm_arch: "x86_64"
test_vm_disk_gib: "{{ lookup('env', 'VM_DISK') | default(10, true) }}"
test_vm_cpu_count: "{{ lookup('env', 'VM_CPU') | default(1, true) }}"
test_vm_disk_cache: "{{ lookup('env', 'VM_DISK_CACHE') | default('writeback', true) }}"
test_vm_node_name_base: "{{ lookup('env', 'NODEBASE') | default('testvm', true) }}"
test_vm_node_names: "{{ lookup('env', 'TEST_VM_NODE_NAMES').split() }}"
# NOTE(pas-ha) name and default are chosen to be the same
# as in 'bifrost-ironic-install' role
network_interface: "virbr0"
# NOTE(pas-ha) these correspond to settings for the libvirt network created by default
test_vm_network: "{{ lookup('env', 'VM_NET_BRIDGE') | default('default', true) }}"
test_vm_network_ip: "192.168.122.1"
test_vm_network_netmask: "255.255.255.0"
test_vm_network_enable_dhcp: true
test_vm_network_dhcp_start: "192.168.122.2"
test_vm_network_dhcp_end: "192.168.122.254"
test_vm_storage_pool: "{{ lookup('env', 'LIBVIRT_STORAGE_POOL') | default('default', true) }}"
test_vm_storage_pool_path: "/var/lib/libvirt/images"
test_vm_logdir: "/var/log/libvirt/baremetal_logs"
# NOTE(pas-ha) next two are generic values for most OSes, overriden by distro-specifc vars
test_vm_emulator: "/usr/bin/qemu-system-x86_64"
test_vm_machine: "pc-1.0"
# NOTE(pas-ha) not really tested whith non-local qemu connections
test_vm_libvirt_uri: "{{ lookup('env', 'LIBVIRT_CONNECT_URI') | default('qemu:///system', true) }}"

View File

@ -19,3 +19,7 @@ required_packages:
- libvirt-daemon-driver-secret - libvirt-daemon-driver-secret
- libvirt-daemon-driver-storage - libvirt-daemon-driver-storage
- libvirt-daemon-kvm - libvirt-daemon-kvm
- libvirt-python
- python-lxml
test_vm_machine: "pc"
test_vm_emulator: "/usr/libexec/qemu-kvm"

View File

@ -6,3 +6,5 @@ required_packages:
- qemu-kvm - qemu-kvm
- qemu-system-x86 - qemu-system-x86
- sgabios - sgabios
- python-libvirt
- python-lxml

View File

@ -11,3 +11,5 @@ required_packages:
- libvirt - libvirt
- libvirt-client - libvirt-client
- libvirt-daemon - libvirt-daemon
- python-libvirt
- python-lxml

View File

@ -8,3 +8,5 @@ required_packages:
- libvirt - libvirt
- libvirt-client - libvirt-client
- libvirt-daemon - libvirt-daemon
- libvirt-python
- python-lxml

View File

@ -1,282 +0,0 @@
#!/bin/bash
#############################################################################
# create_nodes.sh - Script to create VM nodes for use with Ironic.
#
# PURPOSE
# This script can be used to create VM instances without an operating
# system and that are ready for netbooting. They are connected to the
# bridge named 'brbm' (created if it does not exist).
#
# EXAMPLE USAGE
# # Use defaults - Create a single node with base name of 'testvm'
# sudo create_nodes.sh
#
# # Create 5 nodes
# sudo NODECOUNT=5 create_nodes.sh
#
# # Create 3 nodes with base name of 'junk'
# sudo NODEBASE=junk NODECOUNT=3 create_nodes.sh
#
# # Create 2 nodes that use KVM acceleration
# sudo VM_DOMAIN_TYPE=kvm NODECOUNT=2 create_nodes.sh
#
# # Create 3 nodes with different naming
# sudo TEST_VM_NODE_NAMES="controller00 compute00 compute01" create_nodes.sh
#
# THANKS
# Thanks to the author(s) of the ironic-supporting code within devstack,
# from which all of this is derived.
#
# AUTHOR
# David Shrewsbury (shrewsbury.dave@gmail.com)
#############################################################################
set -e # exit immediately on command error
set -u # treat unset variables as error when substituting
LIBVIRT_CONNECT_URI=${LIBVIRT_CONNECT_URI:-"qemu:///system"}
export VIRSH_DEFAULT_CONNECT_URI="$LIBVIRT_CONNECT_URI"
# VM specs
VM_DOMAIN_TYPE=${VM_DOMAIN_TYPE:-qemu}
VM_EMULATOR=${VM_EMULATOR:-/usr/bin/qemu-system-x86_64}
VM_CPU=${VM_CPU:-1}
VM_RAM=${VM_RAM:-3072}
VM_DISK=${VM_DISK:-10}
VM_MACHINE="pc-1.0"
VM_DISK_CACHE=${VM_DISK_CACHE:-writeback}
function is_distro {
local os_release=false
[[ -e /etc/os-release ]] && os_release=true
case "$1" in
centos) { $os_release && grep -q -i "centos" /etc/os-release; } || [[ -e /etc/centos-release ]] ;;
debian) { $os_release && grep -q -i "debian" /etc/os-release; } || [[ -e /etc/debian_version ]] ;;
suse) { $os_release && grep -q -i "suse" /etc/os-release; } || [[ -e /etc/SuSE-release ]] ;;
*) echo "Unsupported distribution '$1'" >&2; exit 1 ;;
esac
}
# CentOS provides a single emulator package
# which differs from other distributions, and
# needs to be explicitly set.
if is_distro "centos"; then
VM_EMULATOR=/usr/libexec/qemu-kvm
VM_MACHINE="pc"
fi
# VM network
VM_NET_BRIDGE=${VM_NET_BRIDGE:-default}
# VM logging directory
VM_LOGDIR=/var/log/libvirt/baremetal_logs
#############################################################################
# FUNCTION
# create_node
#
# PARAMETERS
# $1: Virtual machine name
# $2: Number of CPUs for the VM
# $3: Amount of RAM for the VM
# $4: Disk size (in GB) for the VM
# $5: CPU architecture (i386 or amd64)
# $6: Network bridge for the VMs
# $7: Path to VM emulator
# $8: Logging directory for the VMs
# $9: Domain type of the VM
#############################################################################
function create_node {
NAME=$1
CPU=$2
MEM=$(( 1024 * $3 ))
# extra G to allow fuzz for partition table : flavor size and registered
# size need to be different to actual size.
DISK=$(( $4 + 1))
DISK_CACHE=${10}
case $5 in
i386) ARCH='i686' ;;
amd64) ARCH='x86_64' ;;
*) echo "Unsupported arch $5!" >&2; exit 1 ;;
esac
BRIDGE=$6
EMULATOR=$7
LOGDIR=$8
DOMAIN_TYPE=$9
LIBVIRT_NIC_DRIVER=${LIBVIRT_NIC_DRIVER:-"e1000"}
LIBVIRT_STORAGE_POOL=${LIBVIRT_STORAGE_POOL:-"default"}
LIBVIRT_CONNECT_URI=${LIBVIRT_CONNECT_URI:-"qemu:///system"}
if ! virsh pool-list --all | grep -q $LIBVIRT_STORAGE_POOL; then
virsh pool-define-as --name $LIBVIRT_STORAGE_POOL dir --target /var/lib/libvirt/images >&2
virsh pool-autostart $LIBVIRT_STORAGE_POOL >&2
virsh pool-start $LIBVIRT_STORAGE_POOL >&2
fi
pool_state=$(virsh pool-info $LIBVIRT_STORAGE_POOL | grep State | awk '{ print $2 }')
if [ "$pool_state" != "running" ] ; then
[ ! -d /var/lib/libvirt/images ] && mkdir /var/lib/libvirt/images
virsh pool-start $LIBVIRT_STORAGE_POOL >&2
fi
if [ -n "$LOGDIR" ] ; then
mkdir -p "$LOGDIR"
if is_distro "centos" || is_distro "suse"; then
# NOTE(TheJulia): For some unknown reason, libvirt's log folder
# permissions on CentOS ship in an inoperable state. Users must
# be able to read a folder to open files in the folder structure.
chmod o+rx "$LOGDIR/.."
fi
fi
PREALLOC=
if is_distro "debian"; then
PREALLOC="--prealloc-metadata"
fi
VM_LOGGING="$LOGDIR/${NAME}_console.log"
VOL_NAME="${NAME}.qcow2"
if ! virsh list --all | grep -q $NAME; then
virsh vol-list --pool $LIBVIRT_STORAGE_POOL | grep -q $VOL_NAME &&
virsh vol-delete $VOL_NAME --pool $LIBVIRT_STORAGE_POOL >&2
virsh vol-create-as $LIBVIRT_STORAGE_POOL ${VOL_NAME} ${DISK}G --format qcow2 $PREALLOC >&2
volume_path=$(virsh vol-path --pool $LIBVIRT_STORAGE_POOL $VOL_NAME)
# Pre-touch the VM to set +C, as it can only be set on empty files.
touch "$volume_path"
# NOTE(TheJulia): CentOS default installs with an XFS root, and chattr
# fails to set +C on XFS. This could be more elegant, however the use
# case is for CI testing.
if ! is_distro "centos"; then
chattr +C "$volume_path" || true
fi
vm_xml="
<domain type='${DOMAIN_TYPE}'>
<name>${NAME}</name>
<memory unit='KiB'>${MEM}</memory>
<vcpu>${CPU}</vcpu>
<os>
<type arch='${ARCH}' machine='${VM_MACHINE}'>hvm</type>
<boot dev='network'/>
<bootmenu enable='no'/>
<bios useserial='yes' rebootTimeout='10000'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>${EMULATOR}</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='${DISK_CACHE}'/>
<source file='${volume_path}'/>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</disk>
<controller type='ide' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<interface type='network'>
<source network='${BRIDGE}'/>
</interface>
<input type='mouse' bus='ps2'/>
<graphics type='vnc' port='-1' autoport='yes'/>
<video>
<model type='cirrus' vram='9216' heads='1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
<serial type='file'>
<source path='${VM_LOGGING}'/>
<target port='0'/>
<alias name='serial0'/>
</serial>
<serial type='pty'>
<source path='/dev/pts/49'/>
<target port='1'/>
<alias name='serial1'/>
</serial>
<console type='file'>
<source path='${VM_LOGGING}'/>
<target type='serial' port='0'/>
<alias name='serial0'/>
</console>
<memballoon model='virtio'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
</memballoon>
</devices>
</domain>
"
local vm_tmpfile=$(mktemp -p /tmp vm.XXXX.xml)
# This is very unlikely to happen but still better safe than sorry
if [ $? != 0 ]; then
echo "Failed to create the temporary VM XML file"
exit 1
fi
echo ${vm_xml} > ${vm_tmpfile}
# NOTE(TheJulia): the create command powers on a VM that has been defined,
# where as define creates the VM, but does not change the power state.
virsh define ${vm_tmpfile} &>/dev/null
if [ $? != 0 ]
then
echo "failed to create VM $NAME" >&2
rm -f ${vm_tmpfile}
exit 1
fi
rm -f ${vm_tmpfile}
fi
# echo mac
local macaddr=`virsh dumpxml $NAME | grep "mac address" | head -1 | cut -d\' -f2`
echo $macaddr
}
####################
# Main script code
####################
NODEBASE=${NODEBASE:-testvm}
NODECOUNT=${NODECOUNT:-1}
TEST_VM_NODE_NAMES=${TEST_VM_NODE_NAMES:-""}
NODEOUTPUT=${NODEOUTPUT:-"/tmp/baremetal.csv"}
TEMPFILE=`mktemp`
# must be root
user=`whoami`
if [ "$user" != "root" ]
then
echo "Must be run as root. You are $user." >&2
exit 1
fi
for (( i=1; i<=${NODECOUNT}; i++ ))
do
if [ -z "${TEST_VM_NODE_NAMES}" ]; then
name=${NODEBASE}${i}
else
names=($TEST_VM_NODE_NAMES)
arrayindex=$(($i-1))
name=${names[$arrayindex]}
fi
mac=$(create_node $name $VM_CPU $VM_RAM $VM_DISK amd64 $VM_NET_BRIDGE $VM_EMULATOR $VM_LOGDIR $VM_DOMAIN_TYPE $VM_DISK_CACHE)
printf "$mac,root,undefined,192.168.122.1,$VM_CPU,$VM_RAM,$VM_DISK,flavor,type,a8cb6624-0d9f-c882-affc-046ebb96ec0${i},$name,192.168.122.$((i+1))\n" >>$TEMPFILE
done
mv "${TEMPFILE}" "${NODEOUTPUT}"

View File

@ -0,0 +1,119 @@
# Copyright (c) 2017 Mirantis Inc.
#
# 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.
# Create a VM and volume for it, save its MAC address
---
# NOTE(pas-ha) item here refers to name of the test vm
- set_fact:
vm_name: "{{ item }}"
vm_log_file: "{{ test_vm_logdir }}/{{ item }}_console.log"
- name: set prealloc arg for Debian
set_fact:
prealloc: "--prealloc-metadata"
when:
- "{{ ansible_os_family == 'Debian' }}"
- "{{ test_vm_libvirt_uri == 'qemu:///system' }}"
- name: list info on pools
virt_pool:
command: facts
uri: "{{ test_vm_libvirt_uri }}"
- name: list existing vms
virt:
command: list_vms
register: existing_vms
# NOTE(pas-ha) wrapping in block/rescue to have diagnostic output, requires Ansible>=2
- block:
# NOTE(pas-ha) Ansible still lacks modules to operate on libvirt volumes
# NOTE(pas-ha) adding extra 1G for disk size to accomodate for partition table / configdrive
- name: create volume for vm
command: >
virsh --connect {{ test_vm_libvirt_uri }}
vol-create-as {{ test_vm_storage_pool }} {{ vm_name }}.qcow2
{{ test_vm_disk_gib | int + 1 }}G
--format qcow2 {{ prealloc|default("") }}
when: "{{ vm_name + '.qcow2' not in ansible_libvirt_pools[test_vm_storage_pool].volumes }}"
- name: set path to the volume created
set_fact:
vm_volume_path: "{{ ansible_libvirt_pools[test_vm_storage_pool].path }}/{{ vm_name }}.qcow2"
- name: pre-touch the vm volume
file:
state: touch
path: "{{ vm_volume_path }}"
when: "{{ test_vm_libvirt_uri == 'qemu:///system' }}"
# NOTE(TheJulia): CentOS default installs with an XFS root, and chattr
# fails to set +C on XFS. This could be more elegant, however the use
# case is for CI testing.
- name: set copy-on-write for volume on non-CentOS systems
command: chattr +C {{ vm_volume_path }}
ignore_errors: yes
when:
- "{{ ansible_distribution != 'CentOS' }}"
- "{{ test_vm_libvirt_uri == 'qemu:///system' }}"
- name: create_vm
virt:
command: define
name: "{{ vm_name }}"
uri: "{{ test_vm_libvirt_uri }}"
xml: "{{ lookup('template', 'testvm.xml.j2') }}"
rescue:
- name: "Execute `dmesg` to collect debugging output should VM creation fail."
command: dmesg
- name: >
"Execute `virsh capabilities` to collect debugging output
should VM creation fail."
command: virsh capabilities
- name: "Abort due to failed VM creation"
fail: >
msg="VM creation step failed, please review dmesg
output for additional details"
when: "{{ vm_name not in existing_vms.list_vms }}"
- name: get XML of the vm
virt:
name: "{{ vm_name }}"
command: get_xml
register: testvm_xml
- name: get MAC from vm XML
set_fact:
vm_mac: "{{ (testvm_xml.get_xml | regex_findall(\"<mac address='.*'/>\") | first).split('=') | last | regex_replace(\"['/>]\", '') }}"
- name: set the csv entry for vm
set_fact:
vm_csv_items:
- "{{ vm_mac }}"
- "root"
- "undefined"
- "192.168.122.1"
- "{{ test_vm_cpu_count }}"
- "{{ test_vm_memory_size }}"
- "{{ test_vm_disk_gib }}"
- "flavor"
- "type"
- "a8cb6624-0d9f-c882-affc-046ebb96ec0{{ testvm_csv_data | length + 1 }}"
- "{{ vm_name }}"
- "192.168.122.{{ testvm_csv_data | length + 2 }}"
- name: add created vm info
set_fact:
testvm_csv_data: "{{ testvm_csv_data + [vm_csv_items] }}"

View File

@ -11,8 +11,6 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
#
# TODO: Consider converting to ansible virt module.
--- ---
# NOTE(cinerama) openSUSE Tumbleweed & Leap have different distribution # NOTE(cinerama) openSUSE Tumbleweed & Leap have different distribution
# IDs which are not currently accounted for in Ansible, so adjust facts # IDs which are not currently accounted for in Ansible, so adjust facts
@ -64,61 +62,48 @@
action: "{{ ansible_pkg_mgr }} name={{ item }} state=present" action: "{{ ansible_pkg_mgr }} name={{ item }} state=present"
with_items: "{{ required_packages }}" with_items: "{{ required_packages }}"
- name: "Restart libvirt service" - include: prepare_libvirt.yml
service: name="{{libvirt_service_name}}" state=restarted
- name: "Verify default network is running" - name: truncate explicit list of vm names
shell: virsh net-info default |grep Active|grep -q yes set_fact:
register: virsh_network_status test_vm_node_names: "{{ test_vm_node_names[:(test_vm_num_nodes|int)] }}"
delegate_to: localhost
ignore_errors: yes
- name: "Delete default network interface if not running" - name: generate test vm names
shell: ip link del $(virsh net-info default | awk '$1 == "Bridge:" { print $2 }') set_fact:
when: virsh_network_status.rc != 0 generated_test_vm_node_names: "{{ generated_test_vm_node_names|default([]) + [item] }}"
ignore_errors: yes with_sequence: count={{ test_vm_num_nodes | int }} format={{ test_vm_node_name_base }}%i
delegate_to: localhost when: "{{ test_vm_node_names | length == 0 }}"
- name: "Start default network if not running" - name: set test vm names
command: virsh net-start default set_fact:
when: virsh_network_status.rc != 0 test_vm_node_names: "{{ generated_test_vm_node_names }}"
register: task_start_default_net when: "{{ test_vm_node_names | length == 0 }}"
ignore_errors: yes
delegate_to: localhost
- name: "Fail if default network is not available" - name: create placeholder var for vm entries in CSV format
fail: set_fact:
msg: "Unable to verify the libvirt default network is available" testvm_csv_data: []
when: >
virsh_network_status.rc != 0 and
task_start_default_net.rc != 0
- name: "Create virtual machines" - include: create_vm.yml
script: create_vm_nodes-for-role.sh with_items: "{{ test_vm_node_names }}"
environment:
NODEOUTPUT: "{{baremetal_csv_file}}"
VM_RAM: "{{ test_vm_memory_size }}"
VM_DOMAIN_TYPE: "{{ test_vm_domain_type }}"
NODECOUNT: "{{ test_vm_num_nodes }}"
register: task_create_vm_nodes
ignore_errors: yes
delegate_to: localhost
- name: "Execute `dmesg` to collect debugging output should VM creation fail." - name: remove previous baremetal csv file
command: dmesg file:
when: task_create_vm_nodes.rc != 0 state: absent
path: "{{ baremetal_csv_file }}"
- name: > - name: create empty baremetal csv file
"Execute `virsh capabilities` to collect debugging output file:
should VM creation fail." state: touch
command: virsh capabilities path: "{{ baremetal_csv_file }}"
when: task_create_vm_nodes.rc != 0
- name: "Abort due to failed VM creation" # NOTE(pas-ha) this is a weird Ansible way to not flatten list of lists
fail: > - name: write to baremetal csv file
msg="VM creation step failed, please review dmesg lineinfile:
output for additional details" state: present
when: task_create_vm_nodes.rc != 0 name: "{{ baremetal_csv_file }}"
line: "{{ item | join(',') }}"
with_nested:
- "{{ testvm_csv_data }}"
- name: > - name: >
"Set file permissions such that the baremetal csv file at /tmp/baremetal.csv "Set file permissions such that the baremetal csv file at /tmp/baremetal.csv

View File

@ -0,0 +1,82 @@
# Copyright (c) 2017 Mirantis Inc.
#
# 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.
# Setup libvirt - ensure network and storage pool are defined and active,
# prepare dir for vm logs
---
- name: "Restart libvirt service"
service: name="{{libvirt_service_name}}" state=restarted
- name: ensure libvirt network is present
virt_net:
name: "{{ test_vm_network }}"
state: present
xml: "{{ lookup('template', 'net.xml.j2') }}"
uri: "{{ test_vm_libvirt_uri }}"
- name: find facts on libvirt networks
virt_net:
command: facts
uri: "{{ test_vm_libvirt_uri }}"
# NOTE(pas-ha) yet another place where non-local libvirt will not work
- name: "Delete network interface if virtual network is not active"
command: ip link del {{ ansible_libvirt_networks[test_vm_network].bridge }}
when:
- ansible_libvirt_networks[test_vm_network].state != 'active'
- test_vm_libvirt_uri == 'qemu:///system'
ignore_errors: yes
- name: set libvirt network to autostart
virt_net:
name: "{{ test_vm_network }}"
autostart: yes
uri: "{{ test_vm_libvirt_uri }}"
- name: ensure libvirt network is running
virt_net:
name: "{{ test_vm_network }}"
state: active
uri: "{{ test_vm_libvirt_uri }}"
- name: get libvirt network status
virt_net:
name: "{{ test_vm_network }}"
command: status
uri: "{{ test_vm_libvirt_uri }}"
register: test_vm_net_status
- name: fail if libvirt network is not active
assert:
that: test_vm_net_status.status == 'active'
- name: define a libvirt pool if not set
virt_pool:
name: "{{ test_vm_storage_pool }}"
state: present
uri: "{{ test_vm_libvirt_uri }}"
xml: "{{ lookup('template', 'pool_dir.xml.j2') }}"
- name: ensure libvirt pool is running
virt_pool:
name: "{{ test_vm_storage_pool }}"
state: active
autostart: yes
uri: "{{ test_vm_libvirt_uri }}"
- name: create dir for bm logs
file:
state: directory
path: "{{ test_vm_logdir }}"
mode: "o+rx"

View File

@ -0,0 +1,16 @@
<network>
<name>{{ test_vm_network }}</name>
<forward mode='nat'>
<nat>
<port start='1024' end='65535'/>
</nat>
</forward>
<bridge name='{{ network_interface }}' stp='on' delay='0'/>
<ip address='{{ test_vm_network_ip }}' netmask='{{ test_vm_network_netmask }}'>
{% if test_vm_network_enable_dhcp | bool %}
<dhcp>
<range start='{{ test_vm_network_dhcp_start }}' end='{{ test_vm_network_dhcp_end }}'/>
</dhcp>
{% endif %}
</ip>
</network>

View File

@ -0,0 +1,7 @@
<pool type='dir'>
<name>{{ test_vm_storage_pool }}</name>
<target>
<path>{{ test_vm_storage_pool_path }}</path>
</target>
</pool>

View File

@ -0,0 +1,59 @@
<domain type='{{ test_vm_domain_type }}'>
<name>{{ vm_name }}</name>
<memory unit='MiB'>{{ test_vm_memory_size }}</memory>
<vcpu>{{ test_vm_cpu_count }}</vcpu>
<os>
<type arch='{{ test_vm_arch }}' machine='{{ test_vm_machine }}'>hvm</type>
<boot dev='network'/>
<bootmenu enable='no'/>
<bios useserial='yes' rebootTimeout='10000'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>{{ test_vm_emulator }}</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='{{ test_vm_disk_cache }}'/>
<source file='{{ vm_volume_path }}'/>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</disk>
<controller type='ide' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<interface type='network'>
<source network='{{ test_vm_network }}'/>
</interface>
<input type='mouse' bus='ps2'/>
<graphics type='vnc' port='-1' autoport='yes'/>
<video>
<model type='cirrus' vram='9216' heads='1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
<serial type='file'>
<source path='{{ vm_log_file }}'/>
<target port='0'/>
<alias name='serial0'/>
</serial>
<serial type='pty'>
<source path='/dev/pts/49'/>
<target port='1'/>
<alias name='serial1'/>
</serial>
<console type='file'>
<source path='{{ vm_log_file }}'/>
<target type='serial' port='0'/>
<alias name='serial0'/>
</console>
<memballoon model='virtio'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
</memballoon>
</devices>
</domain>

View File

@ -0,0 +1,17 @@
---
features:
- |
``bifrost-create-vm-nodes`` role now uses Ansible's virt modules to
create virtual machines for bifrost testing.
This supersedes the embedded bash script to create virtual machines.
As a result, all variables that were present in the bash script are
now available as default role variables and can be overridden by standard
Ansible means.
For backward compatibility, some of the variables still support the
use of shell variables, but this is deprecated and should be avoided.
deprecations:
- |
Relying on shell environment variables to set parameters for created
virtual nodes is deprecated and will be removed in the Queens release.
Any scripts relying on such behavior need to be changed to explicitly
pass these parameters as extra-vars to ansible-playbook invocations.