#!/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 "" | \ 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