diff options
Diffstat (limited to 'fuel/prototypes/auto-deploy/deploy/dha-adapters/ipmi.sh')
-rwxr-xr-x | fuel/prototypes/auto-deploy/deploy/dha-adapters/ipmi.sh | 449 |
1 files changed, 449 insertions, 0 deletions
diff --git a/fuel/prototypes/auto-deploy/deploy/dha-adapters/ipmi.sh b/fuel/prototypes/auto-deploy/deploy/dha-adapters/ipmi.sh new file mode 100755 index 000000000..37deb024d --- /dev/null +++ b/fuel/prototypes/auto-deploy/deploy/dha-adapters/ipmi.sh @@ -0,0 +1,449 @@ +#!/bin/bash +############################################################################## +# Copyright (c) 2015 Ericsson AB and others. +# stefan.k.berg@ericsson.com +# jonas.bjurel@ericsson.com +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + + + +######################################################################## +# Internal functions BEGIN + + +dha_f_err() +{ + local rc + local cmd + + rc=$1 + shift + + echo "$@" >&2 + echo "Exit with code $rc" >&2 + + exit $rc +} + +dha_f_run() +{ + $@ + rc=$? + if [ $rc -ne 0 ]; then + dha_f_err $rc "running $@" >&2 + exit $rc + fi +} + + +dha_f_ipmi() +{ + + local nodeId + local ipmiIp + local ipmiUser + local ipmiPass + local i + + nodeId=$1 + shift + + ipmiIp=$($DHAPARSE $DHAFILE getNodeProperty $nodeId ipmiIp) + ipmiUser=$($DHAPARSE $DHAFILE getNodeProperty $nodeId ipmiUser) + ipmiPass=$($DHAPARSE $DHAFILE getNodeProperty $nodeId ipmiPass) + + test -n "$ipmiIp" || error_exit "Could not get IPMI IP" + test -n "$ipmiUser" || error_exit "Could not get IPMI username" + test -n "$ipmiPass" || error_exit "Could not get IPMI password" + + # Repeat three times for good measure (some hardware seems + # weird) + for i in 1 2 + do + ipmitool -I lanplus -A password -H $ipmiIp -U $ipmiUser -P $ipmiPass \ + $@ >/dev/null 2>&1 + sleep 1 + done + ipmitool -I lanplus -A password -H $ipmiIp -U $ipmiUser -P $ipmiPass \ + $@ +} + +# Internal functions END +######################################################################## + + +true=0 +false=1 + +# API: Get the DHA API version supported by this adapter +dha_getApiVersion () +{ + echo "1.0" +} + +# API: Get the name of this adapter +dha_getAdapterName () +{ + echo "ipmi" +} + +# API: ### Node identity functions ### +# API: Node numbering is sequential. + +# API: Get a list of all defined node ids, sorted in ascending order +dha_getAllNodeIds() +{ + dha_f_run $DHAPARSE $DHAFILE getNodes | sort -n +} + + +# API: Get ID for Fuel node ID +dha_getFuelNodeId() +{ + for node in `dha_getAllNodeIds` + do + if [ -n "`dha_f_run $DHAPARSE $DHAFILE getNodeProperty $node isFuel`" ] + then + echo $node + fi + done +} + +# API: Get node property +# API: Argument 1: node id +# API: Argument 2: Property +dha_getNodeProperty() +{ + dha_f_run $DHAPARSE $DHAFILE getNodeProperty $1 $2 +} + + +# API: Get MAC address for the PXE interface of this node. If not +# API: defined, an empty string will be returned. +# API: Argument 1: Node id +dha_getNodePxeMac() +{ + dha_getNodeProperty $1 pxeMac +} + + +### Node operation functions ### + +# API: Use custom installation method for Fuel master? +# API: Returns 0 if true, 1 if false +dha_useFuelCustomInstall() +{ + $DHAPARSE $DHAFILE get fuelCustomInstall | grep -qi true + rc=$? + return $rc +} + +# API: Fuel custom installation method +# API: Leaving the Fuel master powered on and booting from ISO at exit +# API: Argument 1: Full path to ISO file to install +dha_fuelCustomInstall() +{ + if [ ! -e $1 ]; then + error_exit "Could not access ISO file $1" + fi + + dha_useFuelCustomInstall || dha_f_err 1 "dha_fuelCustomInstall not supported" + + fuelIp=`dea getFuelIp` || error_exit "Could not get fuel IP" + fuelNodeId=`dha getFuelNodeId` || error_exit "Could not get fuel node id" + virtName=`$DHAPARSE $DHAFILE getNodeProperty $fuelNodeId libvirtName` + + # Power off the node + virsh destroy $virtName + sleep 5 + + # Zero the MBR + fueldisk=`virsh dumpxml $virtName | \ + grep "<source file" | grep raw | sed "s/.*'\(.*\)'.*/\1/"` + disksize=`ls -l $fueldisk | awk '{ print $5 }'` + rm -f $fueldisk + fallocate -l $disksize $fueldisk + + # Set the boot order + for order in disk iso + do + if [ "$order" == "pxe" ]; then + bootline+="<boot dev='network'\/>\n" + elif [ "$order" == "disk" ]; then + bootline+="<boot dev='hd'/\>\n" + elif [ "$order" == "iso" ]; then + bootline+="<boot dev='cdrom'/\>\n" + else + error_exit "Unknown boot type: $order" + fi + done + + virsh dumpxml $virtName | grep -v "<boot dev.*>" | \ + sed "/<\/os>/i\ + ${bootline}" > $tmpdir/vm.xml || error_exit "Could not set bootorder" + virsh define $tmpdir/vm.xml || error_exit "Could not set bootorder" + + + # Get name of CD device + cdDev=`virsh domblklist $virtName | tail -n +3 | awk '{ print $1 }' | grep ^hd` + + # Eject and insert ISO + virsh change-media $virtName --config --eject $cdDev + sleep 5 + virsh change-media $virtName --config --insert $cdDev $1 || error_exit "Could not insert CD $1" + sleep 5 + + virsh start $virtName || error_exit "Could not start $virtName" + sleep 5 + + # wait for node up + echo "Waiting for Fuel master to accept SSH" + while true + do + ssh root@${fuelIp} date 2>/dev/null + if [ $? -eq 0 ]; then + break + fi + sleep 10 + done + + # Wait until fuelmenu is up + echo "Waiting for fuelmenu to come up" + menuPid="" + while [ -z "$menuPid" ] + do + menuPid=`ssh root@${fuelIp} "ps -ef" 2>&1 | grep fuelmenu | grep -v grep | awk '{ print $2 }'` + sleep 10 + done + + # This is where we inject our own astute.yaml settings + scp -q $deafile root@${fuelIp}:. || error_exit "Could not copy DEA file to Fuel" + echo "Uploading build tools to Fuel server" + ssh root@${fuelIp} rm -rf tools || error_exit "Error cleaning old tools structure" + scp -qrp $topdir/tools root@${fuelIp}:. || error_exit "Error copying tools" + echo "Running transplant #0" + ssh root@${fuelIp} "cd tools; ./transplant0.sh ../`basename $deafile`" \ + || error_exit "Error running transplant sequence #0" + + + + # Let the Fuel deployment continue + echo "Found menu as PID $menuPid, now killing it" + ssh root@${fuelIp} "kill $menuPid" 2>/dev/null + + # Wait until installation complete + echo "Waiting for bootstrap of Fuel node to complete" + while true + do + ssh root@${fuelIp} "ps -ef" 2>/dev/null \ + | grep -q /usr/local/sbin/bootstrap_admin_node + if [ $? -ne 0 ]; then + break + fi + sleep 10 + done + + echo "Waiting for one minute for Fuel to stabilize" + sleep 1m + +} + +# API: Get power on strategy from DHA +# API: Returns one of two values: +# API: all: Power on all nodes simultaneously +# API: sequence: Power on node by node, wait for Fuel detection +dha_getPowerOnStrategy() +{ + local strategy + + strategy=`$DHAPARSE $DHAFILE get powerOnStrategy` + + if [ "$strategy" == "all" ]; then + echo $strategy + elif + [ "$strategy" == "sequence" ]; then + echo $strategy + else + dha_f_err 1 "Could not parse strategy from DHA, got $strategy" + fi +} + +# API: Power on node +# API: Argument 1: node id +dha_nodePowerOn() +{ + local nodeId + + nodeId=$1 + state=$(dha_f_ipmi $1 chassis power status) || error_exit "Could not get IPMI power status" + echo "state $state" + + + if [ "$(echo $state | sed 's/.* //')" == "off" ]; then + dha_f_ipmi $1 chassis power on + fi +} + +# API: Power off node +# API: Argument 1: node id +dha_nodePowerOff() +{ + local nodeId + + nodeId=$1 + state=$(dha_f_ipmi $1 chassis power status) || error_exit "Could not get IPMI power status" + echo "state $state" + + + if [ "$(echo $state | sed 's/.* //')" != "off" ]; then + dha_f_ipmi $1 chassis power off + fi +} + +# API: Reset node +# API: Argument 1: node id +dha_nodeReset() +{ + local nodeId + + nodeId=$1 + state=$(dha_f_ipmi $1 chassis power reset) || error_exit "Could not get IPMI power status" + echo "state $state" + + + if [ "$(echo $state | sed 's/.* //')" != "off" ]; then + dha_f_ipmi $1 chassis power reset + fi +} + +# Boot order and ISO boot file + +# API: Is the node able to commit boot order without power toggle? +# API: Argument 1: node id +# API: Returns 0 if true, 1 if false +dha_nodeCanSetBootOrderLive() +{ + return $true +} + +# API: Set node boot order +# API: Argument 1: node id +# API: Argument 2: Space separated line of boot order - boot ids are "pxe", "disk" and "iso" +# Strategy for IPMI: Always set boot order to persistent except in the case of CDROM. +dha_nodeSetBootOrder() +{ + local id + local order + + id=$1 + shift + order=$1 + + if [ "$order" == "pxe" ]; then + dha_f_ipmi $id chassis bootdev pxe options=persistent || error_exit "Could not get IPMI power status" + elif [ "$order" == "iso" ]; then + dha_f_ipmi $id chassis bootdev cdrom || error_exit "Could not get IPMI power status" + elif [ "$order" == "disk" ]; then + dha_f_ipmi $id chassis bootdev disk options=persistent || error_exit "Could not get IPMI power status" + else + error_exit "Unknown boot type: $order" + fi +} + +# API: Is the node able to operate on ISO media? +# API: Argument 1: node id +# API: Returns 0 if true, 1 if false +dha_nodeCanSetIso() +{ + return $false +} + +# API: Is the node able to insert add eject ISO files without power toggle? +# API: Argument 1: node id +# API: Returns 0 if true, 1 if false +dha_nodeCanHandeIsoLive() +{ + return $false +} + +# API: Insert ISO into virtualDVD +# API: Argument 1: node id +# API: Argument 2: iso file +dha_nodeInsertIso() +{ + error_exit "Node can not handle InsertIso" +} + +# API: Eject ISO from virtual DVD +# API: Argument 1: node id +dha_nodeEjectIso() +{ + error_exit "Node can not handle InsertIso" +} + +# API: Wait until a suitable time to change the boot order to +# API: "disk iso" when ISO has been booted. Can't be too long, nor +# API: too short... +# API: We should make a smart trigger for this somehow... +dha_waitForIsoBoot() +{ + echo "waitForIsoBoot: Not used by ipmi" +} + +# API: Is the node able to reset its MBR? +# API: Returns 0 if true, 1 if false +dha_nodeCanZeroMBR() +{ + return $false +} + +# API: Reset the node's MBR +dha_nodeZeroMBR() +{ + error_exit "Node $1 does not support ZeroMBR" +} + + +# API: Entry point for dha functions +# API: Typically do not call "dha_node_zeroMBR" but "dha node_ZeroMBR" +# API: +# API: Before calling dha, the adapter file must gave been sourced with +# API: the DHA file name as argument +dha() +{ + if [ -z "$DHAFILE" ]; then + error_exit "dha_setup has not been run" + fi + + + if type dha_$1 &>/dev/null; then + cmd=$1 + shift + dha_$cmd $@ + return $? + else + error_exit "No such function dha_$1 defined" + fi +} + +if [ "$1" == "api" ]; then + egrep "^# API: |dha.*\(\)" $0 | sed 's/^# API: /# /' | grep -v dha_f_ | sed 's/)$/)\n/' +else + dhatopdir=$(dirname $(readlink -f $BASH_SOURCE)) + DHAPARSE="$dhatopdir/dhaParse.py" + DHAFILE=$1 + + if [ ! -f $DHAFILE ]; then + error_exit "No such DHA file: $DHAFILE" + else + echo "Adapter init" + echo "$@" + echo "DHAPARSE: $DHAPARSE" + echo "DHAFILE: $DHAFILE" + fi + +fi |