Restoring a controller team


NOTE: Before running this script, re-install the controller. Otherwise an Error 404 condition results and the controller is not restored. See “Restoring a controller from a backup ”.

Because the scripts in this appendix cross page boundaries, be careful to avoid including the page number when copying a script. Copying a script one page at a time can prevent inclusion of page numbers.


#!/bin/bash
#-------------------------------------------------------------------------------
# Copyright 2013 Hewlett Packard Co., All Rights Reserved. 
#-------------------------------------------------------------------------------
#
# Restore a Team 
#-------------------------------------------------------------------------------
export BACKUP_DIR="/opt/sdn/backup" 
export BACKUP_TEAM_DIR="/opt/sdn/team_backup" 
export RESTORE_TEAM_DIR="/opt/sdn/team_restore"
export TEAM_BACKUP_STATUS_FILE="$RESTORE_TEAM_DIR/teamRestore_status" 
export TEAM_BACKUP_LOGFILE="$RESTORE_TEAM_DIR/teamRestore_log.log" 
export RESTORE_BACKUP_FILESET="$RESTORE_TEAM_DIR/opt/sdn/team_backup" 
export B_PID=$$ 
trap "exit 1" TERM 
#==============================================================================
# F U N C T I O N S
#==============================================================================
#------------------------------------------------------------------------------
# Function extract_zip_and_ip ( ) 
# Extracts the team backup zip and the backed up IP addresses.
#------------------------------------------------------------------------------
function extract_zip_and_ip { 
unzip -o "$RESTORE_TEAM_DIR/sdn_team_backup*" -d $RESTORE_TEAM_DIR
if [ $? -ne 0 ]; then 
teamBackup_log "Failed to unzip the team backup file." 
exitBackup 1
fi
teamBackup_log "Extracted the team backup file successfully."
rm -rf "$RESTORE_TEAM_DIR/sdn_team_backup*" 
backupIp=($(ls $RESTORE_BACKUP_FILESET | grep "zip$" | sed "s/.zip//" | \ 
sed "s/.Leader//" | sed "s/sdn_controller_backup_//")) 
numBackup=${#backupIp[@]} 
teamBackup_log "Found $numBackup backup file sets in the team backup file." 
}
#------------------------------------------------------------------------------
# Function create_restoreDir ( ) 
# Creates the team restore directory.
#------------------------------------------------------------------------------
function create_restoreDir { 
rm -rf $RESTORE_TEAM_DIR 
mkdir $RESTORE_TEAM_DIR
chmod 777 $RESTORE_TEAM_DIR 
}
#------------------------------------------------------------------------------
# Function validate_my_Ip ( ) 
# Validates the configured node IP against the backed up IP addresses.
#------------------------------------------------------------------------------
function validate_my_Ip { 
for (( v=0; v<numBackup; v++ )); do 
myip=`ifconfig|grep -o "${backupIp[$v]}"`
if [ "$myip" != "" ]; then 
teamBackup_log "IP $myip is a valid member of the team." 
return
fi
done
teamBackup_log "IP $myip is not a valid member of the team, exiting." 
exitBackup 1 
}
#------------------------------------------------------------------------------
# Function upload_backup_file ( <systemIp> <systemUUID> <authToken> <zipFile> ) 
# Uploads backup file to the specific nodes of the team.
#------------------------------------------------------------------------------
function upload_backup_file { 
local sysIp=$1 
local sysUUID=$2
local sysAuth=$3
local uploadUrl="https://$sysIp:8443/sdn/v2.0/restore/backup" 
local zipFile=$4
if [ ! -f $zipFile ]; then
teamBackup_log "File $zipFile does not exist."
exitBackup 1 
fi
curl --noproxy $sysIp -X POST --fail -ksSfL --url $uploadUrl \ 
-H "X-Auth-Token:$sysAuth"\
--data-binary @$zipFile
if [ $? -ne 0 ]; then
teamBackup_log "Failed to upload backup $zipFile to $sysIp."
exitBackup 1 
fi
teamBackup_log "Backup $zipFile uploaded successfully to $sysIp."
}
#------------------------------------------------------------------------------
# Function restore_node ( <systemIp> <systemUUID> <authToken> ) 
# Restores a particular node. 
#------------------------------------------------------------------------------
function restore_node { 
local sysIp=$1
local sysUUID=$2 
local sysAuth=$3
local restoreUrl="https://$sysIp:8443/sdn/v2.0/restore"
# Set the IP first. Ignore errors since this only works for standalone.
put $sysIp $sysAuth "https://$sysIp:8443/sdn/v2.0/systems/$sysUUID" \
"{\"system\":{\"ip\":\"$sysIp\"}}" > /dev/null 2>&1 
restoreSession=`post $sysIp $sysAuth $restoreUrl ` 
if [ $errorCode -ne 0 ]; then
teamBackup_log "Failed to start restore on node $sysIp."
exitBackup 1
fi
teamBackup_log "Started restore on node $sysIp." 
}
#------------------------------------------------------------------------------
# Function validate_node_status ( )
# Validates node status after the restore. 
#------------------------------------------------------------------------------
function validate_node_status { 
local sysIp=$1 
# Wait for the restore to complete. 
local sysUrl="https://$sysIp:8443/sdn/v2.0/systems"
for (( k=0; k<100; k++ )); do 
sleep 30 
authToken=`getAuthToken $sysIp`
[ "$authToken" == "" ] && continue
# Try to contact the system.
data=`get $sysIp $authToken "$sysUr?ip=$sysIp"` 
[ "$data" == "" ] && continue
teamBackup_log "Node:$sysIp came up successfully." && return  
done
teamBackup_log "Node:$sysIP failed to come up." 
exitBackup 1 
}
#------------------------------------------------------------------------------ 
# Function restore_nodes ( <ipAddrArray> ) 
# Restores only the specified node(s). 
#------------------------------------------------------------------------------
function restore_nodes {
local leaderindex=-1 
local restoreIpArr=("$@")
local numNodes=${#restoreIpArr[@]} 
for (( i=0; i<$numNodes; i++ )); do 
# Get the auth token for a specific node. 
restoreAuth[$i]=`getAuthToken ${restoreIpArr[$i]}` 
if [ "${restoreAuth[$i]}" == "" ]; then 
teamBackup_log "Failed to get the auth Token for ${restoreIpArr[$i]}, can't start restore."
exitBackup 1 
fi
uuidURL="https://${restoreIpArr[$i]}:8443/sdn/v2.0/systems"
restoreUUID[$i]=`get ${restoreIpArr[$i]} ${restoreAuth[$i]} "$uuidURL"` 
if [ "${restoreUUID[$i]}" == "" ]; then 
teamBackup_log "Failed to get the UUID for ${restoreIpArr[$i]}, can't start restore."
exitBackup 1 
fi
restoreUUID[$i]=`extractJSONString "${restoreUUID[$i]}" "uid" | sed '/^$/d'` 
teamBackup_log "UUID for ${restoreIpArr[$i]} is ${restoreUUID[$i]}" 
# Upload the backup files to a specific node. 
local ipFileName="sdn_controller_backup_${restoreIpArr[$i]}*.zip" 
local zipFile=`ls $RESTORE_BACKUP_FILESET/$ipFileName`
upload_backup_file ${restoreIpArr[$i]} ${restoreUUID[$i]} \ 
${restoreAuth[$i]} $zipFile
# Check if this is the leader node from the backup set. 
local leaderZip=`echo $zipFile|grep "Leader"` 
[ "$leaderZip" != "" ] && leaderIndex=$I
done 
# Start restore in the leader node first before all the other nodes. 
if [ $leaderIndex -ne -1 ]; then 
restore_node ${restoreIpArr[$leaderIndex]} ${restoreUUID[$leaderIndex]} \
${restoreAuth[$leaderIndex]} 
fi
# Verify the leader node is up after the restore. 
validate_node_status ${restoreIpArr[$leaderIndex]} 
# Continue restore on the remaining nodes. 
for (( i=0; i<$numNodes; i++ )); do 
# Skip the leader node; it's already done.
[ $i -eq $leaderIndex ] && continue 
# Restore the specified node.
restore_node ${restoreIpArr[$i]} ${restoreUUID[$i]} ${restoreAuth[$i]} 
done
sleep 200 
# Validate that the restored nodes are up. 
for (( n=0; n<$numNodes; n++ )); do 
# Skip the leader node; it's already done. 
[ $n -eq $leaderIndex ] && continue
validate_node_status ${restoreIpArr[$n]}
done
}
#------------------------------------------------------------------------------ 
# Function teamBackup_log ( <message> )
# Writes messages to the log for the team backup operation. 
#------------------------------------------------------------------------------
function teamBackup_log {
msg="$1"
echo "$msg" |tee -a $TEAM_BACKUP_LOGFILE
}
#------------------------------------------------------------------------------
# Function exitBackup ( <exitStatus> )
# Exits the backup.
#------------------------------------------------------------------------------
function exitBackup {
[ $1 -ne 0 ] && teamBackup_log "Stopping backup/restore with errors."
rm -rf $TEAM_BACKUP_STATUS_FILE
kill -s TERM $B_PID 
exit $1
}
#------------------------------------------------------------------------------
# Function get ( <ipAddr> <authToken> <url> ) 
# Performs a GET.
#------------------------------------------------------------------------------
function get {
local getIP=$1
local getToken=$2
local getUrl=$3 
local attempts=0 
while [ $attempts -lt 5 ]; do
curl --noproxy $getIP --header "X-Auth-Token:$getToken" \ 
--fail -ksS -L -f --request GET --url "$getUrl"
errorCode=$
?
let "attempts = $attempts + 1" 
if [ 35 -eq $errorCode ]; then
teamBackup_log "SSL error on GET of $getUrl, retrying..."
continue; 
fi
break; 
done
}
#------------------------------------------------------------------------------
# Function post ( <ipAddr> <authToken> <url> <data>)
# Performs a POST of the specified data. 
#------------------------------------------------------------------------------
function post { 
local postIP=$1 
local postToken=$2
local postUrl=$3 
local postData=$4
local attempts=0
while [ $attempts -lt 5 ]; do
postRes=`curl --noproxy $postIP --header "X-Auth-Token:$postToken" \
--fail -ksS --request POST --url "$postUrl" --data-binary "$postData"`
errorCode=$? 
let "attempts = $attempts + 1"
if [ 35 -eq $errorCode ]; then
teamBackup_log "SSL error on POST to $postUrl, retrying..." 
continue;
fi
break;
done
echo $postRes
}
#------------------------------------------------------------------------------
# Function put ( <ipAddr> <authToken> <url> <data> )
# Performs a PUT of the specified data.
#------------------------------------------------------------------------------
function put {
local putIP=$1
local putToken=$2
local putUrl=$3
local putData=$4
local attempts=0 
while [ $attempts -lt 5 ]; do 
putRes=`curl --noproxy $putIP --header "X-Auth-Token:$putToken" \
--fail -ksS -L -f --request PUT "$putUrl" --data-binary "$putData"`
errorCode=$?
let "attempts = $attempts + 1"
if [ 35 -eq $errorCode ]; then
teamBackup_log "SSL error on POST to $putUrl, retrying" 
continue;
fi
break;
done
echo $putRes
}
#------------------------------------------------------------------------------
# Function extractJSONString ( <json> <fieldName> ) 
# Extracts the Json value corresponding to the field name. 
#------------------------------------------------------------------------------
function extractJSONString {
json=$1
field=$2
json=`echo $json|tr -d '"'| sed -e 's/\,\|{/\n/g'|grep -w "$field"| \
cut -d ':' -f2-` 
echo $json 
}
#------------------------------------------------------------------------------
# Function getAuthToken ( <ipAddr> ) 
# Log-in and get the UID.
#------------------------------------------------------------------------------
function getAuthToken {
local nodeIP=$1 
url="https://$nodeIP:8443/sdn/v2.0/auth"
login="{
\"login\": {
\"domain\": \"$domain\",
\"user\": \"$user\", 
\"password\": \"$pass\"
}
}
}" 
# Attempt to authenticate and extract token if successful. 
auth=$(curl --noproxy $nodeIP -X POST --fail -ksSfL --url "$url" \
-H "Content-Type: application/json" --data-binary "$login" 2>&1)
if [ $? -ne 0 ]; then
teamBackup_log "Unable to authenticate as user $user in $domain domain."
exitBackup 1
fi
authToken=`extractJSONString "$auth" "token" | sed '/^$/d'` 
if [ $restore_mode -ne 1 ] && [ "$authToken" == "" ]; then
teamBackup_log "Failed to get the authentication token." 
exitBackup 1
fi
echo $authToken
}
#==============================================================================
# M A I N
#==============================================================================
restore_mode=1 
selective_restore=0
# Check for unzip package.
command -v unzip &> /dev/null 
if [ $? -ne 0 ]; then 
echo "The unzip package must be installed to use this script."
exit 1 
fi
# Check the user specified script parameters. 
if [ $# -lt 3 ]; then
echo "Usage : restoreTeam <user> <domain> [<ip1> <ip2> ...] <user@IP:path>"
echo " <user> - user name to access the controller"
echo " <domain> - domain of the controller"
echo " [<ip1> <ip2> ...] - ip(s) of node(s) to be restored; if none are specified all nodes are restored"
echo " <user@IP:path> - remote location to retrieve backup file" 
echo " user - the login name for the system" 
echo " ip - the ip address of the system" 
echo " path - where to copy the file from on the remote system"
exit 1
fi
create_restoreDir
user="$1"
echo -n "Enter Controller Password: "
read -s pass
echo
domain="$2"
file="" 
if [ $# -eq 3 ]; then
teamBackup_log "Starting the team restore. This will restore all the nodes in a team."
file=$3
else
teamBackup_log "Starting selective restore on specified IPs. This restore will happen only on the specified nodes." 
count=0
selective_restore=1
for ip in "$@"; do
restoreIp[$count]=$ip
let "count = $count + 1"
done
fileIndex=$(($# - 1))
file=${restoreIp[$fileIndex]} && unset restoreIp[$fileIndex] 
fi
# Upload the team backup file from the user specified location.
scp $file $RESTORE_TEAM_DIR
if [ $? -ne 0 ]; then
teamBackup_log "Failed to upload team backup file to the node."
exitBackup 1
fi
# Unzip the team backup file.
extract_zip_and_ip
# Validate the IP address of the node.
validate_my_Ip
# Restore the node(s).
if [ $selective_restore -eq 1 ]; then
restore_nodes ${restoreIp[@]}
else
restore_nodes ${backupIp[@]}
fi
echo
teamBackup_log "The team was restored successfully."
exitBackup 0