Merge "Add discover nodes exercise"

This commit is contained in:
Jenkins 2016-03-16 11:07:06 +00:00 committed by Gerrit Code Review
commit b14fc0f890
3 changed files with 403 additions and 1 deletions

84
devstack/discovery_exercise.sh Executable file
View File

@ -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"

312
devstack/exercise_common.sh Normal file
View File

@ -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}
# ....
# <mac address='52:54:00:df:96:0c'/>
# ....
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 <<EOF
[
{
"description": "${node_name} discovery rule",
"actions": [
{"action": "set-attribute", "path": "/name",
"value": "${node_name}"},
{"action": "set-attribute", "path": "/driver",
"value": "${node_driver}"}
EOF
eval keys=\${!${driver_info_name}[@]}
for key in ${keys} ; do
eval value=\${${driver_info_name}[${key}]}
cat <<EOF
, {"action": "set-attribute", "path": "/driver_info/${key}",
"value": "${value}"}
EOF
done
cat <<EOF
],
"conditions": [
{"op": "eq", "field": "data://auto_discovered", "value": true}
]
}
]
EOF
}
function validate_node_flavor {
local node=${1:?uuid not specified}
local flavor=${2:-baremetal}
local json_data
local expected
local actual
local key
declare -A expected
declare -A actual
flavor_expand ${flavor} expected
json_data=$(curl_ironic /v1/nodes/${node})
for key in cpu_arch cpus local_gb memory_mb ; do
json_query json_data actual ${key} -r ".properties.${key}"
done
assert_equal ${expected[cpu_arch]} ${actual[cpu_arch]} "unexpected cpu_arch: ${actual[cpu_arch]}"
assert_equal ${expected[ram]} ${actual[memory_mb]} "unexpected memory: ${actual[memory_mb]}"
assert_equal ${expected[vcpus]} ${actual[cpus]} "unexpected cpus: ${actual[cpus]}"
assert_equal ${expected[local_gb]} ${actual[local_gb]} "unexpected local gb: ${actual[local_gb]}"
}
function node_driver_info {
local node=${1:?uuid not specified}
local var_name=${2:?var name not specified}
local node_json=$(curl_ironic /v1/nodes/${node})
local key
for key in ssh_address ssh_virt_type ssh_port ssh_username ssh_key_filename deploy_kernel deploy_ramdisk ; do
json_query node_json $var_name $key -r ".driver_info.$key"
done
}
function validate_node_driver_info {
local node=${1:?uuid not specified}
local expected_var_name=${2:?expected var name not specified}
local actual
declare -A actual
node_driver_info ${node} actual
assert_equal_arrays $expected_var_name actual
}
function get_ini {
local file=${1:?file not specified}
local section=${2:?section not specified}
local option=${3:?option not specified}
cat <<_GET_INI | python -
import ConfigParser
cp = ConfigParser.ConfigParser()
cp.read("$file")
assert "$section" in cp.sections(), '$section not in $file'
assert "$option" in cp.options("$section"), '$option not in $file:$section'
print cp.get("$section", "$option")
_GET_INI
}
function wait_for {
local timeout=${1:?timeout required}; shift
local start_time=$(date +"%s")
echo "waiting for ${@}; timeout: ${timeout}"
while [ $(( start_time + timeout)) -ge $(date +"%s") ] && ! eval "${@}" ; do
sleep ${wait_sleep:-3}
done
if [ $(( start_time + timeout )) -lt $(date +"%s") ] ; then
echo "timeout reached (elapsed time: $(( $(date +"%s") - start_time )))"
return 1
fi
}

View File

@ -30,7 +30,9 @@ IRONIC_INSPECTOR_INTERNAL_SUBNET_SIZE=${IRONIC_INSPECTOR_INTERNAL_SUBNET_SIZE:-2
IRONIC_INSPECTOR_DHCP_RANGE=${IRONIC_INSPECTOR_DHCP_RANGE:-172.24.42.100,172.24.42.253}
IRONIC_INSPECTOR_INTERFACE=${IRONIC_INSPECTOR_INTERFACE:-br-inspector}
IRONIC_INSPECTOR_INTERNAL_URI="http://$IRONIC_INSPECTOR_INTERNAL_IP:$IRONIC_INSPECTOR_PORT"
IRONIC_INSPECTOR_INTERNAL_IP_WITH_NET=$IRONIC_INSPECTOR_INTERNAL_IP/$IRONIC_INSPECTOR_INTERNAL_SUBNET_SIZE
IRONIC_INSPECTOR_INTERNAL_IP_WITH_NET="$IRONIC_INSPECTOR_INTERNAL_IP/$IRONIC_INSPECTOR_INTERNAL_SUBNET_SIZE"
IRONIC_INSPECTOR_NODE_NOT_FOUND_HOOK=${IRONIC_INSPECTOR_NODE_NOT_FOUND_HOOK:-""}
GITDIR["python-ironic-inspector-client"]=$DEST/python-ironic-inspector-client
GITREPO["python-ironic-inspector-client"]=${IRONIC_INSPECTOR_CLIENT_REPO:-${GIT_BASE}/openstack/python-ironic-inspector-client.git}
@ -198,11 +200,15 @@ function configure_inspector {
inspector_iniset processing ramdisk_logs_dir "$IRONIC_INSPECTOR_RAMDISK_LOGDIR"
inspector_iniset processing always_store_ramdisk_logs "$IRONIC_INSPECTOR_ALWAYS_STORE_RAMDISK_LOGS"
inspector_iniset processing log_bmc_address False
if [ -n "$IRONIC_INSPECTOR_NODE_NOT_FOUND_HOOK" ]; then
inspector_iniset processing node_not_found_hook "$IRONIC_INSPECTOR_NODE_NOT_FOUND_HOOK"
fi
inspector_iniset DEFAULT timeout $IRONIC_INSPECTOR_TIMEOUT
get_or_create_service "ironic-inspector" "baremetal-introspection" "Ironic Inspector baremetal introspection service"
get_or_create_endpoint "baremetal-introspection" "$REGION_NAME" \
"$IRONIC_INSPECTOR_URI" "$IRONIC_INSPECTOR_URI" "$IRONIC_INSPECTOR_URI"
}
function configure_inspector_swift {