instack-undercloud/scripts/instack-ironic-deployment

402 lines
13 KiB
Bash
Executable File

#!/bin/bash
set -eu
set -o pipefail
SCRIPT_NAME=$(basename $0)
OS_AUTH_URL=${OS_AUTH_URL:-""}
if [ -z "$OS_AUTH_URL" ]; then
echo "You must source a stackrc file for the Undercloud."
exit 1
fi
# NOTE(dtantsur): last working API version
export IRONIC_API_VERSION="1.6"
function show_options () {
echo "Usage: $SCRIPT_NAME [options]"
echo
echo "Deploys instances via Ironic in preparation for an Overcloud deployment."
echo
echo "Options:"
echo " --register-nodes -- register nodes from a nodes json file"
echo " --nodes-json -- nodes json file containing node data"
echo " for registration."
echo " Default: nodes.json in the current directory"
echo " --discover-nodes -- Perform discovery of registered nodes."
echo " Powers on registered nodes to complete"
echo " the discovery process."
echo " --configure-nodes -- Configure BIOS and RAID volumes of "
echo " registered nodes."
echo " --setup-flavors -- Setup Nova flavors to match discovered"
echo " profiles"
echo " --show-profile -- Show matching profile of nodes"
echo " --deploy-nodes -- Deploy nodes"
echo " --check-ssh -- Check the root ssh connection to each"
echo " deployed node."
echo " --delete-stack -- Wait until the stack has deleted."
echo " --delete-nodes -- Delete all nodes."
echo " -x -- enable tracing"
echo " --help, -h -- Print this help message."
echo
exit $1
}
TEMP=$(getopt -o ,h -l,register-nodes,nodes-json:,discover-nodes,configure-nodes,deploy-nodes,help,setup-flavors,show-profile,check-ssh,delete-stack,delete-nodes,config-tools-provision -o,x,h -n $SCRIPT_NAME -- "$@")
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"
REGISTER_NODES=
NODES_JSON=
DISCOVER_NODES=
CONFIGURE_NODES=
DEPLOY_NODES=
SETUP_FLAVORS=
SHOW_PROFILE=
CHECK_SSH=
DELETE_STACK=
DELETE_NODES=
STDERR=/dev/null
# NOTE(bnemec): Can be removed once Ironic is updated to fix the
# novaclient.v1_1 deprecation warning
export PYTHONWARNINGS="ignore"
DEPLOY_NAME=${DEPLOY_NAME:-"ironic-discover"}
IRONIC=$(openstack endpoint show baremetal | grep publicurl | awk '{ print $4; }')
IRONIC=${IRONIC%/}
# Raise retry time to 60 seconds
export IRONIC_MAX_RETRIES=${IRONIC_MAX_RETRIES:-24}
export IRONIC_RETRY_INTERVAL=${IRONIC_RETRY_INTERVAL:-5}
while true ; do
case "$1" in
--register-nodes) REGISTER_NODES="1"; shift 1;;
--nodes-json) NODES_JSON="$2"; shift 2;;
--discover-nodes) DISCOVER_NODES="1"; shift 1;;
--configure-nodes) CONFIGURE_NODES="1"; shift 1;;
--show-profile) SHOW_PROFILE="1"; shift 1;;
--deploy-nodes) DEPLOY_NODES="1"; shift 1;;
--setup-flavors) SETUP_FLAVORS="1"; shift 1;;
--check-ssh) CHECK_SSH="1"; shift 1;;
--delete-stack) DELETE_STACK="1"; shift 1;;
--delete-nodes) DELETE_NODES="1"; shift 1;;
-x) set -x; STDERR=/dev/stderr; shift 1;;
-h | --help) show_options 0;;
--) shift ; break ;;
*) echo "Error: unsupported option $1." ; exit 1 ;;
esac
done
function register_nodes {
NODES_JSON=${NODES_JSON:-"nodes.json"}
NULL_STATS=${NULL_STATS:-0}
tmp_json=$NODES_JSON
if [ "$NULL_STATS" = "1" ]; then
tmp_json=$(mktemp)
jq '.nodes[].memory=null | .nodes[].disk=null | .nodes[].arch=null | .nodes[].cpu=null' $NODES_JSON > $tmp_json
fi
echo " Registering nodes from $NODES_JSON"
register-nodes --service-host undercloud --nodes <(jq '.nodes' $tmp_json) 1>/dev/null
if [ "$NULL_STATS" = "1" ]; then
rm -f $tmp_json
fi
deploy_kernel_id=$(glance image-show bm-deploy-kernel | awk ' / id / {print $4}')
deploy_ramdisk_id=$(glance image-show bm-deploy-ramdisk | awk ' / id / {print $4}')
# Add the local boot capability and deploy_{kernel, ramdisk} parameters
node_list=$(ironic node-list --limit 0)
node_ids=$(echo "$node_list" | tail -n +4 | head -n -1 | awk -F "| " '{print $2}')
for node_id in $node_ids; do
ironic node-update $node_id add properties/capabilities="boot_option:local" driver_info/deploy_ramdisk=$deploy_ramdisk_id driver_info/deploy_kernel=$deploy_kernel_id 1> /dev/null
done
echo " Nodes registered."
echo
echo "$node_list"
echo
}
function discover_nodes {
echo " Discovering nodes."
node_ids=$(ironic node-list | tail -n +4 | head -n -1 | awk -F "| " '{print $2}')
for node_id in $node_ids; do
# NOTE(dtantsur): ||true is in case nodes are already MANAGEABLE
ironic node-set-provision-state $node_id manage 2> /dev/null || true
echo -n " Sending node ID $node_id to discoverd for discovery ... "
openstack baremetal introspection start $node_id
# small sleep to avoid too many nodes DHCP'ing at once
sleep 5
echo "DONE."
done
echo " Polling discoverd for discovery results ... "
for node_id in $node_ids; do
echo -n " Result for node $node_id is ... "
while true; do
finished=$(openstack baremetal introspection status $node_id -f value -c finished)
if [ "$finished" = "True" ]; then
error=$(openstack baremetal introspection status $node_id -f value -c error)
if [ "$error" = "None" ]; then
echo "DISCOVERED."
else
echo "ERROR: $error"
fi
break
fi
sleep 15
done
done
echo " Setting node states to AVAILABLE... "
for node_id in $node_ids; do
ironic node-set-provision-state $node_id provide
done
echo
}
function configure_bios {
echo " Configuring BIOS."
node_ids=$(ironic node-list | tail -n +4 | head -n -1 | awk -F "| " '{print $2}')
for node_id in $node_ids; do
driver=$(ironic node-show $node_id | grep 'driver[ \t]' | awk -F "|" '{print $3}' | xargs)
if [ "$driver" == "pxe_drac" ]; then
echo -n " Configuring BIOS for node ID $node_id ... "
ironic node-vendor-passthru $node_id --http_method POST configure_bios_settings
echo "DONE."
fi
done
# NOTE(ifarkas): wait until Ironic processes the request
sleep 15
echo
}
function configure_raid_volumes {
create_root_volume=$1
create_nonroot_volumes=$2
echo " Configuring RAID volumes."
node_ids=$(ironic node-list | tail -n +4 | head -n -1 | awk -F "| " '{print $2}')
for node_id in $node_ids; do
driver=$(ironic node-show $node_id | grep 'driver[ \t]' | awk -F "|" '{print $3}' | xargs)
if [ "$driver" == "pxe_drac" ]; then
echo -n " Configuring RAID volumes for node ID $node_id ... "
ironic node-vendor-passthru $node_id --http_method POST create_raid_configuration \
create_root_volume=$create_root_volume \
create_nonroot_volumes=$create_nonroot_volumes
echo "DONE."
fi
done
# NOTE(ifarkas): wait until Ironic processes the request
sleep 15
echo
}
function wait_for_drac_config_jobs {
echo " Waiting for DRAC config jobs to finish ... "
node_ids=$(ironic node-list | tail -n +4 | head -n -1 | awk -F "| " '{print $2}')
for node_id in $node_ids; do
driver=$(ironic node-show $node_id | grep 'driver[ \t]' | awk -F "|" '{print $3}' | xargs)
if [ "$driver" == "pxe_drac" ]; then
echo -n " Waiting for node $node_id ... "
while true; do
jobs=$(ironic node-vendor-passthru $node_id --http_method GET list_unfinished_jobs)
if [[ $jobs == *"'unfinished_jobs': []"* ]]; then
break
fi
sleep 30
done
echo "DONE."
fi
done
echo
}
function change_power_state {
requested_state=$1
echo " Changing power states."
node_ids=$(ironic node-list | tail -n +4 | head -n -1 | awk -F "| " '{print $2}')
for node_id in $node_ids; do
echo -n " Changing power state for node ID $node_id ... "
ironic node-set-power-state $node_id $requested_state
echo "DONE."
done
# NOTE(ifarkas): wait until Ironic processes the request
sleep 15
echo
}
function wait_for_ssh {
echo " Waiting for ssh as root to be enabled ... "
echo
ips=$(nova list | tail -n +4 | head -n -1 | awk '{print $12}' | cut -d= -f2)
for ip in $ips; do
echo -n " checking $ip ... "
tripleo wait_for 300 1 ssh -o "PasswordAuthentication=no" -o "StrictHostKeyChecking=no" root@$ip ls
echo "DONE."
done
echo
}
function deploy_nodes {
wait_for_hypervisor_stats
DEPLOY_HEAT_TEMPLATE=${DEPLOY_HEAT_TEMPLATE:-"/usr/share/instack-undercloud/heat-templates/ironic-deployment.yaml"}
CONTROL_COUNT=${CONTROL_COUNT:-"1"}
COMPUTE_COUNT=${COMPUTE_COUNT:-"3"}
echo " Creating heat stack ... "
heat stack-create $DEPLOY_NAME -f $DEPLOY_HEAT_TEMPLATE -P "control_count=$CONTROL_COUNT" -P "compute_count=$COMPUTE_COUNT"
echo " Created."
echo
echo -n " Waiting for stack to finish ... "
echo
tripleo wait_for_stack_ready 60 10 $DEPLOY_NAME
echo "DONE."
heat stack-show $DEPLOY_NAME
heat stack-list
wait_for_ssh
echo
}
function setup_flavors {
if ! nova flavor-show baremetal 2>$STDERR 1>/dev/null; then
echo " Creating baremetal flavor ... "
nova flavor-create baremetal auto 4096 40 1
else
echo " baremetal flavor already exists."
fi
echo
nova flavor-list
echo
echo " Setting baremetal flavor keys ... "
nova flavor-key baremetal set \
"cpu_arch"="x86_64" \
"capabilities:boot_option"="local"
nova flavor-show baremetal
}
function show_profile {
node_ids=$(ironic node-list | tail -n +4 | head -n -1 | awk -F "| " '{print $2}')
token=$(openstack token issue | grep ' id ' | awk '{print $4}')
echo " Querying assigned profiles ... "
echo
for node_id in $node_ids; do
echo " $node_id"
echo -n " "
curl -s -H "x-auth-token: $token" $IRONIC/v1/nodes/$node_id | jq '.properties.capabilities'
echo
done
echo
echo " DONE."
echo
}
function wait_for_hypervisor_stats {
node_ids=$(ironic node-list | tail -n +4 | head -n -1 | awk -F "| " '{print $2}')
expected_nodes=$(echo $node_ids | wc -w)
expected_memory=0
expected_vcpus=0
token=$(openstack token issue | grep ' id ' | awk '{print $4}')
echo -n " Wating for nova hypervisor stats ... "
for node_id in $node_ids; do
mem=$(curl -s -H "x-auth-token: $token" $IRONIC/v1/nodes/$node_id | jq '.properties.memory_mb | tonumber')
vcpu=$(curl -s -H "x-auth-token: $token" $IRONIC/v1/nodes/$node_id | jq '.properties.cpus | tonumber')
expected_memory=$(($expected_memory + $mem))
expected_vcpus=$(($expected_vcpus + $vcpu))
done
tripleo wait_for 180 1 wait_for_hypervisor_stats $expected_nodes $expected_memory $expected_vcpus
echo "DONE."
echo
}
function delete_stack {
heat stack-delete $DEPLOY_NAME
tripleo wait_for 90 2 ! heat stack-show $DEPLOY_NAME
}
function delete_nodes {
for n in $(ironic node-list | tail -n +4 | head -n -1 | awk '{print $2}'); do
ironic node-delete $n;
done
}
echo "Preparing for deployment..."
if [ "$REGISTER_NODES" = 1 ]; then
register_nodes
fi
if [ "$DISCOVER_NODES" = 1 ]; then
discover_nodes
fi
if [ "$CONFIGURE_NODES" = 1 ]; then
configure_bios
create_root_volume=true
create_nonroot_volumes=false
configure_raid_volumes $create_root_volume $create_nonroot_volumes
change_power_state reboot
wait_for_drac_config_jobs
change_power_state off
discover_nodes
create_root_volume=false
create_nonroot_volumes=true
configure_raid_volumes $create_root_volume $create_nonroot_volumes
change_power_state reboot
wait_for_drac_config_jobs
change_power_state off
fi
if [ "$SETUP_FLAVORS" = 1 ]; then
setup_flavors
fi
if [ "$SHOW_PROFILE" = 1 ]; then
show_profile
fi
if [ "$CHECK_SSH" = 1 ]; then
wait_for_ssh
fi
if [ "$DELETE_STACK" = 1 ]; then
delete_stack
fi
if [ "$DELETE_NODES" = 1 ]; then
delete_nodes
fi
echo "Prepared."
if [ "$DEPLOY_NODES" = 1 ]; then
echo "Deploying..."
deploy_nodes
echo "Deployed."
fi