402 lines
13 KiB
Bash
Executable File
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
|