From 2422a081a5be0d5ac5afb122361bc283da67341f Mon Sep 17 00:00:00 2001 From: Pavel Raiskup Date: Wed, 22 Oct 2014 08:54:05 +0200 Subject: big reorg: prepare for generalization Try to split into three separate components -> controller, tester, and 'tasks' (postgresql-tasks in our case). The controller component is the main part which is able to run the task remotely. Tester is more-like library for 'tasks' component (should be reusable on the raw git level). * controller: Almost separated component. * postgresql-tasks: Likewise. * tester: Likewise. --- controller | 70 -------------- controller/ansible/dummy-wrapper.yml | 7 ++ controller/ansible/fedora.yml | 64 +++++++++++++ controller/ansible/include/additional-packages.yml | 6 ++ controller/ansible/include/beakerlib.yml | 1 + controller/ansible/include/download-results.yml | 5 + controller/ansible/include/prepare-testenv.yml | 3 + controller/ansible/run_include | 19 ++++ controller/ansible_helpers/wait-for-ssh | 11 +++ controller/config/.gitignore | 2 + controller/config/config.sh.template | 36 ++++++++ controller/config/hosts.template | 2 + controller/config/os/EXAMPLE.sh | 20 ++++ controller/controller | 73 +++++++++++++++ controller/get_machine | 85 +++++++++++++++++ controller/parse_credsfile | 14 +++ controller/private/os/EXAMPLE.yml | 7 ++ controller/result_stats | 74 +++++++++++++++ controller/result_templates/html.tmpl | 42 +++++++++ controller/run_remote | 101 +++++++++++++++++++++ 20 files changed, 572 insertions(+), 70 deletions(-) delete mode 100755 controller create mode 100644 controller/ansible/dummy-wrapper.yml create mode 100644 controller/ansible/fedora.yml create mode 100644 controller/ansible/include/additional-packages.yml create mode 100644 controller/ansible/include/beakerlib.yml create mode 100644 controller/ansible/include/download-results.yml create mode 100644 controller/ansible/include/prepare-testenv.yml create mode 100755 controller/ansible/run_include create mode 100755 controller/ansible_helpers/wait-for-ssh create mode 100644 controller/config/.gitignore create mode 100644 controller/config/config.sh.template create mode 100644 controller/config/hosts.template create mode 100644 controller/config/os/EXAMPLE.sh create mode 100755 controller/controller create mode 100755 controller/get_machine create mode 100644 controller/parse_credsfile create mode 100644 controller/private/os/EXAMPLE.yml create mode 100755 controller/result_stats create mode 100644 controller/result_templates/html.tmpl create mode 100755 controller/run_remote (limited to 'controller') diff --git a/controller b/controller deleted file mode 100755 index 7f628d6..0000000 --- a/controller +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash - -. config/config.sh || { - echo >&2 "sorry, but config/config.sh not found" - exit 1 -} - -# (still) local variables -distro=fedora -distro_ver=20 -arch=x86_64 -starttime=$(date -u +%Y%m%d_%H%M%S_%N) - -die() { echo "$@"; exit 1; } - -prereq_resultdir() -{ - test -d "$DTF_DATABASE" || mkdir -p "$DTF_DATABASE" -} - -unpack_results() -{ - local where="$1" - local tmp_results_dir="$2" - - local workdir=$(mktemp -d "/tmp/.dtf.XXXXXX") || die "can not create workdir" - - { pushd "$workdir" >/dev/null \ - && tar -xf "$tmp_results_dir/dtf.tar.gz" \ - && pushd dtf >/dev/null - } || die "can not unpack results" - - for i in *.log; do - local task_id="${i%%.log}" - local mydir="" - - # First item in tarball is the "main" directory - while read dirname; do - test -z "$mydir" && mydir="$dirname" - done <<<"$(tar xvf "$task_id.tar.gz")" - - # Give the unpacked results better name - rm "$task_id.tar.gz" - mv "$mydir" "$task_id.dir" - done - - { popd && popd ; } > /dev/null - - { mkdir -p "$(dirname "$where")" \ - && mv "$workdir/dtf" "$where" ; - } || die "can not create resultdir" -} - -prereq_resultdir - -workdir=$(mktemp -d "/var/tmp/dtf_postgresql_setup-XXXXXX") - -./run_remote \ - --distro="$distro" \ - --distro-version="$distro_ver" \ - --workdir="$workdir" \ - --openstack-instance="$DTF_OPENSTACK_ID" \ -|| die "can not perform run_remote" - -resultdir="$DTF_DATABASE/$distro/$distro_ver/$arch" -unpack_results "$resultdir/result_$starttime" "$workdir" - -./runner/result_stats "$resultdir" > "$resultdir/results.html" - -rsync -r "${DTF_DATABASE%%/}/" "${DTF_PRESENTER_PLACE%%/}" diff --git a/controller/ansible/dummy-wrapper.yml b/controller/ansible/dummy-wrapper.yml new file mode 100644 index 0000000..524b0ea --- /dev/null +++ b/controller/ansible/dummy-wrapper.yml @@ -0,0 +1,7 @@ +- name: "dummy-wrapper" + hosts: "{{ target }}" + remote_user: root + gather_facts: False + + tasks: + - include: "{{ include_file }}" diff --git a/controller/ansible/fedora.yml b/controller/ansible/fedora.yml new file mode 100644 index 0000000..cc64eac --- /dev/null +++ b/controller/ansible/fedora.yml @@ -0,0 +1,64 @@ +- name: self-standing testsuite + remote_user: root + gather_facts: False + hosts: localhost + vars_files: + - "{{ opt_credsfile }}" + + tasks: + - name: generate builder name + local_action: shell echo `dd if=/dev/urandom bs=1k count=10 | md5sum ; echo DBTESTS` + register: vm_name + + - debug: msg="osusername={{ os_username }}" + + - name: spin it up + local_action: nova_compute auth_url={{os_auth_url}} + flavor_id={{os_flavor_id}} image_id="{{ os_image_id }}" key_name={{ os_keypair }} + login_password={{os_nova_password}} login_tenant_name="{{os_tenant_name}}" + login_username={{os_username}} security_groups={{os_security_group}} + wait=yes name="{{vm_name.stdout}}" wait_for=600 + register: nova + + - debug: msg="{{ nova.info.addresses }}" + + # This is ugly as hell... Hopefully nothing will be changing. + - local_action: command echo "{{ nova.info.addresses[os_network_dev][1].addr }}" + register: machine_ip + + - debug: msg="{{ machine_ip.stdout }}" + + - name: wait for the host to be hot + local_action: wait_for host={{ machine_ip.stdout }} port=22 delay=5 timeout=600 + + - local_action: shell ../ansible_helpers/wait-for-ssh "root@{{ machine_ip.stdout }}" + + - name: add it to the special group + local_action: add_host hostname={{ machine_ip.stdout }} + groupname=temp_group + +- hosts: temp_group + user: root + gather_facts: False + tasks: + - copy: src={{ opt_workdir }}/{{ opt_testsuite_name }}.tar.gz + dest=/root/{{ opt_testsuite_name }}.tar.gz + + - include: include/beakerlib.yml + + - include: include/prepare-testenv.yml + + - include: include/additional-packages.yml + when: dtf_rpm_files_list is defined + + - shell: cd /root && tar -xf {{ opt_testsuite_name }}.tar.gz + + - shell: cd /root/{{ opt_testsuite_name }}&& ./run &>/var/tmp/dtf-run.overview + register: test_result + ignore_errors: yes + + - include: include/download-results.yml + + - name: stop the vm + shell: echo "not implemented yet" + when: test_result.rc == 0 diff --git a/controller/ansible/include/additional-packages.yml b/controller/ansible/include/additional-packages.yml new file mode 100644 index 0000000..f821255 --- /dev/null +++ b/controller/ansible/include/additional-packages.yml @@ -0,0 +1,6 @@ +- local_action: shell cat "{{ dtf_rpm_files_list }}" | xargs -n 100 + register: additional_packages + +- debug: msg="{{ additional_packages.stdout }}" + +- shell: yum install -y {{ additional_packages.stdout }} diff --git a/controller/ansible/include/beakerlib.yml b/controller/ansible/include/beakerlib.yml new file mode 100644 index 0000000..0461f25 --- /dev/null +++ b/controller/ansible/include/beakerlib.yml @@ -0,0 +1 @@ +- yum: conf_file=https://beaker-project.org/yum/beaker-server-Fedora.repo state=present name=beakerlib diff --git a/controller/ansible/include/download-results.yml b/controller/ansible/include/download-results.yml new file mode 100644 index 0000000..4404e08 --- /dev/null +++ b/controller/ansible/include/download-results.yml @@ -0,0 +1,5 @@ +- shell: cp -f /var/tmp/dtf-run.overview /var/tmp/dtf/ + +- shell: cd /var/tmp ; tar -czf dtf.tar.gz dtf + +- fetch: src=/var/tmp/dtf.tar.gz dest="{{ opt_workdir }}/" flat=yes diff --git a/controller/ansible/include/prepare-testenv.yml b/controller/ansible/include/prepare-testenv.yml new file mode 100644 index 0000000..a63e51a --- /dev/null +++ b/controller/ansible/include/prepare-testenv.yml @@ -0,0 +1,3 @@ +- yum: state=present name=postgresql-server + +- yum: state=present name=postgresql-upgrade diff --git a/controller/ansible/run_include b/controller/ansible/run_include new file mode 100755 index 0000000..4e84c7d --- /dev/null +++ b/controller/ansible/run_include @@ -0,0 +1,19 @@ +#!/bin/bash + +export ANSIBLE_HOST_KEY_CHECKING=False + +workdir="$(dirname "${BASH_SOURCE[0]}")" +workdir=$(readlink -f "$workdir") + +export playbook=$(readlink -f "$1") + +( set -x + cd "$workdir" + + ansible-playbook -i "$workdir/../config/hosts" \ + --extra-vars "include_file=$playbook" \ + --extra-vars "script_name=dummy" \ + --extra-vars "opt_workdir=/tmp/dtf-$(date +%H%M%S%N)" \ + --extra-vars "target=host" \ + "dummy-wrapper.yml" +) diff --git a/controller/ansible_helpers/wait-for-ssh b/controller/ansible_helpers/wait-for-ssh new file mode 100755 index 0000000..eb3880a --- /dev/null +++ b/controller/ansible_helpers/wait-for-ssh @@ -0,0 +1,11 @@ +#!/bin/bash -x + +where="$1" + +test -z "$where" && echo >&2 "no host specified" && exit 1 + +while [ 1 ]; do + ssh -o StrictHostKeyChecking=no -q $where exit &>/dev/null && exit 0 +done + +exit 1 diff --git a/controller/config/.gitignore b/controller/config/.gitignore new file mode 100644 index 0000000..57c4fcb --- /dev/null +++ b/controller/config/.gitignore @@ -0,0 +1,2 @@ +*.sh +hosts diff --git a/controller/config/config.sh.template b/controller/config/config.sh.template new file mode 100644 index 0000000..94cbe22 --- /dev/null +++ b/controller/config/config.sh.template @@ -0,0 +1,36 @@ +# OpenStack ID +# ------------ +# +# By default, based on DTF_OPENSTACK_ID content the corresponding OpenStack +# configuration is used. You may have multiple OpenStack instances configured - +# this option selects one. Based on the OpenStack ID (say 'EXAMPLE'), those +# configuration-like files are used: +# +# * private/os/'EXAMPLE'.yml +# File having OpenStack credentials in ansible variable file (YAML file +# with "key: value" lines). See the ./private/os/EXAMPLE.yml for +# variables you should set up. Keep this file secret. +# +# * config/os/'EXAMPLE'.sh +# This file must contain configuration for specific OpenStack instance. +# Usually information about available images, flavors, networking, etc. +# The template file config/os/EXAMPLE.sh may be used when configuring your +# testing environment. + +export DTF_OPENSTACK_ID=dropbear + +# Result Database +# --------------- +# Directory where the testsuite should keep its (persistent) results. Make sure +# that this directory is backed up. + +export DTF_DATABASE=/var/lib/dtf_results + +# Presenter place +# --------------- +# For now, only static results are available. DTF_PRESENTER_PLACE must contain +# rsync-compatible destination (it may be place accessible via ssh+rsync). It +# is expected that some httpd server is able to read the directory with results +# and publish them as static directory structure over http://. + +export DTF_PRESENTER_PLACE=user@example.org:/var/www/html/my_project/dtf diff --git a/controller/config/hosts.template b/controller/config/hosts.template new file mode 100644 index 0000000..6850700 --- /dev/null +++ b/controller/config/hosts.template @@ -0,0 +1,2 @@ +[host] +10.64.27.30 diff --git a/controller/config/os/EXAMPLE.sh b/controller/config/os/EXAMPLE.sh new file mode 100644 index 0000000..b5ba270 --- /dev/null +++ b/controller/config/os/EXAMPLE.sh @@ -0,0 +1,20 @@ +## THIS IS EXAMPLE OPENSTACK DTF CONFIGURATION ## + +# variable declarations, should be C&Ped +declare -A os_flavor_ids os_image_ids +export os_flavor_ids=[] +export os_image_ids=[] + +# connection info about particular OpenStack instance + +# which ssh keys should be uploaded to created VMs +export os_keypair="keypair-id" +# group of firewall rules to be set on VMs +export os_security_group=test_group +# the name of network connection as is presented by ansible +export os_network_dev=network_name + +# per-distribution dictionary with images/flavors +os_flavor_ids["fedora20"]="2" +os_image_ids["fedora20"]="0461eef2-5921-4c01-95a6-6edf96d41b89" + diff --git a/controller/controller b/controller/controller new file mode 100755 index 0000000..e0cffe9 --- /dev/null +++ b/controller/controller @@ -0,0 +1,73 @@ +#!/bin/bash + +. config/config.sh || { + echo >&2 "sorry, but config/config.sh not found" + exit 1 +} + +# (still) local variables +distro=fedora +distro_ver=21 +arch=x86_64 +starttime=$(date -u +%Y%m%d_%H%M%S_%N) + +die() { echo "$@"; exit 1; } + +prereq_resultdir() +{ + test -d "$DTF_DATABASE" || mkdir -p "$DTF_DATABASE" +} + +unpack_results() +{ + local where="$1" + local tmp_results_dir="$2" + + local workdir=$(mktemp -d "/tmp/.dtf.XXXXXX") || die "can not create workdir" + + { pushd "$workdir" >/dev/null \ + && tar -xf "$tmp_results_dir/dtf.tar.gz" \ + && pushd dtf >/dev/null + } || die "can not unpack results" + + for i in *.log; do + local task_id="${i%%.log}" + local mydir="" + + # First item in tarball is the "main" directory + while read dirname; do + test -z "$mydir" && mydir="$dirname" + done <<<"$(tar xvf "$task_id.tar.gz")" + + # Give the unpacked results better name + rm "$task_id.tar.gz" + mv "$mydir" "$task_id.dir" + done + + { popd && popd ; } > /dev/null + + { mkdir -p "$(dirname "$where")" \ + && mv "$workdir/dtf" "$where" ; + } || die "can not create resultdir" +} + +prereq_resultdir + +workdir=$(mktemp -d "/var/tmp/dtf_postgresql_setup-XXXXXX") + +# cp /var/tmp/dtf_postgresql_setup-yK12r7/dtf.tar.gz "$workdir" +./run_remote \ + --distro="$distro" \ + --distro-version="$distro_ver" \ + --workdir="$workdir" \ + --openstack-instance="$DTF_OPENSTACK_ID" \ + "$(test -f additional_packages \ + && echo '--extra-rpms-file=additional_packages')" \ +|| die "can not perform run_remote" + +resultdir="$DTF_DATABASE/$distro/$distro_ver/$arch" +unpack_results "$resultdir/result_$starttime" "$workdir" + +./runner/result_stats "$resultdir" > "$resultdir/results.html" + +rsync -r "${DTF_DATABASE%%/}/" "${DTF_PRESENTER_PLACE%%/}" diff --git a/controller/get_machine b/controller/get_machine new file mode 100755 index 0000000..7d4e619 --- /dev/null +++ b/controller/get_machine @@ -0,0 +1,85 @@ +#!/bin/bash + +die() { echo "$@" ; exit 1 ; } +info() { echo " * $@" ; } + +opt_openstack_instance=os1 +opt_distro=fedora +opt_distro_version=20 + +function show_help() +{ +cat <&2 +Usage: $0 OPTION + +Script is aimed to help sysadmin. + +Options: + --distro=NAME Distro name, like fedora + --distro-version=VERSION E.g. 20 for Fedora 20 + --openstack-instance=ID +EOHELP +test -n "$1" && exit "$1" +} + +boot() +( + set -o pipefail + nova boot "$1" --poll \ + --image "$2" \ + --flavor "$3" \ + --security-groups "$os_security_group" \ + --key-name "$os_keypair" \ + | grep "| id " | cut -d\| -f 3 | xargs -n 1 +) + +get_ip() +( + id="$1" + set -o pipefail + nova show "$id" | grep ' network ' \ + | cut -d\| -f 3 | cut -d, -f2 | xargs -n 1 +) + + +longopts="distro:,distro-version:,openstack-instance:" +ARGS=$(getopt -o "" -l "help,$longopts" -n "$0" -- "$@") \ + || exit 1 +eval set -- "$ARGS" + +while true; do + case "$1" in + --distro|--distro-version|--openstack-instance) + opt=$(sed -e 's/^--//' -e 's/[^[a-zA-Z0-9]/_/g'<<<"$1") + eval "opt_$opt=\"${2,,}\"" + shift 2 + ;; + + --help) + show_help 0 + ;; + + --) + shift + break; + esac +done + +. ./parse_credsfile "$opt_openstack_instance" || exit 1 +. ./config/os/"$opt_openstack_instance.sh" || exit 1 + +image_version=$opt_distro$opt_distro_version +image=${os_image_ids[$image_version]} +flavor=${os_flavor_ids[$image_version]} + +test -z "$image" && die "no image for '$image_version'" +test -z "$flavor" && die "no flavor for '$image_version'" + +info "booting machine $image_version from $image" + +machine=$(boot "testing-$image" "$image" "$flavor") + +info "machine id: $machine" + +ip=$(get_ip "$machine") +info "ip: $ip" diff --git a/controller/parse_credsfile b/controller/parse_credsfile new file mode 100644 index 0000000..df2a6bf --- /dev/null +++ b/controller/parse_credsfile @@ -0,0 +1,14 @@ +credsfile="private/os/$1.yml" + +while read line; do + if [[ "$line" =~ ^([a-zA-Z0-9_]*):\ ?(.*)$ ]]; then + key="${BASH_REMATCH[1]}" + if test "$key" = os_nova_password; then + key=os_password + fi + eval set ${BASH_REMATCH[2]} + eval export "${key^^}"="\"$@\"" + fi +done < "$credsfile" + +# vi: syntax=sh diff --git a/controller/private/os/EXAMPLE.yml b/controller/private/os/EXAMPLE.yml new file mode 100644 index 0000000..d44cbac --- /dev/null +++ b/controller/private/os/EXAMPLE.yml @@ -0,0 +1,7 @@ +## THIS IS EXAMPLE OPENSTACK CREDENTIALS FILE ## +--- +os_auth_url: http://openstack-controller.example.com:5000/v2.0 +os_tenant_id: 8289c1553643c7adf3476fb6234562c0 +os_tenant_name: Example Develpoment Group +os_username: jdoe +os_nova_password: plainPasswordKeepSecrete diff --git a/controller/result_stats b/controller/result_stats new file mode 100755 index 0000000..a92d6d6 --- /dev/null +++ b/controller/result_stats @@ -0,0 +1,74 @@ +#!/bin/perl + +use strict; +use warnings; +use utf8; + +use Data::Dumper; +use File::Basename; +use Cwd; +use Encode 'encode_utf8'; + +# teplates +use Text::Xslate; + +# yaml (quick) parser +use YAML::Syck; + +our $srcdir = dirname(__FILE__); + +sub html_printer +{ + my $results = $_[0]; + my $task_ids = $_[1]; + + my $xslate = Text::Xslate->new(path => ["$srcdir/result_templates"]); + + my $content = $xslate->render("html.tmpl", { + results => $results, + task_ids => $task_ids, + }); + print encode_utf8($content); +} + +my $workdir = $ARGV[0]; + +my $data = []; + +my $task_ids = {}; + +# go through *each* result directory +my $olddir = getcwd; +for (`find "$workdir" -maxdepth 1 -type d -name 'result_*'`) { + chomp; + chdir $_; + + my $run_results = {}; + $run_results->{dirname} = basename($_); + $run_results->{tasks} = {}; + $run_results->{exit_status} = 0; + + # go through each task + for (`find -maxdepth 1 -type f -name '*.result'`) { + chomp; + + (my $task_id = $_) =~ s/\.result$//; + $task_id =~ s/.*\///; + $task_ids->{$task_id} = 1; + + my $yaml_file = $_; + open my $fd, '<', $yaml_file + or die "can't open yaml file '$yaml_file'"; + + my $config = YAML::Syck::LoadFile($fd); + if ($config->{exit_status} != 0) { + $run_results->{exit_status} = 1; + } + $run_results->{tasks}->{$task_id} = $config; + } + + push @{$data}, $run_results; +} +chdir $olddir; + +html_printer $data, $task_ids; diff --git a/controller/result_templates/html.tmpl b/controller/result_templates/html.tmpl new file mode 100644 index 0000000..8a09ad7 --- /dev/null +++ b/controller/result_templates/html.tmpl @@ -0,0 +1,42 @@ + + + + + +Results + + + +
+ + + + +: for $task_ids.keys() -> $task_id { + +: } + + +: for $results -> $result { + : if ($result.exit_status) { + + : } else { + + : } + + : for $task_ids.keys() -> $task_id { + : if (not defined($result.tasks[$task_id].exit_status)) { + + : } elsif ($result.tasks[$task_id].exit_status == 0) { + + : } else { + + : } + : } + +:} + +
Run time<: $task_id :>
<: $result.dirname :>NOT AVAILABLEOKFAIL
+
+ + diff --git a/controller/run_remote b/controller/run_remote new file mode 100755 index 0000000..0f7ccc3 --- /dev/null +++ b/controller/run_remote @@ -0,0 +1,101 @@ +#!/bin/bash + +. config/config.sh || { + echo >&2 "sorry, but config/config.sh not found" + exit 1 +} + +longopts="verbose,help,force,testid:,listonly" + +run_playbook=${run_playbook-ansible/fedora.yml} + +opt_workdir=/var/tmp/dbt-results +opt_distro=fedora +opt_openstack_instance="$DTF_OPENSTACK_ID" +opt_distro_ver=20 +opt_extra_rpms= +opt_taskdir= + +die() { echo >&2 "$@" ; exit 1 ; } + +longopts="distro:,distro-version:,workdir:,openstack-instance:,extra-rpms-file:" +longopts+=",taskdir:" +ARGS=$(getopt -o "v" -l "$longopts" -n "getopt" -- "$@") \ + || exit 1 +eval set -- "$ARGS" + +while true; do + case "$1" in + --taskdir) + opt=$(sed -e 's/^--//' -e 's/[^[a-zA-Z0-9]/_/g'<<<"$1") + eval "opt_$opt=\"${2,,}\"" + shift 2 + ;; + + --distro) + opt_distro="$2" + shift 2 + ;; + + --distro-version) + opt_distro_ver="$2" + shift 2 + ;; + + --openstack-instance) + opt_openstack_instance="$2" + shift 2 + ;; + + --workdir) + # where the remote results are fetched into + opt_workdir="$2" + shift 2 + ;; + + --extra-rpms-file) + opt_extra_rpms="$(readlink -f "$2")" + shift 2 + ;; + + --) + shift + break + ;; + esac +done + +test -z "$opt_taskdir" && die "you must specify --taskdir" + +credsfile="$(readlink -f "./private/os/$opt_openstack_instance.yml")" +test -z "$credsfile" && die "--ansible-creds option must be specified" +test ! -f "$credsfile" && die "file $credsfile not found" + +config_os_file="$(readlink -f "./config/os/$opt_openstack_instance.sh")" +test ! -r "$config_os_file" && die "file $config_os_file not found" +. "$config_os_file" + +config_os_id="$opt_distro$opt_distro_ver" + +tarball() +( + testsuite_name="$(basename "$opt_taskdir")" + echo "$testsuite_name" + "$opt_taskdir/run" --dist | gzip > "$opt_workdir/$testsuite_name.tar.gz" +) + +testsuite_name="$(tarball)" || die "can not create dist tarball" + +export ANSIBLE_HOST_KEY_CHECKING=False +ansible-playbook "$run_playbook" \ + --extra-vars "opt_distro=$opt_distro" \ + --extra-vars "opt_distro_ver=$opt_distro_ver" \ + --extra-vars "opt_workdir=$opt_workdir" \ + --extra-vars "opt_credsfile=$credsfile" \ + --extra-vars "os_flavor_id=${os_flavor_ids[$config_os_id]}" \ + --extra-vars "os_image_id=${os_image_ids[$config_os_id]}" \ + --extra-vars "os_keypair=${os_keypair}" \ + --extra-vars "os_security_group=${os_security_group}" \ + --extra-vars "os_network_dev=${os_network_dev}" \ + --extra-vars "opt_testsuite_name=${testsuite_name}" \ + --extra-vars "${opt_extra_rpms:+dtf_rpm_files_list=$opt_extra_rpms}" -- cgit