diff --git a/devstack/discovery_exercise.sh b/devstack/discovery_exercise.sh new file mode 100755 index 000000000..b368c55ba --- /dev/null +++ b/devstack/discovery_exercise.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +set -eux + +# Import help functions +IRONIC_INSPECTOR_DEVSTACK_PLUGIN_DIR=$(cd $(dirname "${BASH_SOURCE:-$0}") && pwd) +source ${IRONIC_INSPECTOR_DEVSTACK_PLUGIN_DIR}/exercise_common.sh + +# this exercise destroys BM nodes +# precaution measures +assert_sudo +hook=$(get_ini $IRONIC_INSPECTOR_CONF_FILE processing node_not_found_hook) || { + echo "Please, enable node_not_found_hook in processing section of inspector.conf" + exit 1 +} + +if [ -z "$hook" ] ; then + echo "Please, provide a value for node_not_found_hook in processing section of inspector.conf" + exit 1 +fi + +nodes=$(node_list) +if [ -z "$nodes" ]; then + echo "No nodes found in Ironic" + exit 1 +fi + +# Choose one ironic node for discover +discover_uuid= +for uuid in $nodes; do + provision_state=$(node_attribute $uuid provision_state) + if [[ $provision_state = "available" ]] || [[ $provision_state = "enroll" ]] ; then + discover_uuid=$uuid + break + fi +done + +if [ -z "$discover_uuid" ] ; then + echo "No nodes in available provisioning state" + exit 1 +fi + +# Get node details before delete it +node_name=$(node_attribute $discover_uuid name) +node_driver=$(node_attribute $discover_uuid driver) +node_mac=$(node_mac $discover_uuid) +declare -A driver_info +node_driver_info $discover_uuid driver_info + +# create temporary discovery rule +discovery_rule=$(mktemp) +node_discovery_rule $node_name $node_driver driver_info > "$discovery_rule" + +echo "Purging introspection rules; importing custom rules" +openstack baremetal introspection rule purge +openstack baremetal introspection rule import "$discovery_rule" + +# get virsh node uuid +virsh_uuid=$(node_to_virsh_uuid $discover_uuid) + +# delete&rediscover node +echo "Delete Ironic node $discover_uuid (and ports) for discovery" +ironic node-delete $discover_uuid +wait_for 120 ! assert_mac_blacklisted $node_mac + +# Start vm's for discover +echo "booting virsh $virsh_uuid domain to be discovered" +sudo virsh start $virsh_uuid + +echo "waiting for discovered node to appear" +discovered_node= +wait_for 900 node_exists $node_name discovered_node + +echo "waiting for introspection to finish" +wait_for 900 assert_node_introspection_status $discovered_node + +# validate discovery result +validate_node_flavor $discovered_node baremetal +assert_equal $node_driver $(node_attribute $discovered_node driver) +validate_node_driver_info $discovered_node driver_info + +rm -f $discovery_rule + +echo "Validation passed" diff --git a/devstack/exercise_common.sh b/devstack/exercise_common.sh new file mode 100644 index 000000000..21790e373 --- /dev/null +++ b/devstack/exercise_common.sh @@ -0,0 +1,312 @@ +#!/bin/bash + +IRONIC_INSPECTOR_CONF_FILE="/etc/ironic-inspector/inspector.conf" + +function assert_sudo { + # make sure sudo works in non-interactive mode + if ! sudo -n true ; then + echo "ERROR: sudo doesn't work" + return 1 + fi +} + +function token_issue { + openstack token issue -f value -c id +} + +function endpoint_url { + local endpoint=${1:?endpoint not specified} + openstack endpoint show ${endpoint} -f value -c adminurl +} + +function auth_curl { + local url=${1:?url not specified} ; shift + local method=${1:-GET} ; shift + local token=$(token_issue) + + curl -H "X-Auth-Token: $token" -X ${method} ${url} ${@} +} + +function curl_ironic { + local url=${1:?url not specified} ; shift + local method=${1:-GET} ; shift + + auth_curl "$(endpoint_url baremetal)/${url#/}" ${method} ${@} +} + +function node_list { + openstack baremetal list -f value -c UUID +} + +function node_attribute { + local uuid=${1:?uuid not specified} + local attribute=${2:?attribute not specified} + + openstack baremetal show ${uuid} -f value -c ${attribute} +} + +function json_query { + local data_name=${1:?data variable name not specified}; shift + local var_name=${1:?variable name not specified}; shift + local key=${1:?key not specified}; shift + local query=$@ + + local tmp=$(jq ${query} <<<${!data_name}) + eval ${var_name}[${key}]=${tmp} +} + +function virsh_domains { + + # Id Name State + #---------------------------------------------------- + # - baremetalbrbm_0 shut off + # + sudo -n virsh list --all | tail -n+3 | awk '{print $2;}' | head -n-1 +} + +function virsh_domain_mac { + local domain=${1:?domain not specified} + + # .... + # + # .... + sudo -n virsh dumpxml $domain | grep 'mac address' | cut -d \' -f2 +} + +function node_mac { + local uuid=${1:?uuid not specified} + + # +--------------------------------------+-------------------+ + # | UUID | Address | + # +--------------------------------------+-------------------+ + # | 4d734b98-bae9-43a7-ba27-8dbdce2b0bf1 | 52:54:00:df:96:0c | + # +--------------------------------------+-------------------+ + ironic node-port-list $uuid | tail -n+4 | head -n+1 | head -1 | tr -d \| | awk '{print $2;}' +} + +function node_to_virsh_uuid { + local uuid=${1:?uuid not specified} + local node_mac=$(node_attribute $uuid mac_address) + local map + local node + local domain + + declare -A map + + for node in $(node_list) ; do + map[$(node_mac $node)]=$node + done + + for domain in $(virsh_domains) ; do + if [[ ${map[$(virsh_domain_mac $domain)]} = $uuid ]] ; then + echo $domain + return + fi + done + return 1 +} + +function node_exists { + local query=${1:?query not specified} + local result_name=${2} + + for node in $(node_list) ; do + if [ "${node}" == "${query}" ] || [ $(node_attribute $node name) == "${query}" ] ; then + if [ -n "$result_name" ] ; then + eval $result_name=$node + fi + return + fi + done + return 1 +} + +function flavor_expand { + local flavor=${1:?flavor not specified} + local var_name=${2:?variable name not specified} + + eval $var_name[vcpus]=$(openstack flavor show ${flavor} -f value -c vcpus) + eval $var_name[ram]=$(openstack flavor show ${flavor} -f value -c ram) + eval $var_name[cpu_arch]=$(openstack flavor show ${flavor} -f value -c properties | sed "s/.*cpu_arch='\([^']*\)'.*/\1/") + eval $var_name[disk]=$(openstack flavor show ${flavor} -f value -c disk) + eval $var_name[ephemeral]=$(openstack flavor show ${flavor} -f value -c "OS-FLV-EXT-DATA:ephemeral") + eval $var_name[local_gb]=$(($var_name[disk] + $var_name[ephemeral])) + +} + +function assert_last { + local code=${1:?code not specified} + local expected=${2:-0} + local message=${3:-} + + if [ ${code} -ne ${expected} ] ; then + if [ -n "${message}" ] ; then + echo "${message}" + fi + return 1 + fi +} + +function assert_equal { + local lvalue=${1:?lvalue not specified} + local rvalue=${2:?rvalue not specified} + local message=${3:-} + + [ "${lvalue}" == "${rvalue}" ] || assert_last ${?} 0 "${message}" || return ${?} +} + +function assert_equal_arrays { + local lvalue_name=${1:?lvalue name not specified} + local rvalue_name=${2:?rvalue name not specified} + local lvalue + local rvalue + local keys + local key + + eval keys=\${!${lvalue_name}[@]} + for key in ${keys} ; do + eval lvalue=\${$lvalue_name[$key]} + eval rvalue=\${$rvalue_name[$key]} + assert_equal $lvalue $rvalue "$key: $lvalue != $rvalue" || return ${?} + done + eval keys=\${!${rvalue_name}[@]} + for key in ${keys} ; do + eval lvalue=\${$lvalue_name[$key]} + eval rvalue=\${$rvalue_name[$key]} + assert_equal $lvalue $rvalue "$key: $lvalue != $rvalue" || return ${?} + done +} + +function assert_mac_blacklisted { + local mac=${1:?mac not specified} + + sudo -n iptables -L ironic-inspector | grep -iq "${mac}" && return + return 1 +} + +function assert_node_introspection_status { + local node=${1:?uuid not specified} + local finished_query=${2:-True} + local error_query=${3:-None} + local finished=$(openstack baremetal introspection status $node -f value -c finished) + local error=$(openstack baremetal introspection status $node -f value -c error) + + assert_equal ${finished_query} ${finished} || return ${?} + assert_equal ${error_query} ${error} || return ${?} +} + +function node_discovery_rule { + local node_name=${1:?node name not specified} + local node_driver=${2:?driver not specified} + local driver_info_name=${3:?driver info name not specified} + local keys + local key + local value + + cat <