From f888748d4e71c0a59107451049cb71b7d42c7ed7 Mon Sep 17 00:00:00 2001 From: Pavlo Shchelokovskyy Date: Tue, 31 Jan 2017 11:12:16 +0200 Subject: [PATCH] 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 --- .../roles/bifrost-create-vm-nodes/README.md | 119 ++++++++ .../bifrost-create-vm-nodes/defaults/main.yml | 28 +- .../defaults/required_defaults_CentOS.yml | 4 + .../defaults/required_defaults_Debian.yml | 2 + .../defaults/required_defaults_RedHat.yml | 2 + .../defaults/required_defaults_Suse.yml | 2 + .../files/create_vm_nodes-for-role.sh | 282 ------------------ .../tasks/create_vm.yml | 119 ++++++++ .../bifrost-create-vm-nodes/tasks/main.yml | 87 +++--- .../tasks/prepare_libvirt.yml | 82 +++++ .../templates/net.xml.j2 | 16 + .../templates/pool_dir.xml.j2 | 7 + .../templates/testvm.xml.j2 | 59 ++++ .../notes/ansible-virt-0759a857daaacccf.yaml | 17 ++ 14 files changed, 492 insertions(+), 334 deletions(-) delete mode 100755 playbooks/roles/bifrost-create-vm-nodes/files/create_vm_nodes-for-role.sh create mode 100644 playbooks/roles/bifrost-create-vm-nodes/tasks/create_vm.yml create mode 100644 playbooks/roles/bifrost-create-vm-nodes/tasks/prepare_libvirt.yml create mode 100644 playbooks/roles/bifrost-create-vm-nodes/templates/net.xml.j2 create mode 100644 playbooks/roles/bifrost-create-vm-nodes/templates/pool_dir.xml.j2 create mode 100644 playbooks/roles/bifrost-create-vm-nodes/templates/testvm.xml.j2 create mode 100644 releasenotes/notes/ansible-virt-0759a857daaacccf.yaml 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} - - - - -
- - -
- - - - - - -