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:
parent
4733aa3b37
commit
f888748d4e
@ -11,8 +11,20 @@ The following packages are required and ensured to be present:
|
||||
- qemu-utils
|
||||
- qemu-kvm
|
||||
- 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
|
||||
--------------
|
||||
|
||||
@ -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
|
||||
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
|
||||
------------
|
||||
|
||||
|
@ -2,5 +2,31 @@
|
||||
# defaults file for bifrost-create-vm-nodes
|
||||
baremetal_csv_file: "/tmp/baremetal.csv"
|
||||
test_vm_memory_size: "3072"
|
||||
test_vm_num_nodes: "1"
|
||||
test_vm_num_nodes: 1
|
||||
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) }}"
|
||||
|
@ -19,3 +19,7 @@ required_packages:
|
||||
- libvirt-daemon-driver-secret
|
||||
- libvirt-daemon-driver-storage
|
||||
- libvirt-daemon-kvm
|
||||
- libvirt-python
|
||||
- python-lxml
|
||||
test_vm_machine: "pc"
|
||||
test_vm_emulator: "/usr/libexec/qemu-kvm"
|
||||
|
@ -6,3 +6,5 @@ required_packages:
|
||||
- qemu-kvm
|
||||
- qemu-system-x86
|
||||
- sgabios
|
||||
- python-libvirt
|
||||
- python-lxml
|
||||
|
@ -11,3 +11,5 @@ required_packages:
|
||||
- libvirt
|
||||
- libvirt-client
|
||||
- libvirt-daemon
|
||||
- python-libvirt
|
||||
- python-lxml
|
||||
|
@ -8,3 +8,5 @@ required_packages:
|
||||
- libvirt
|
||||
- libvirt-client
|
||||
- libvirt-daemon
|
||||
- libvirt-python
|
||||
- python-lxml
|
||||
|
@ -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}"
|
119
playbooks/roles/bifrost-create-vm-nodes/tasks/create_vm.yml
Normal file
119
playbooks/roles/bifrost-create-vm-nodes/tasks/create_vm.yml
Normal 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] }}"
|
@ -11,8 +11,6 @@
|
||||
# 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.
|
||||
#
|
||||
# TODO: Consider converting to ansible virt module.
|
||||
---
|
||||
# NOTE(cinerama) openSUSE Tumbleweed & Leap have different distribution
|
||||
# IDs which are not currently accounted for in Ansible, so adjust facts
|
||||
@ -64,61 +62,48 @@
|
||||
action: "{{ ansible_pkg_mgr }} name={{ item }} state=present"
|
||||
with_items: "{{ required_packages }}"
|
||||
|
||||
- name: "Restart libvirt service"
|
||||
service: name="{{libvirt_service_name}}" state=restarted
|
||||
- include: prepare_libvirt.yml
|
||||
|
||||
- name: "Verify default network is running"
|
||||
shell: virsh net-info default |grep Active|grep -q yes
|
||||
register: virsh_network_status
|
||||
delegate_to: localhost
|
||||
ignore_errors: yes
|
||||
- name: truncate explicit list of vm names
|
||||
set_fact:
|
||||
test_vm_node_names: "{{ test_vm_node_names[:(test_vm_num_nodes|int)] }}"
|
||||
|
||||
- name: "Delete default network interface if not running"
|
||||
shell: ip link del $(virsh net-info default | awk '$1 == "Bridge:" { print $2 }')
|
||||
when: virsh_network_status.rc != 0
|
||||
ignore_errors: yes
|
||||
delegate_to: localhost
|
||||
- name: generate test vm names
|
||||
set_fact:
|
||||
generated_test_vm_node_names: "{{ generated_test_vm_node_names|default([]) + [item] }}"
|
||||
with_sequence: count={{ test_vm_num_nodes | int }} format={{ test_vm_node_name_base }}%i
|
||||
when: "{{ test_vm_node_names | length == 0 }}"
|
||||
|
||||
- name: "Start default network if not running"
|
||||
command: virsh net-start default
|
||||
when: virsh_network_status.rc != 0
|
||||
register: task_start_default_net
|
||||
ignore_errors: yes
|
||||
delegate_to: localhost
|
||||
- name: set test vm names
|
||||
set_fact:
|
||||
test_vm_node_names: "{{ generated_test_vm_node_names }}"
|
||||
when: "{{ test_vm_node_names | length == 0 }}"
|
||||
|
||||
- name: "Fail if default network is not available"
|
||||
fail:
|
||||
msg: "Unable to verify the libvirt default network is available"
|
||||
when: >
|
||||
virsh_network_status.rc != 0 and
|
||||
task_start_default_net.rc != 0
|
||||
- name: create placeholder var for vm entries in CSV format
|
||||
set_fact:
|
||||
testvm_csv_data: []
|
||||
|
||||
- name: "Create virtual machines"
|
||||
script: create_vm_nodes-for-role.sh
|
||||
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
|
||||
- include: create_vm.yml
|
||||
with_items: "{{ test_vm_node_names }}"
|
||||
|
||||
- name: "Execute `dmesg` to collect debugging output should VM creation fail."
|
||||
command: dmesg
|
||||
when: task_create_vm_nodes.rc != 0
|
||||
- name: remove previous baremetal csv file
|
||||
file:
|
||||
state: absent
|
||||
path: "{{ baremetal_csv_file }}"
|
||||
|
||||
- name: >
|
||||
"Execute `virsh capabilities` to collect debugging output
|
||||
should VM creation fail."
|
||||
command: virsh capabilities
|
||||
when: task_create_vm_nodes.rc != 0
|
||||
- name: create empty baremetal csv file
|
||||
file:
|
||||
state: touch
|
||||
path: "{{ baremetal_csv_file }}"
|
||||
|
||||
- name: "Abort due to failed VM creation"
|
||||
fail: >
|
||||
msg="VM creation step failed, please review dmesg
|
||||
output for additional details"
|
||||
when: task_create_vm_nodes.rc != 0
|
||||
# NOTE(pas-ha) this is a weird Ansible way to not flatten list of lists
|
||||
- name: write to baremetal csv file
|
||||
lineinfile:
|
||||
state: present
|
||||
name: "{{ baremetal_csv_file }}"
|
||||
line: "{{ item | join(',') }}"
|
||||
with_nested:
|
||||
- "{{ testvm_csv_data }}"
|
||||
|
||||
- name: >
|
||||
"Set file permissions such that the baremetal csv file at /tmp/baremetal.csv
|
||||
|
@ -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"
|
16
playbooks/roles/bifrost-create-vm-nodes/templates/net.xml.j2
Normal file
16
playbooks/roles/bifrost-create-vm-nodes/templates/net.xml.j2
Normal 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>
|
@ -0,0 +1,7 @@
|
||||
<pool type='dir'>
|
||||
<name>{{ test_vm_storage_pool }}</name>
|
||||
<target>
|
||||
<path>{{ test_vm_storage_pool_path }}</path>
|
||||
</target>
|
||||
</pool>
|
||||
|
@ -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>
|
17
releasenotes/notes/ansible-virt-0759a857daaacccf.yaml
Normal file
17
releasenotes/notes/ansible-virt-0759a857daaacccf.yaml
Normal 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.
|
Loading…
Reference in New Issue
Block a user