diff --git a/playbooks/roles/bifrost-create-vm-nodes/README.md b/playbooks/roles/bifrost-create-vm-nodes/README.md
index 1abbb9503..bb16b7720 100644
--- a/playbooks/roles/bifrost-create-vm-nodes/README.md
+++ b/playbooks/roles/bifrost-create-vm-nodes/README.md
@@ -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
------------
diff --git a/playbooks/roles/bifrost-create-vm-nodes/defaults/main.yml b/playbooks/roles/bifrost-create-vm-nodes/defaults/main.yml
index 42bf5330e..d9c345cbc 100644
--- a/playbooks/roles/bifrost-create-vm-nodes/defaults/main.yml
+++ b/playbooks/roles/bifrost-create-vm-nodes/defaults/main.yml
@@ -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) }}"
diff --git a/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_CentOS.yml b/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_CentOS.yml
index 163aaf6aa..713409950 100644
--- a/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_CentOS.yml
+++ b/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_CentOS.yml
@@ -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"
diff --git a/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_Debian.yml b/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_Debian.yml
index e1e4149a5..2629df120 100644
--- a/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_Debian.yml
+++ b/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_Debian.yml
@@ -6,3 +6,5 @@ required_packages:
- qemu-kvm
- qemu-system-x86
- sgabios
+ - python-libvirt
+ - python-lxml
diff --git a/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_RedHat.yml b/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_RedHat.yml
index ec00eac3c..ada9de9ba 100644
--- a/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_RedHat.yml
+++ b/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_RedHat.yml
@@ -11,3 +11,5 @@ required_packages:
- libvirt
- libvirt-client
- libvirt-daemon
+ - python-libvirt
+ - python-lxml
diff --git a/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_Suse.yml b/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_Suse.yml
index a9b18fa3a..a195eac9b 100644
--- a/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_Suse.yml
+++ b/playbooks/roles/bifrost-create-vm-nodes/defaults/required_defaults_Suse.yml
@@ -8,3 +8,5 @@ required_packages:
- libvirt
- libvirt-client
- libvirt-daemon
+ - libvirt-python
+ - python-lxml
diff --git a/playbooks/roles/bifrost-create-vm-nodes/files/create_vm_nodes-for-role.sh b/playbooks/roles/bifrost-create-vm-nodes/files/create_vm_nodes-for-role.sh
deleted file mode 100755
index a271006a3..000000000
--- a/playbooks/roles/bifrost-create-vm-nodes/files/create_vm_nodes-for-role.sh
+++ /dev/null
@@ -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="
-
- ${NAME}
- ${MEM}
- ${CPU}
-
- hvm
-
-
-
-
-
-
-
-
-
-
- destroy
- restart
- restart
-
- ${EMULATOR}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-"
-
- 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}"
diff --git a/playbooks/roles/bifrost-create-vm-nodes/tasks/create_vm.yml b/playbooks/roles/bifrost-create-vm-nodes/tasks/create_vm.yml
new file mode 100644
index 000000000..f2d947740
--- /dev/null
+++ b/playbooks/roles/bifrost-create-vm-nodes/tasks/create_vm.yml
@@ -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(\"\") | 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] }}"
diff --git a/playbooks/roles/bifrost-create-vm-nodes/tasks/main.yml b/playbooks/roles/bifrost-create-vm-nodes/tasks/main.yml
index cd3772c52..bcd487dc7 100644
--- a/playbooks/roles/bifrost-create-vm-nodes/tasks/main.yml
+++ b/playbooks/roles/bifrost-create-vm-nodes/tasks/main.yml
@@ -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,68 +62,55 @@
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
can be read by the user executing Ansible"
file:
- path: "{{baremetal_csv_file}}"
- owner: "{{ansible_env.SUDO_USER}}"
+ path: "{{ baremetal_csv_file }}"
+ owner: "{{ ansible_env.SUDO_USER }}"
when: >
ansible_env.SUDO_USER is defined and
baremetal_csv_file is defined and
diff --git a/playbooks/roles/bifrost-create-vm-nodes/tasks/prepare_libvirt.yml b/playbooks/roles/bifrost-create-vm-nodes/tasks/prepare_libvirt.yml
new file mode 100644
index 000000000..7347e11ad
--- /dev/null
+++ b/playbooks/roles/bifrost-create-vm-nodes/tasks/prepare_libvirt.yml
@@ -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"
diff --git a/playbooks/roles/bifrost-create-vm-nodes/templates/net.xml.j2 b/playbooks/roles/bifrost-create-vm-nodes/templates/net.xml.j2
new file mode 100644
index 000000000..ba06f18be
--- /dev/null
+++ b/playbooks/roles/bifrost-create-vm-nodes/templates/net.xml.j2
@@ -0,0 +1,16 @@
+
+ {{ test_vm_network }}
+
+
+
+
+
+
+
+ {% if test_vm_network_enable_dhcp | bool %}
+
+
+
+ {% endif %}
+
+
diff --git a/playbooks/roles/bifrost-create-vm-nodes/templates/pool_dir.xml.j2 b/playbooks/roles/bifrost-create-vm-nodes/templates/pool_dir.xml.j2
new file mode 100644
index 000000000..cddca3f68
--- /dev/null
+++ b/playbooks/roles/bifrost-create-vm-nodes/templates/pool_dir.xml.j2
@@ -0,0 +1,7 @@
+
+ {{ test_vm_storage_pool }}
+
+ {{ test_vm_storage_pool_path }}
+
+
+
diff --git a/playbooks/roles/bifrost-create-vm-nodes/templates/testvm.xml.j2 b/playbooks/roles/bifrost-create-vm-nodes/templates/testvm.xml.j2
new file mode 100644
index 000000000..a2de6b167
--- /dev/null
+++ b/playbooks/roles/bifrost-create-vm-nodes/templates/testvm.xml.j2
@@ -0,0 +1,59 @@
+
+ {{ vm_name }}
+ {{ test_vm_memory_size }}
+ {{ test_vm_cpu_count }}
+
+ hvm
+
+
+
+
+
+
+
+
+
+
+ destroy
+ restart
+ restart
+
+ {{ test_vm_emulator }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/releasenotes/notes/ansible-virt-0759a857daaacccf.yaml b/releasenotes/notes/ansible-virt-0759a857daaacccf.yaml
new file mode 100644
index 000000000..237884af7
--- /dev/null
+++ b/releasenotes/notes/ansible-virt-0759a857daaacccf.yaml
@@ -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.