summaryrefslogtreecommitdiffstats
path: root/fuel/prototypes/auto-deploy/deploy
diff options
context:
space:
mode:
Diffstat (limited to 'fuel/prototypes/auto-deploy/deploy')
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/deploy.sh193
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/dha-adapters/dhaParse.py87
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/dha-adapters/ipmi.sh449
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/dha-adapters/libvirt.sh334
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/functions/common.sh67
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/functions/dea-api.sh171
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/functions/deaParse.py85
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/functions/deploy_env.sh140
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/functions/install_iso.sh91
-rw-r--r--fuel/prototypes/auto-deploy/deploy/functions/isolinux.cfg.patch14
-rw-r--r--fuel/prototypes/auto-deploy/deploy/functions/ks.cfg.patch19
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/functions/patch-iso.sh85
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/tools/transplant0.sh40
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/tools/transplant1.sh67
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/tools/transplant2.sh98
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/tools/transplant_fuel_settings.py50
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/tools/transplant_interfaces.py77
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/tools/transplant_network_scheme.py42
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/tools/transplant_network_settings.py52
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/tools/transplant_opnfv_settings.py42
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/tools/transplant_settings.py36
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/verify_dea.sh79
-rwxr-xr-xfuel/prototypes/auto-deploy/deploy/verify_dha.sh125
23 files changed, 2443 insertions, 0 deletions
diff --git a/fuel/prototypes/auto-deploy/deploy/deploy.sh b/fuel/prototypes/auto-deploy/deploy/deploy.sh
new file mode 100755
index 000000000..f5aa634f9
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/deploy.sh
@@ -0,0 +1,193 @@
+#!/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
+##############################################################################
+
+# Setup locations
+topdir=$(dirname $(readlink -f $BASH_SOURCE))
+exampledir=$(cd $topdir/../examples; pwd)
+functions=${topdir}/functions
+
+# Define common functions
+. ${functions}/common.sh
+
+exit_handler() {
+ # Remove safety catch
+ kill -9 `ps -p $killpid -o pid --no-headers` \
+ `ps --ppid $killpid -o pid --no-headers`\
+ > /dev/null 2>&1
+}
+
+usage()
+{
+ cat <<EOF
+Syntax: `basename $0` [-nf] <isofile> <deafile> <dhafile>
+Arguments
+ -nf Do not install Fuel master
+EOF
+}
+
+
+# maximum allowed deploy time (default three hours)
+MAXDEPLOYTIME=${MAXDEPLOYTIME-3h}
+
+####### MAIN ########
+
+time0=`date +%s`
+
+if [ "`whoami`" != "root" ]; then
+ error_exit "You need be root to run this script"
+fi
+
+# Set initial veriables
+nofuel=1
+
+
+# Check for arguments
+if [ "$1" == "-nf" ]; then
+ nofuel=0
+ shift
+fi
+
+if [ $# -ne 3 ]; then
+ usage
+ exit 1
+fi
+
+# Setup tmpdir - if TMPDIR env variable is set, use that one
+# else create in $HOME/fueltmp
+if [ -n "${TMPDIR}" ]; then
+ if [ -d ${TMPDIR} ]; then
+ tmpdir=${TMPDIR}/fueltmp
+ echo "Using TMPDIR=${TMPDIR}, so tmpdir=${tmpdir}"
+ else
+ error_exit "No such directory for TMPDIR: ${TMPDIR}"
+ fi
+else
+ tmpdir=${HOME}/fueltmp
+ echo "Default: tmpdir=$tmpdir"
+fi
+
+# Umask must be changed so files created are readable by qemu
+umask 0022
+
+if [ -d $tmpdir ]; then
+ rm -Rf $tmpdir || error_exit "Could not remove tmpdir $tmpdir"
+fi
+mkdir $tmpdir || error_exit "Could not create tmpdir $tmpdir"
+
+isofile=$(cd `dirname $1`; echo `pwd`/`basename $1`)
+deafile=$(cd `dirname $2`; echo `pwd`/`basename $2`)
+dhafile=$(cd `dirname $3`; echo `pwd`/`basename $3`)
+
+if [ ! -f $isofile ]; then
+ error_exit "Could not find ISO file $isofile"
+elif [ ! -f $deafile ]; then
+ error_exit "Could not find DEA file $deafile"
+elif [ ! -f $dhafile ]; then
+ error_exit "Could not find DHA file $dhafile"
+fi
+
+# Connect adapter
+adapter=`grep "^adapter: " $dhafile | sed 's/.*: //'`
+if [ -z "$adapter" ]; then
+ error_exit "No adapter in DHA file!"
+elif [ ! -f $topdir/dha-adapters/${adapter}.sh ]; then
+ error_exit "Could not find adapter for $adapter"
+else
+ . $topdir/dha-adapters/${adapter}.sh $dhafile
+fi
+
+# Connect DEA API
+. ${topdir}/functions/dea-api.sh $deafile
+
+# Enable safety catch
+echo "Enabling auto-kill if deployment exceeds $MAXDEPLOYTIME"
+(sleep $MAXDEPLOYTIME; echo "Auto-kill of deploy after a timeout of $MAXDEPLOYTIME"; kill $$) &
+killpid=$!
+
+# Enable exit handler
+trap exit_handler exit
+
+# Get Fuel node information
+fuelIp=`dea getFuelIp` || error_exit "Could not get Fuel IP"
+fuelNetmask=`dea getFuelNetmask` || error_exit "Could not get Fuel netmask"
+fuelGateway=`dea getFuelGateway` || error_exit "Could not get Fuel Gateway"
+fuelHostname=`dea getFuelHostname` || error_exit "Could not get Fuel hostname"
+fuelDns=`dea getFuelDns` || error_exit "Could not get Fuel DNS"
+fuelNodeId=`dha getFuelNodeId` || error_exit "Could not get fuel node id"
+dha useFuelCustomInstall
+fuelCustom=$?
+
+# Stop all VMs
+for id in `dha getAllNodeIds`
+do
+ if [ $nofuel -eq 0 -o $fuelCustom -eq 0 ]; then
+ if [ $fuelNodeId -ne $id ]; then
+ echo "Powering off id $id"
+ dha nodePowerOff $id
+ fi
+ else
+ echo "Powering off id $id"
+ dha nodePowerOff $id
+ fi
+done
+
+# Install the Fuel master
+if [ $nofuel -eq 1 ]; then
+ echo "Patching iso file"
+
+ deployiso="${tmpdir}/deploy-`basename $isofile`"
+ ${functions}/patch-iso.sh $isofile $deployiso $tmpdir \
+ $fuelIp $fuelNetmask $fuelGateway $fuelHostname $fuelDns \
+ || error_exit "Failed to patch ISO"
+
+ # Swap isofiles from now on
+ isofile=$deployiso
+ if dha useFuelCustomInstall; then
+ echo "Custom Fuel install"
+ dha fuelCustomInstall $isofile || error_exit "Failed to run Fuel custom install"
+ else
+ echo "Ordinary Fuel install"
+ . ${functions}/install_iso.sh || error_exit "Failed to install Fuel"
+ fi
+else
+ echo "Not installing Fuel master"
+fi
+
+. ${functions}/deploy_env.sh
+
+echo "Waiting for one minute for deploy to stabilize"
+sleep 1m
+
+echo "Verifying node status after deployment"
+# Any node with non-ready status?
+ssh root@${fuelIp} fuel node 2>/dev/null | tail -n +3 | cut -d "|" -f 2 | \
+ sed 's/ //g' | grep -v ready | wc -l | grep -q "^0$"
+if [ $? -ne 0 ]; then
+ echo -e "Deploy failed to verify\n"
+ ssh root@${fuelIp} fuel node 2>/dev/null
+ error_exit "Exiting with error status"
+else
+ echo -e "Deployment verified\n"
+ ssh root@${fuelIp} fuel node 2>/dev/null
+ echo -e "\nNow running sanity and smoke health checks"
+ echo -e "\n\n"
+ ssh root@${fuelIp} fuel health --env ${envId} --check sanity,smoke \
+ --force
+ if [ $? -eq 0 ]; then
+ echo "Health checks passed!"
+ else
+ error_exit "One or several health checks failed!"
+ fi
+
+ time1=`date +%s`
+ echo "Total deployment time: $[(time1-time0)/60] minutes"
+ exit 0
+fi
diff --git a/fuel/prototypes/auto-deploy/deploy/dha-adapters/dhaParse.py b/fuel/prototypes/auto-deploy/deploy/dha-adapters/dhaParse.py
new file mode 100755
index 000000000..d2712c6d7
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/dha-adapters/dhaParse.py
@@ -0,0 +1,87 @@
+#!/usr/bin/python
+##############################################################################
+# 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
+##############################################################################
+
+import yaml
+import re
+import sys
+import os
+
+def test(arr):
+ print "Nodes"
+ nodes = doc["nodes"]
+ for node in nodes:
+ print "Node %d " % node["id"]
+ print " Mac: %s" % node["adminMac"]
+ print " Role: %s" % node["role"]
+
+def get(arg):
+ try:
+ if doc[arg[0]]:
+ print doc[arg[0]]
+ else:
+ print ""
+ except KeyError:
+ print ""
+
+def getNodes(arg):
+ for node in doc["nodes"]:
+ print node["id"]
+
+# Get property arg2 from arg1
+def getNodeProperty(arg):
+ id=arg[0]
+ key=arg[1]
+
+ for node in doc["nodes"]:
+ if node["id"] == int(id):
+ try:
+ if node[key]:
+ print node[key]
+ exit(0)
+ except:
+ print ""
+ exit(0)
+ exit(1)
+
+
+
+infile = sys.argv[1]
+
+if not os.path.exists(infile):
+ sys.stderr.write("ERROR: The file "+infile+" could not be opened\n")
+ sys.exit(1)
+
+
+f1 = open(infile, 'r')
+doc = yaml.load(f1)
+f1.close()
+
+cmd = sys.argv[2]
+args = sys.argv[3:]
+
+if cmd == "test":
+ test(args)
+elif cmd == "getNodes":
+ getNodes(args)
+elif cmd == "getNodeProperty":
+ getNodeProperty(args)
+elif cmd == "get":
+ get(args)
+else:
+ print "No such command: %s" % cmd
+ exit(1)
+
+#print "Dumping"
+#print yaml.dump(doc, default_flow_style=False)
+
+#Functions:
+
+#getIdRole
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
diff --git a/fuel/prototypes/auto-deploy/deploy/dha-adapters/libvirt.sh b/fuel/prototypes/auto-deploy/deploy/dha-adapters/libvirt.sh
new file mode 100755
index 000000000..8d9edde3f
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/dha-adapters/libvirt.sh
@@ -0,0 +1,334 @@
+#!/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
+}
+
+# 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 "libvirt"
+}
+
+# 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()
+{
+ dha_useFuelCustomInstall || dha_f_err 1 "dha_fuelCustomInstall not supported"
+ date
+}
+
+# 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 state
+ local virtName
+
+ virtName=`$DHAPARSE $DHAFILE getNodeProperty $1 libvirtName`
+ state=`virsh domstate $virtName`
+ if [ "$state" == "shut off" ]; then
+ dha_f_run virsh start $virtName
+ fi
+}
+
+# API: Power off node
+# API: Argument 1: node id
+dha_nodePowerOff()
+{
+ local state
+ local virtName
+
+ virtName=`$DHAPARSE $DHAFILE getNodeProperty $1 libvirtName`
+ state=`virsh domstate $virtName`
+ if [ "$state" != "shut off" ]; then
+ dha_f_run virsh destroy $virtName
+ fi
+}
+
+# API: Reset node
+# API: Argument 1: node id
+dha_nodeReset()
+{
+ local virtName
+
+ virtName=`$DHAPARSE $DHAFILE getNodeProperty $1 libvirtName`
+ dha_f_run virsh reset $virtName
+}
+
+# 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 $false
+}
+
+# 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"
+dha_nodeSetBootOrder()
+{
+ local id
+ local bootline
+ local virtName
+ local order
+
+ id=$1
+ virtName=`$DHAPARSE $DHAFILE getNodeProperty $1 libvirtName`
+ shift
+
+ for order in $@
+ 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
+ echo $bootline
+
+ 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"
+
+}
+
+# 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 $true
+}
+
+# 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 $true
+}
+
+# API: Insert ISO into virtualDVD
+# API: Argument 1: node id
+# API: Argument 2: iso file
+dha_nodeInsertIso()
+{
+ local virtName
+ local isoFile
+
+ virtName=`$DHAPARSE $DHAFILE getNodeProperty $1 libvirtName`
+ isoFile=$2
+ virsh change-media $virtName --insert hdc $isoFile
+}
+
+# API: Eject ISO from virtual DVD
+# API: Argument 1: node id
+dha_nodeEjectIso()
+{
+ local virtName
+ local isoFile
+
+ virtName=`$DHAPARSE $DHAFILE getNodeProperty $1 libvirtName`
+ isoFile=$2
+ virsh change-media $virtName --eject hdc
+}
+
+# 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: No delay necessary for libvirt"
+}
+
+# API: Is the node able to reset its MBR?
+# API: Returns 0 if true, 1 if false
+dha_nodeCanZeroMBR()
+{
+ return $true
+}
+
+# API: Reset the node's MBR
+dha_nodeZeroMBR()
+{
+ local fueldisk
+ local disksize
+
+ fueldisk=`virsh dumpxml $(dha_getNodeProperty $1 libvirtName) | \
+ grep "<source file" | grep raw | sed "s/.*'\(.*\)'.*/\1/"`
+ disksize=`ls -l $fueldisk | awk '{ print $5 }'`
+ rm -f $fueldisk
+ fallocate -l $disksize $fueldisk
+}
+
+
+# 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
diff --git a/fuel/prototypes/auto-deploy/deploy/functions/common.sh b/fuel/prototypes/auto-deploy/deploy/functions/common.sh
new file mode 100755
index 000000000..6947d796f
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/functions/common.sh
@@ -0,0 +1,67 @@
+##############################################################################
+# 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
+##############################################################################
+
+# Common functions
+
+error_exit () {
+ echo "Error: $@" >&2
+ exit 1
+}
+
+ssh() {
+ SSHPASS="r00tme" sshpass -e ssh -o UserKnownHostsFile=${tmpdir}/known_hosts \
+ -o StrictHostKeyChecking=no -o ConnectTimeout=15 "$@"
+}
+
+scp() {
+ SSHPASS="r00tme" sshpass -e scp -o UserKnownHostsFile=${tmpdir}/known_hosts \
+ -o StrictHostKeyChecking=no -o ConnectTimeout=15 "$@"
+}
+
+
+fuel () {
+ ssh root@`dea getFuelIp` "fuel $@"
+}
+
+
+# TODO: Move numberOfNodes into the DEA API
+numberOfNodes() {
+ fuel node | tail -n +3 | grep -v "^$" | wc -l
+}
+
+# TODO: Move numberOfNodesUp into the DEA API
+numberOfNodesUp() {
+ fuel node | tail -n +3 | grep -v "^$" | grep True | wc -l
+}
+
+# Currently not used!
+# Wait for node count to increase
+waitForNode() {
+ local cnt
+ local initCnt
+ local expectCnt
+
+ initCnt=`numberOfNodesUp`
+ expectCnt=$[initCnt+1]
+ while true
+ do
+ cnt=`numberOfNodesUp`
+ if [ $cnt -eq $expectCnt ]; then
+ break
+ elif [ $cnt -lt $initCnt ]; then
+ error_exit "Node count decreased while waiting, $initCnt -> $cnt"
+ elif [ $cnt -gt $expectCnt ]; then
+ error_exit "Node count exceeded expect count, $cnt > $expectCnt"
+ fi
+ sleep 10
+ echo -n "[${cnt}]"
+ done
+ echo "[${cnt}]"
+}
diff --git a/fuel/prototypes/auto-deploy/deploy/functions/dea-api.sh b/fuel/prototypes/auto-deploy/deploy/functions/dea-api.sh
new file mode 100755
index 000000000..61d670f92
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/functions/dea-api.sh
@@ -0,0 +1,171 @@
+#!/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
+
+
+
+dea_f_err()
+{
+ local rc
+ local cmd
+
+ rc=$1
+ shift
+
+ if [ -n "$rc" ]; then
+ echo "Error ($rc): $@" >&2
+ else
+ echo "Error: $@" >&2
+ fi
+}
+
+dea_f_run()
+{
+ $@
+ rc=$?
+ if [ $rc -ne 0 ]; then
+ dea_f_err $rc "Error running $@"
+ return $rc
+ fi
+}
+
+# Internal functions END
+########################################################################
+
+true=0
+false=1
+
+# API: Get the DEA API version supported by this adapter
+dea_getApiVersion ()
+{
+ echo "1.0"
+}
+
+
+# API: Node numbering is sequential.
+
+
+# API: Get the role for this node
+# API: Argument 1: node id
+dea_getNodeRole()
+{
+ $DEAPARSE $DEAFILE getNodeRole $@
+
+}
+
+# API: Get IP address of Fuel master
+dea_getFuelIp()
+{
+ $DEAPARSE $DEAFILE getProperty fuel ADMIN_NETWORK ipaddress
+}
+
+# API: Get netmask Fuel master
+dea_getFuelNetmask()
+{
+ $DEAPARSE $DEAFILE getProperty fuel ADMIN_NETWORK netmask
+}
+
+# API: Get gateway address of Fuel master
+# FIXME: This is currently not in the DEA, so make the gatway the ..1
+# FiXME: of the IP
+dea_getFuelGateway()
+{
+ $DEAPARSE $DEAFILE getProperty fuel ADMIN_NETWORK ipaddress | \
+ sed 's/.[0-9]*$/.1/'
+}
+
+# API: Get gateway address of Fuel master
+dea_getFuelHostname()
+{
+ $DEAPARSE $DEAFILE getProperty fuel HOSTNAME
+}
+
+# API: Get DNS address of Fuel master
+dea_getFuelDns()
+{
+ $DEAPARSE $DEAFILE getProperty fuel DNS_UPSTREAM
+}
+
+# API: Convert a normal MAC to a Fuel short mac for --node-id
+dea_convertMacToShortMac()
+{
+ echo $1 | sed 's/.*..:..:..:..:\(..:..\).*/\1/' | tr [A-Z] [a-z]
+}
+
+
+# API: Get property from DEA file
+# API: Argument 1: search path, as e.g. "fuel ADMIN_NETWORK ipaddress"
+dea_getProperty()
+{
+ $DEAPARSE $DEAFILE getProperty $@
+}
+
+# API: Convert DHA node id to Fuel cluster node id
+# API: Look for lowest Fuel node number, this will be DHA node 1
+# API: Argument: node id
+dea_getClusterNodeId()
+{
+ local baseId
+ local inId
+ local fuelIp
+
+ inId=$1
+ fuelIp=`dea_getFuelIp`
+
+ baseId=`ssh root@${fuelIp} fuel node | tail -n +3 | awk '{ print $1 }'| sed 's/ //g' | sort -n | head -1`
+ echo "$[inId + baseId - 1]"
+}
+
+# API: Entry point for dea functions
+# API: Typically do not call "dea_node_zeroMBR" but "dea node_ZeroMBR"
+# API:
+# API: Before calling dea, the adapter file must gave been sourced with
+# API: the DEA file name as argument
+dea()
+{
+ if [ -z "$DEAFILE" ]; then
+ error_exit "dea_setup has not been run"
+ fi
+
+
+ if type dea_$1 &>/dev/null; then
+ cmd=$1
+ shift
+ dea_$cmd $@
+ return $?
+ else
+ error_exit "No such function dea_$1 defined"
+ fi
+}
+
+if [ "$1" == "api" ]; then
+ egrep "^# API: |dea.*\(\)" $0 | sed 's/^# API: /# /' | grep -v dea_f_ | sed 's/)$/)\n/'
+else
+ deatopdir=$(dirname $(readlink -f $BASH_SOURCE))
+ DEAPARSE="$deatopdir/deaParse.py"
+ DEAFILE=$1
+
+ if [ ! -f $DEAFILE ]; then
+ error_exit "No such DEA file: $DEAFILE"
+ else
+ echo "Adapter init"
+ echo "$@"
+ echo "DEAPARSE: $DEAPARSE"
+ echo "DEAFILE: $DEAFILE"
+ fi
+fi
+
+
+
diff --git a/fuel/prototypes/auto-deploy/deploy/functions/deaParse.py b/fuel/prototypes/auto-deploy/deploy/functions/deaParse.py
new file mode 100755
index 000000000..7ca650171
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/functions/deaParse.py
@@ -0,0 +1,85 @@
+#!/usr/bin/python
+##############################################################################
+# 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
+##############################################################################
+
+import yaml
+import re
+import sys
+import os
+
+def test(arr):
+ print "Nodes"
+ nodes = doc["nodes"]
+ for node in nodes:
+ print "Node %d " % node["id"]
+ print " Mac: %s" % node["adminMac"]
+ print " Role: %s" % node["role"]
+
+def getNodeRole(arg):
+ for node in doc["nodes"]:
+ print node
+ try:
+ if node["role"] == arg[0]:
+ print doc["id"]
+ except KeyError:
+ exit(1)
+
+def getNodes(arg):
+ for node in doc["nodes"]:
+ print node["id"]
+
+
+def getProperty(arg):
+ result = doc
+ for level in arg:
+ result = result[level]
+ print result
+
+def getNodeRole(arg):
+ for node in doc["nodes"]:
+ if int(arg[0]) == node["id"]:
+ print node["role"]
+
+def getNode(arg):
+ id=arg[0]
+ key=arg[1]
+ for node in doc["nodes"]:
+ if int(node["id"]) == int(id):
+ print node[key]
+
+ # for node in doc["nodes"]:
+ # if int(node["id"]) == int(arg[0]):
+ # print node
+
+infile = sys.argv[1]
+
+if not os.path.exists(infile):
+ sys.stderr.write("ERROR: The file "+infile+" could not be opened\n")
+ sys.exit(1)
+
+
+f1 = open(infile, 'r')
+doc = yaml.load(f1)
+f1.close()
+
+cmd = sys.argv[2]
+args = sys.argv[3:]
+
+if cmd == "getProperty":
+ getProperty(args)
+elif cmd == "getNodeRole":
+ getNodeRole(args)
+elif cmd == "getNode":
+ getNode(args)
+elif cmd == "get":
+ get(args)
+else:
+ print "No such command: %s" % cmd
+ exit(1)
diff --git a/fuel/prototypes/auto-deploy/deploy/functions/deploy_env.sh b/fuel/prototypes/auto-deploy/deploy/functions/deploy_env.sh
new file mode 100755
index 000000000..e650f4d6e
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/functions/deploy_env.sh
@@ -0,0 +1,140 @@
+##############################################################################
+# 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
+##############################################################################
+
+# Deploy!
+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 "Uploading templating tols to Fuel server"
+ssh root@${fuelIp} rm -rf create_templates || error_exit "Error cleaning old create_templates structure"
+scp -qrp $topdir/../create_templates root@${fuelIp}:. || error_exit "Error copying create_templates"
+
+# Refuse to run if environment already present
+envcnt=`fuel env | tail -n +3 | grep -v '^$' | wc -l`
+if [ $envcnt -ne 0 ]; then
+ error_exit "Environment count is $envcnt"
+fi
+
+# Refuse to run if any nodes are up
+nodeCnt=`numberOfNodesUp`
+if [ $nodeCnt -ne 0 ]; then
+ error_exit "Nodes are up (node count: $nodeCnt)"
+fi
+
+# FIXME: Add support for CentOS creation here
+# Extract release ID for Ubuntu environment
+ubuntucnt=`fuel release | grep Ubuntu | wc -l`
+if [ $ubuntucnt -ne 1 ]; then
+ error_exit "Not exacly one Ubuntu release found"
+fi
+
+# FIXME: Make release a property in the dea.yaml and use that instead!
+ubuntuid=`fuel release | grep Ubuntu | awk '{ print $1 }'`
+
+# Create environment
+envName=`dea getProperty environment_name` || error_exit "Could not get environment name"
+envMode=`dea getProperty environment_mode` || error_exit "Could not get environment mode"
+
+fuel env create --name $envName \
+ --rel $ubuntuid \
+ --mode $envMode \
+ --network-mode neutron \
+ --net-segment-type vlan \
+ || error_exit "Error creating environment"
+
+envId=`ssh root@${fuelIp} fuel env | tail -n +3 | awk '{ print $1 }'` \
+ || error_exit "Could not get environment id"
+
+echo "Running transplant #1"
+ssh root@${fuelIp} "cd tools; ./transplant1.sh ../`basename $deafile`" \
+ || error_exit "Error running transplant sequence #1"
+
+# Start VMs
+strategy=`dha getPowerOnStrategy` || error_exit "Could not get power on strategy"
+if [ $strategy == "all" ]; then
+ echo "Starting all nodes at once"
+ poweredOn=0
+ for id in `dha getAllNodeIds`
+ do
+ if [ $id -ne $fuelNodeId ]; then
+ echo "Setting boot order pxe disk for node $id"
+ dha nodeSetBootOrder $id "pxe disk" || "Could not set boot order for node"
+ echo "Powering on node $id"
+ dha nodePowerOn $id || error_exit "Could not power on node"
+ poweredOn=$[poweredOn + 1]
+ fi
+ done
+ # Wait for all nodes to be accounted for
+ echo "Waiting for $poweredOn nodes to come up"
+ while true
+ do
+ nodesUp=`numberOfNodesUp`
+ echo -n "[${nodesUp}]"
+ if [ $nodesUp -eq $poweredOn ]; then
+ break
+ fi
+ sleep 10
+ done
+ echo "[${nodesUp}]"
+else
+ # Refuse to run if any nodes are defined
+ totalNodeCnt=`numberOfNodes`
+ if [ $totalNodeCnt -ne 0 ]; then
+ error_exit "There are already ${totalNodeCnt} defined nodes, can not run power on in sequence!"
+ fi
+ echo "Starting nodes sequentially, waiting for Fuel detection until proceeding"
+ for id in `dha getAllNodeIds`
+ do
+ if [ $id -ne $fuelNodeId ]; then
+ echo "Setting boot order pxe disk for node $id"
+ dha nodeSetBootOrder $id "pxe disk" || "Could not set boot order for node"
+ echo "Powering on node $id"
+ dha nodePowerOn $id || error_exit "Could not power on node"
+ # Wait for node count to increase
+ waitForNode
+ fi
+ done
+fi
+
+# Set roles for detected hosts
+for id in `dha getAllNodeIds`
+do
+ # If not a Fuel node
+ if [ $fuelNodeId -ne $id ]; then
+ longMac=`dha getNodePxeMac $id` || \
+ error_exit "Could not get MAC address for node $id from DHA"
+ shortMac=`dea convertMacToShortMac $longMac`
+ role="`dea getNodeRole $id`"
+ echo "Setting role $role for Fuel node $shortMac (DEA node $id)"
+ fuel node set --node-id $shortMac --role $role --env $envId \
+ || error_exit "Could not set role for $node"
+ fi
+done
+
+# Run pre-deploy with default input
+# Need to set terminal as script does "clear" and needs curses support
+ssh root@${fuelIp} "TERM=vt100 /opt/opnfv/pre-deploy.sh < /dev/null" \
+ || error_exit "Pre-deploy failed"
+
+# Inject node network config (will override pre-deploy Astute settings but we
+# want to catch pre-deploy provisioning changes)
+# TODO: There needs to be a function to adjust the NTP settings for clients
+# TODO: to that of the actual set of controllers in this deployment.
+echo "Running transplant #2"
+ssh root@${fuelIp} "cd tools; ./transplant2.sh ../`basename $deafile`" \
+ || error_exit "Error running transplant sequence #2"
+
+
+# Deploy
+echo "Deploying!"
+ssh root@${fuelIp} "fuel deploy-changes --env $envId" >/dev/null 2>&1 || error_exit "Deploy failed"
+echo "Deployment completed"
diff --git a/fuel/prototypes/auto-deploy/deploy/functions/install_iso.sh b/fuel/prototypes/auto-deploy/deploy/functions/install_iso.sh
new file mode 100755
index 000000000..2ec510b25
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/functions/install_iso.sh
@@ -0,0 +1,91 @@
+##############################################################################
+# 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
+##############################################################################
+
+fuelIp=`dea getFuelIp` || error_exit "Could not get fuel IP"
+fuelNodeId=`dha getFuelNodeId` || error_exit "Could not get fuel node id"
+
+
+if dha nodeCanZeroMBR $fuelNodeId; then
+ echo "Node $fuelNodeId capable of zeroing MBR so doing that..."
+ dha nodeZeroMBR $fuelNodeId || error_exit "Failed to zero Fuel MBR"
+ dha nodeSetBootOrder $fuelNodeId "disk iso"
+elif dha nodeCanSetBootOrderLive; then
+ echo "Node can change ISO boot order live"
+ dha nodeSetBootOrder $fuelNodeId "iso disk"
+else
+ error_exit "No way to install Fuel node"
+fi
+
+sleep 3
+dha nodeEjectIso $fuelNodeId
+dha nodeInsertIso $fuelNodeId $isofile
+
+sleep 3
+dha nodePowerOn $fuelNodeId
+
+# Switch back boot order to disk, hoping that node is now up
+
+# FIXME: Can we do a smarter and more generic detection of when the
+# FIXME: kickstart procedure has started? Then th dha_waitForIsoBoot
+# FIXME: can be removed. Setting and IP already in the kickstart install
+# FIXME: and ping-wait for that?
+dha waitForIsoBoot
+
+dha nodeSetBootOrder $fuelNodeId "disk iso"
+
+# 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
diff --git a/fuel/prototypes/auto-deploy/deploy/functions/isolinux.cfg.patch b/fuel/prototypes/auto-deploy/deploy/functions/isolinux.cfg.patch
new file mode 100644
index 000000000..298a05721
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/functions/isolinux.cfg.patch
@@ -0,0 +1,14 @@
+*** isolinux/isolinux.cfg.orig 2015-04-15 08:29:52.026868322 -0400
+--- isolinux/isolinux.cfg 2015-04-15 08:30:34.350868343 -0400
+***************
+*** 19,22 ****
+ menu label Fuel Install (^Static IP)
+ menu default
+ kernel vmlinuz
+! append initrd=initrd.img biosdevname=0 ks=cdrom:/ks.cfg ip=10.20.0.2 gw=10.20.0.1 dns1=10.20.0.1 netmask=255.255.255.0 hostname=fuel.domain.tld showmenu=no
+--- 19,22 ----
+ menu label Fuel Install (^Static IP)
+ menu default
+ kernel vmlinuz
+! append initrd=initrd.img biosdevname=0 ks=cdrom:/ks.cfg ip=10.20.0.2 gw=10.20.0.1 dns1=10.20.0.1 netmask=255.255.255.0 hostname=fuel.domain.tld showmenu=yes
+
diff --git a/fuel/prototypes/auto-deploy/deploy/functions/ks.cfg.patch b/fuel/prototypes/auto-deploy/deploy/functions/ks.cfg.patch
new file mode 100644
index 000000000..189695792
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/functions/ks.cfg.patch
@@ -0,0 +1,19 @@
+*** ks.cfg.orig Wed Apr 15 21:47:09 2015
+--- ks.cfg Wed Apr 15 21:47:24 2015
+***************
+*** 35,41 ****
+ default_drive=`echo ${drives} ${removable_drives} | awk '{print $1}'`
+
+ installdrive="undefined"
+! forceformat="no"
+ for I in `cat /proc/cmdline`; do case "$I" in *=*) eval $I;; esac ; done
+
+ set ${drives} ${removable_drives}
+--- 35,41 ----
+ default_drive=`echo ${drives} ${removable_drives} | awk '{print $1}'`
+
+ installdrive="undefined"
+! forceformat="yes"
+ for I in `cat /proc/cmdline`; do case "$I" in *=*) eval $I;; esac ; done
+
+ set ${drives} ${removable_drives}
diff --git a/fuel/prototypes/auto-deploy/deploy/functions/patch-iso.sh b/fuel/prototypes/auto-deploy/deploy/functions/patch-iso.sh
new file mode 100755
index 000000000..d27dcdf2d
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/functions/patch-iso.sh
@@ -0,0 +1,85 @@
+#!/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
+##############################################################################
+
+exit_handler() {
+ rm -Rf $tmpnewdir
+ fusermount -u $tmporigdir 2>/dev/null
+ test -d $tmporigdir && rmdir $tmporigdir
+}
+
+trap exit_handler exit
+
+error_exit() {
+ echo "$@"
+ exit 1
+}
+
+if [ $# -ne 8 ]; then
+ error_exit "Input argument error"
+fi
+
+top=$(cd `dirname $0`; pwd)
+origiso=$(cd `dirname $1`; echo `pwd`/`basename $1`)
+newiso=$(cd `dirname $2`; echo `pwd`/`basename $2`)
+tmpdir=$3
+fuelIp=$4
+fuelNetmask=$5
+fuelGateway=$6
+fuelHostname=$7
+fuelDns=$8
+
+tmporigdir=${tmpdir}/origiso
+tmpnewdir=${tmpdir}/newiso
+
+test -f $origiso || error_exit "Could not find origiso $origiso"
+test -d $tmpdir || error_exit "Could not find tmpdir $tmpdir"
+
+
+if [ "`whoami`" != "root" ]; then
+ error_exit "You need be root to run this script"
+fi
+
+echo "Copying..."
+rm -Rf $tmpnewdir || error_exit "Failed deleting old ISO copy dir"
+mkdir -p $tmporigdir $tmpnewdir
+fuseiso $origiso $tmporigdir || error_exit "Failed to FUSE mount ISO"
+cd $tmporigdir
+find . | cpio -pd $tmpnewdir || error_exit "Failed to copy FUSE ISO with cpio"
+cd $tmpnewdir
+fusermount -u $tmporigdir || error_exit "Failed to FUSE unmount ISO"
+rmdir $tmporigdir || error_exit "Failed to delete original FUSE ISO directory"
+chmod -R 755 $tmpnewdir || error_exit "Failed to set protection on new ISO dir"
+
+echo "Patching..."
+cd $tmpnewdir
+# Patch ISO to make it suitable for automatic deployment
+cat $top/ks.cfg.patch | patch -p0 || error_exit "Failed patching ks.cfg"
+rm -rf .rr_moved
+
+# Add dynamic Fuel content
+echo "isolinux.cfg before: `grep netmask isolinux/isolinux.cfg`"
+sed -i "s/ ip=[^ ]*/ ip=$fuelIp/" isolinux/isolinux.cfg
+sed -i "s/ gw=[^ ]*/ gw=$fuelGateway/" isolinux/isolinux.cfg
+sed -i "s/ dns1=[^ ]*/ dns1=$fuelDns/" isolinux/isolinux.cfg
+sed -i "s/ netmask=[^ ]*/ netmask=$fuelNetmask/" isolinux/isolinux.cfg
+sed -i "s/ hostname=[^ ]*/ hostname=$fuelHostname/" isolinux/isolinux.cfg
+sed -i "s/ showmenu=[^ ]*/ showmenu=yes/" isolinux/isolinux.cfg
+echo "isolinux.cfg after: `grep netmask isolinux/isolinux.cfg`"
+
+rm -vf $newiso
+echo "Creating iso $newiso"
+mkisofs -quiet -r \
+ -J -R -b isolinux/isolinux.bin \
+ -no-emul-boot \
+ -boot-load-size 4 -boot-info-table \
+ --hide-rr-moved \
+ -x "lost+found" -o $newiso . || error_exit "Failed making iso"
+
diff --git a/fuel/prototypes/auto-deploy/deploy/tools/transplant0.sh b/fuel/prototypes/auto-deploy/deploy/tools/transplant0.sh
new file mode 100755
index 000000000..7c5883b56
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/tools/transplant0.sh
@@ -0,0 +1,40 @@
+#!/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
+##############################################################################
+
+cleanup () {
+ if [ -n "$tmpDir" ]; then
+ rm -Rf $tmpDir
+ fi
+}
+
+trap cleanup exit
+
+error_exit () {
+ echo "Error: $@" >&2
+ exit 1
+}
+
+tmpDir=`mktemp -d /tmp/deaXXXX`
+
+export PATH=`dirname $0`:$PATH
+
+if [ $# -lt 1 ]; then
+ error_exit "Argument error"
+fi
+deafile=$1
+shift
+
+if [ ! -f "$deafile" ]; then
+ error_exit "Can't find $deafile"
+fi
+
+transplant_fuel_settings.py /etc/fuel/astute.yaml $deafile || \
+ error_exit "Could not transplant astute settings"
diff --git a/fuel/prototypes/auto-deploy/deploy/tools/transplant1.sh b/fuel/prototypes/auto-deploy/deploy/tools/transplant1.sh
new file mode 100755
index 000000000..2401c6f88
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/tools/transplant1.sh
@@ -0,0 +1,67 @@
+#!/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
+##############################################################################
+
+cleanup () {
+ if [ -n "$tmpDir" ]; then
+ rm -Rf $tmpDir
+ fi
+}
+
+trap cleanup exit
+
+error_exit () {
+ echo "Error: $@" >&2
+ exit 1
+}
+
+tmpDir=`mktemp -d /tmp/deaXXXX`
+
+export PATH=`dirname $0`:$PATH
+
+if [ $# -lt 1 ]; then
+ error_exit "Argument error"
+fi
+deafile=$1
+shift
+
+if [ ! -f "$deafile" ]; then
+ error_exit "Can't find $deafile"
+fi
+
+if [ `fuel env | tail -n +3 | grep -v '^$' | wc -l` -ne 1 ]; then
+ error_exit "Not exactly one environment"
+fi
+envId=`fuel env | tail -n +3 | grep -v '^$' | awk '{ print $1 }'`
+
+fuel settings --env $envId --download --dir $tmpDir > /dev/null || \
+ error_exit "Could not get settings"
+
+fuel network --env $envId --download --dir $tmpDir > /dev/null || \
+ error_exit "Could not get network settings"
+
+cp $tmpDir/network_${envId}.yaml network_before.yaml
+
+# Transplant network settings
+transplant_network_settings.py $tmpDir/network_${envId}.yaml $deafile || \
+ error_exit "Could not transplant network settings"
+fuel network --env $envId --upload --dir $tmpDir || \
+ error_exit "Could not update network settings"
+cp $tmpDir/network_${envId}.yaml network_after.yaml
+
+# Transplant settings
+cp $tmpDir/settings_${envId}.yaml settings_before.yaml
+transplant_settings.py $tmpDir/settings_${envId}.yaml $deafile || \
+ error_exit "Could not transplant settings"
+fuel settings --env $envId --upload --dir $tmpDir || \
+ error_exit "Could not update settings"
+cp $tmpDir/settings_${envId}.yaml settings_after.yaml
+
+
diff --git a/fuel/prototypes/auto-deploy/deploy/tools/transplant2.sh b/fuel/prototypes/auto-deploy/deploy/tools/transplant2.sh
new file mode 100755
index 000000000..46c7a6008
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/tools/transplant2.sh
@@ -0,0 +1,98 @@
+#!/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
+##############################################################################
+
+cleanup () {
+ if [ -n "$tmpDir" ]; then
+ rm -Rf $tmpDir
+ fi
+}
+
+trap cleanup exit
+
+error_exit () {
+ echo "Error: $@" >&2
+ exit 1
+}
+
+# Return offset between DEA node id and cluster node id
+getDeaNodeOffset()
+{
+ local baseId
+
+ baseId=`fuel node | tail -n +3 | awk '{ print $1 }' | sed 's/ //g' | sort -n | head -1`
+ echo "$[baseId - 1]"
+}
+
+tmpDir=`mktemp -d /tmp/deaXXXX`
+
+export PATH=`dirname $0`:$PATH
+
+if [ $# -ne 1 ]; then
+ error_exit "Argument error"
+fi
+deaFile=$1
+
+if [ ! -f "$deaFile" ]; then
+ error_exit "Can't find $deaFile"
+fi
+
+
+if [ `fuel env | tail -n +3 | grep -v '^$' | wc -l` -ne 1 ]; then
+ error_exit "Not exactly one environment"
+fi
+envId=`fuel env | tail -n +3 | grep -v '^$' | awk '{ print $1 }'`
+
+# Phase 1: Graft deployment information
+fuel deployment --env $envId --default --dir $tmpDir || \
+ error_exit "Could not dump environment"
+
+for controller in `find $tmpDir -type f | grep -v compute`
+do
+ transplant_network_scheme.py $controller $deaFile controller || \
+ error_exit "Failed to graft `basename $controller`"
+
+ transplant_opnfv_settings.py $controller $deaFile controller || \
+ error_exit "Failed to graft `basename $controller`"
+done
+
+for compute in `find $tmpDir -type f | grep compute`
+do
+ transplant_network_scheme.py $compute $deaFile compute || \
+ error_exit "Failed to graft `basename $compute`"
+
+ transplant_opnfv_settings.py $compute $deaFile compute || \
+ error_exit "Failed to graft `basename $controller`"
+done
+
+fuel deployment --env $envId --upload --dir $tmpDir || \
+ error_exit "Could not upload environment"
+
+# Phase 2: Graft interface information
+deaOffset=`getDeaNodeOffset`
+echo "DEA offset: $deaOffset"
+
+for clusterNodeId in `fuel node | grep True | awk '{ print $1}'`
+do
+ deaNodeId=$[clusterNodeId - deaOffset]
+ echo "Node $clusterNodeId is $deaNodeId"
+ fuel node --node-id $clusterNodeId --network --download --dir $tmpDir || \
+ error_exit "Could not download node $clusterNodeId"
+
+ transplant_interfaces.py ${tmpDir}/node_${clusterNodeId}/interfaces.yaml \
+ $deaFile $deaNodeId || \
+ error_exit "Failed to graft interfaces"
+
+ fuel node --node-id $clusterNodeId --network --upload --dir $tmpDir || \
+ error_exit "Could not upload node $clusterNodeId"
+done
+
+
+
diff --git a/fuel/prototypes/auto-deploy/deploy/tools/transplant_fuel_settings.py b/fuel/prototypes/auto-deploy/deploy/tools/transplant_fuel_settings.py
new file mode 100755
index 000000000..49ea5e455
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/tools/transplant_fuel_settings.py
@@ -0,0 +1,50 @@
+#!/usr/bin/python
+##############################################################################
+# 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
+##############################################################################
+
+import yaml
+import re
+import sys
+import os
+
+if len(sys.argv) != 3:
+ sys.stderr.write("Usage: "+sys.argv[0]+" <astutefile> <deafile>\n")
+ sys.exit(1)
+
+fuelfile = sys.argv[1]
+if not os.path.exists(fuelfile):
+ sys.stderr.write("ERROR: The file "+fuelfile+" could not be opened\n")
+ sys.exit(1)
+
+deafile = sys.argv[2]
+if not os.path.exists(deafile):
+ sys.stderr.write("ERROR: The file "+deafile+" could not be opened\n")
+ sys.exit(1)
+
+f = open(deafile, 'r')
+dea = yaml.load(f)
+f.close()
+
+f = open(fuelfile, 'r')
+fuel = yaml.load(f)
+f.close()
+
+dea = dea["fuel"]
+for property in dea.keys():
+ if property == "ADMIN_NETWORK":
+ for adminproperty in dea[property].keys():
+ fuel[property][adminproperty] = dea[property][adminproperty]
+ else:
+ fuel[property] = dea[property]
+
+f = open(fuelfile, 'w')
+f.write(yaml.dump(fuel, default_flow_style=False))
+f.close()
+
diff --git a/fuel/prototypes/auto-deploy/deploy/tools/transplant_interfaces.py b/fuel/prototypes/auto-deploy/deploy/tools/transplant_interfaces.py
new file mode 100755
index 000000000..609f360ba
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/tools/transplant_interfaces.py
@@ -0,0 +1,77 @@
+#!/usr/bin/python
+##############################################################################
+# 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
+##############################################################################
+
+import yaml
+import re
+import sys
+import os
+
+if len(sys.argv) != 4:
+ sys.stderr.write("Usage: "+sys.argv[0]+" <infile> <deafile> <nodeid>\n")
+ sys.exit(1)
+
+infile = sys.argv[1]
+if not os.path.exists(infile):
+ sys.stderr.write("ERROR: The file "+infile+" could not be opened\n")
+ sys.exit(1)
+
+deafile = sys.argv[2]
+if not os.path.exists(deafile):
+ sys.stderr.write("ERROR: The file "+deafile+" could not be opened\n")
+ sys.exit(1)
+deafile = sys.argv[2]
+nodeid = int(sys.argv[3])
+
+namespace = "interfaces"
+
+f1 = open(infile, 'r')
+doc1 = yaml.load(f1)
+f1.close()
+
+f2 = open(deafile, 'r')
+doc2 = yaml.load(f2)
+f2.close()
+
+
+# Create lookup table network name -> id for current setup
+nwlookup = {}
+for interface in doc1:
+ iface = {}
+ networks = []
+ for network in interface["assigned_networks"]:
+ nwlookup[network["name"]] = network["id"]
+
+# Find network information in DEA for this node
+nodeInfo = {}
+for node in doc2["nodes"]:
+ if node["id"] == nodeid:
+ nodeInfo=node
+ print "Found nodeinfo for node %d" % nodeid
+
+out = {}
+out["interfaces"] = {}
+
+for interface in doc1:
+ assigned = []
+ nw = {}
+ interface["assigned_networks"] = []
+ try:
+ for nwname in nodeInfo["interfaces"][interface["name"]]:
+ iface = {}
+ iface["id"] = nwlookup[nwname]
+ iface["name"] = nwname
+ interface["assigned_networks"].append(iface)
+ except:
+ print "No match for interface " + interface["name"]
+
+f3 = open(infile, 'w')
+f3.write(yaml.dump(doc1, default_flow_style=False))
+f3.close()
diff --git a/fuel/prototypes/auto-deploy/deploy/tools/transplant_network_scheme.py b/fuel/prototypes/auto-deploy/deploy/tools/transplant_network_scheme.py
new file mode 100755
index 000000000..7d50cbefe
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/tools/transplant_network_scheme.py
@@ -0,0 +1,42 @@
+#!/usr/bin/python
+##############################################################################
+# 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
+##############################################################################
+
+import yaml
+import re
+import sys
+import os
+
+if len(sys.argv) != 4:
+ sys.stderr.write("Usage: "+sys.argv[0]+" <file> <deafile> [compute|controller]\n")
+ sys.exit(1)
+
+file = sys.argv[1]
+if not os.path.exists(file):
+ sys.stderr.write("ERROR: The file "+file+" could not be opened\n")
+ sys.exit(1)
+
+deafile = sys.argv[2]
+namespace = sys.argv[3]
+
+f1 = open(file, 'r')
+doc1 = yaml.load(f1)
+f1.close()
+
+f2 = open(deafile, 'r')
+doc2 = yaml.load(f2)
+f1.close()
+
+doc1["network_scheme"]["transformations"] = doc2[namespace]
+
+f2 = open(file, 'w')
+f2.write(yaml.dump(doc1, default_flow_style=False))
+f2.close()
+
diff --git a/fuel/prototypes/auto-deploy/deploy/tools/transplant_network_settings.py b/fuel/prototypes/auto-deploy/deploy/tools/transplant_network_settings.py
new file mode 100755
index 000000000..c0a46bec0
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/tools/transplant_network_settings.py
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+##############################################################################
+# 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
+##############################################################################
+
+import yaml
+import re
+import sys
+import os
+
+if len(sys.argv) != 3:
+ sys.stderr.write("Usage: "+sys.argv[0]+" <file> <deafile>\n")
+ sys.exit(1)
+
+file = sys.argv[1]
+if not os.path.exists(file):
+ sys.stderr.write("ERROR: The file "+file+" could not be opened\n")
+ sys.exit(1)
+
+deafile = sys.argv[2]
+if not os.path.exists(deafile):
+ sys.stderr.write("ERROR: The file "+deafile+" could not be opened\n")
+ sys.exit(1)
+
+f1 = open(file, 'r')
+doc1 = yaml.load(f1)
+f1.close()
+
+f2 = open(deafile, 'r')
+doc2 = yaml.load(f2)
+f2.close()
+
+# Grab IDs from Fuel version, graft onto DEA version and save
+id = []
+groupid = []
+for nw in doc1["networks"]:
+ id.append(nw["id"])
+ groupid.append(nw["group_id"])
+
+for nw in doc2["network"]["networks"]:
+ nw["id"] = id.pop(0)
+ nw["group_id"] = groupid.pop(0)
+
+f3 = open(file, 'w')
+f3.write(yaml.dump(doc2["network"], default_flow_style=False))
+f3.close()
diff --git a/fuel/prototypes/auto-deploy/deploy/tools/transplant_opnfv_settings.py b/fuel/prototypes/auto-deploy/deploy/tools/transplant_opnfv_settings.py
new file mode 100755
index 000000000..00d095093
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/tools/transplant_opnfv_settings.py
@@ -0,0 +1,42 @@
+#!/usr/bin/python
+##############################################################################
+# 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
+##############################################################################
+
+import yaml
+import re
+import sys
+import os
+
+if len(sys.argv) != 4:
+ sys.stderr.write("Usage: "+sys.argv[0]+" <file> <deafile> [compute|controller]\n")
+ sys.exit(1)
+
+file = sys.argv[1]
+if not os.path.exists(file):
+ sys.stderr.write("ERROR: The file "+file+" could not be opened\n")
+ sys.exit(1)
+
+deafile = sys.argv[2]
+namespace = sys.argv[3]
+
+f1 = open(file, 'r')
+doc1 = yaml.load(f1)
+f1.close()
+
+f2 = open(deafile, 'r')
+doc2 = yaml.load(f2)
+f1.close()
+
+doc1["opnfv"] = doc2["opnfv"][namespace]
+
+f2 = open(file, 'w')
+f2.write(yaml.dump(doc1, default_flow_style=False))
+f2.close()
+
diff --git a/fuel/prototypes/auto-deploy/deploy/tools/transplant_settings.py b/fuel/prototypes/auto-deploy/deploy/tools/transplant_settings.py
new file mode 100755
index 000000000..7f5c0d8e2
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/tools/transplant_settings.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python
+##############################################################################
+# 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
+##############################################################################
+
+import yaml
+import re
+import sys
+import os
+
+if len(sys.argv) != 3:
+ sys.stderr.write("Usage: "+sys.argv[0]+" <file> <deafile>\n")
+ sys.exit(1)
+
+file = sys.argv[1]
+if not os.path.exists(file):
+ sys.stderr.write("ERROR: The file "+file+" could not be opened\n")
+ sys.exit(1)
+
+deafile = sys.argv[2]
+
+f1 = open(deafile, 'r')
+doc = yaml.load(f1)
+f1.close()
+
+out = doc["settings"]
+f2 = open(file, 'w')
+f2.write(yaml.dump(out, default_flow_style=False))
+f2.close()
+
diff --git a/fuel/prototypes/auto-deploy/deploy/verify_dea.sh b/fuel/prototypes/auto-deploy/deploy/verify_dea.sh
new file mode 100755
index 000000000..2054e9f70
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/verify_dea.sh
@@ -0,0 +1,79 @@
+#!/bin/bash -e
+##############################################################################
+# 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
+##############################################################################
+
+
+error_exit()
+{
+ echo "Error: $@"
+ exit 1
+}
+
+if [ $# -ne 1 ]; then
+ echo "Syntax: `basename $0` deafile"
+ exit 1
+fi
+
+if [ ! -f $1 ]; then
+ echo "No such DEA file: $1"
+ exit 1
+fi
+
+tmpdir=$HOME/fueltmp2
+rm -Rf $tmpdir
+mkdir $tmpdir
+
+topdir=$(dirname $(readlink -f $BASH_SOURCE))
+. $topdir/functions/common.sh
+. $topdir/functions/dea-api.sh $1
+
+echo "API version: `dea getApiVersion`"
+
+#echo "Cluster node id for node 1 is: `dea getClusterNodeId 1`"
+
+err=1
+echo "Verifying that expected functions are present..."
+for function in \
+ dea_getApiVersion \
+ dea_getNodeRole \
+ dea_getFuelIp \
+ dea_getFuelNetmask \
+ dea_getFuelGateway \
+ dea_getFuelHostname \
+ dea_getFuelDns \
+ dea_convertMacToShortMac \
+ dea_getProperty \
+ dea_getClusterNodeId \
+ dea
+do
+ if type $function &>/dev/null; then
+ echo "$function: OK"
+ else
+ echo "$function: Missing!"
+ err=0
+ fi
+done
+
+if [ $err -eq 0 ]; then
+ echo "Error in API!"
+ exit 1
+else
+ echo "API functions OK."
+ echo ""
+fi
+
+echo "Fuel IP address: `dea getFuelIp`"
+echo "Fuel netmask: `dea getFuelNetmask`"
+echo "Fuel gateway: `dea getFuelGateway`"
+echo "Fuel hostname: `dea getFuelHostname`"
+echo "Fuel DNS: `dea getFuelDns`"
+echo "Short MAC of 11:22:33:44:55:66: `dea convertMacToShortMac 11:22:33:44:55:66`"
+
+echo "Done"
diff --git a/fuel/prototypes/auto-deploy/deploy/verify_dha.sh b/fuel/prototypes/auto-deploy/deploy/verify_dha.sh
new file mode 100755
index 000000000..6e2b75f44
--- /dev/null
+++ b/fuel/prototypes/auto-deploy/deploy/verify_dha.sh
@@ -0,0 +1,125 @@
+#!/bin/bash -e
+##############################################################################
+# 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
+##############################################################################
+
+error_exit()
+{
+ echo "Error: $@" >&2
+ exit 1
+}
+
+if [ $# -ne 2 ]; then
+ echo "Syntax: `basename $0` adaptername dhafile"
+ exit 1
+fi
+
+if [ ! -f dha-adapters/${1}.sh ]; then
+ echo "No such adapter file: $1"
+ exit 1
+elif [ ! -f $2 ]; then
+ echo "No such DHA file: $2"
+ exit 1
+fi
+
+. dha-adapters/${1}.sh $2
+
+
+err=1
+echo "Verifying that expected functions are present..."
+for function in \
+ dha_getApiVersion \
+ dha_getAdapterName \
+ dha_getAllNodeIds \
+ dha_getFuelNodeId \
+ dha_getNodeProperty \
+ dha_getNodePxeMac \
+ dha_useFuelCustomInstall \
+ dha_fuelCustomInstall \
+ dha_getPowerOnStrategy \
+ dha_nodePowerOn \
+ dha_nodePowerOff \
+ dha_nodeReset \
+ dha_nodeCanSetBootOrderLive \
+ dha_nodeSetBootOrder \
+ dha_nodeCanSetIso \
+ dha_nodeCanHandeIsoLive \
+ dha_nodeInsertIso \
+ dha_nodeEjectIso \
+ dha_waitForIsoBoot \
+ dha_nodeCanZeroMBR \
+ dha_nodeZeroMBR \
+ dha
+do
+ if type $function &>/dev/null; then
+ echo "$function: OK"
+ else
+ echo "$function: Missing!"
+ err=0
+ fi
+done
+
+
+echo "Adapter API version: `dha getApiVersion`"
+echo "Adapter name: `dha getAdapterName`"
+
+echo "All PXE MAC addresses:"
+for id in `(dha getAllNodeIds) | sort`
+do
+ if [ "`dha getAdapterName`" == "libvirt" ]; then
+ libvirtName=`dha getNodeProperty $id libvirtName`
+ else
+ libvirtName=""
+ fi
+
+ if [ $id == "`dha getFuelNodeId`" ]; then
+ echo "$id: `dha getNodeProperty $id pxeMac` $libvirtName <--- Fuel master"
+ else
+ echo "$id: `dha getNodeProperty $id pxeMac` $libvirtName"
+ fi
+done
+
+
+echo -n "Using Fuel custom install: "
+if dha useFuelCustomInstall; then
+ echo "yes"
+else
+ echo "no"
+fi
+
+
+echo -n "Can set boot order live: "
+if dha nodeCanSetBootOrderLive; then
+ echo "yes"
+else
+ echo "no"
+fi
+
+echo -n "Can operate on ISO media: "
+if dha nodeCanSetIso; then
+ echo "yes"
+else
+ echo "no"
+fi
+
+echo -n "Can insert/eject ISO without power toggle: "
+if dha nodeCanHandeIsoLive; then
+ echo "yes"
+else
+ echo "no"
+fi
+
+echo -n "Can erase the boot disk MBR: "
+if dha nodeCanZeroMBR; then
+ echo "yes"
+else
+ echo "no"
+fi
+
+echo "Done"