1
0
mirror of https://github.com/gluster/gluster-block.git synced 2026-02-05 21:45:39 +01:00
Files
gluster-block/extras/replace-node.sh
Prasanna Kumar Kalever 92f46404cb misc: fix bash path
SUSE OBS rpmlint whines about:
[251s] gluster-block.x86_64: E: env-script-interpreter (Badness: 9)
 /usr/lib/gluster-block/upgrade_activities.sh /usr/bin/env bash
 [251s] This script uses 'env' as an interpreter.

Thanks to Kaleb S. Keithley <kkeithle@redhat.com> for reporting this issue.

Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
Reviewed-by: Niels Devos <ndevos@redhat.com>
Reviewed-by: Amar Tumballi <amarts@redhat.com>
2019-05-07 19:05:29 +05:30

577 lines
17 KiB
Bash
Executable File

#!/bin/bash
#************************************************************************#
# #
# Copyright (c) 2017 Red Hat, Inc. <http://www.redhat.com> #
# This file is part of gluster-block. #
# #
# This file is licensed to you under your choice of the GNU Lesser #
# General Public License, version 3 or any later version (LGPLv3 or #
# later), or the GNU General Public License, version 2 (GPLv2), in all #
# cases as published by the Free Software Foundation. #
# #
#************************************************************************#
# How to run this script: #
# ---------------------- #
# $ ./replace-node.sh ${MOUNTPOINT} ${OLDNODE} ${NEWNODE} #
# #
#************************************************************************#
LOGDIR="/var/log/gluster-block/"
function schedule_terminate () {
echo -e "\nholdon! we have received signal, this program will be terminated in the next safe point ..\n"
printLog "Terminating script in the signal handler..."
SAFE_EXIT=1
fdClose ${fd}
}
function getAvailableFd() {
for i in {1..65536}; do
if [ ! -e /proc/$$/fd/${i} ]; then
echo ${i};
return 0;
fi
done
return 1;
}
function fdOpen() {
local fd=${1}
local path=${2}
# open in read mode
eval "exec ${fd}<${path}"
}
function fdClose() {
local fd=${1}
eval "exec ${fd}>&-"
}
function printLog() {
local msg=${1}
echo "[$(date -u +'%Y-%m-%d %I:%M:%S')] ${msg}" >> ${LOGDIR}/gluster-block-replace.log
}
function readMetaInfo() {
while read line; do
METADATA+=(["$(echo ${line} | cut -d: -f1)"]=$(echo ${line} | cut -d' ' -f2 | tr -d " \n"))
done < ${1}
}
function isStrPartOfArray() {
local args=("${@}")
local str=${args[0]}
local array=${args[@]:1}
for i in ${array[@]}; do
if [ "${str}" == "${i}" ]; then
return 0;
fi
done
return 1;
}
function isStatusValid() {
local status=${1}
case "${status}" in
"CONFIGSUCCESS" | "CLEANUPINPROGRESS" | "AUTHENFORCEING" | "AUTHENFORCED" | "AUTHENFORCEFAIL" | "AUTHCLEARENFORCED" | "AUTHCLEARENFORCEING" | "AUTHCLEARENFORCEFAIL")
return 0;
;;
esac
return 1;
}
function getValidHosts() {
eval "declare -A metadata="${1#*=}
local validHostsArr=()
local commonKeys=(VOLUME GBID SIZE HA ENTRYCREATE PASSWORD)
for index in ${!metadata[@]}; do
isStrPartOfArray "${index}" "${commonKeys[@]}"
ret=$?
if [[ ${ret} -ne 0 ]]; then
isStatusValid ${metadata["${index}"]}
ret=$?
if [[ ${ret} -ne 1 ]]; then
validHostsArr+=("${index}")
fi
fi
done
unset metadata
echo "${validHostsArr[@]}" # return
}
function runCreate() {
eval "declare -A metadata="${1#*=}
local block_name=${2}
local old_node=${3}
local new_node=${4}
local iqn_prefix="iqn.2016-12.org.gluster-block"
local gbid=${metadata["GBID"]}
local hosts=( $(getValidHosts "$(declare -p metadata)") )
local subcmd1="\$(targetcli /backstores/user:glfs ls | grep ' ${block_name} ' -c)"
local subcmd2="targetcli set global auto_add_default_portal=false auto_enable_tpgt=false loglevel_file=info logfile=${LOGFILE}\n
targetcli /backstores/user:glfs create ${block_name} ${metadata["SIZE"]} ${metadata["VOLUME"]}@${new_node}/block-store/${gbid} ${gbid}\n
targetcli /backstores/user:glfs/${block_name} set attribute cmd_time_out=0\n
targetcli /iscsi create ${iqn_prefix}:${gbid}\n"
for index in ${!hosts[@]}; do
NODE=${hosts[$index]}
if [[ "${NODE}" == "${old_node}" ]]; then
NODE=${new_node}
fi
no=$(expr ${index} + 1)
if [[ ${no} -ne 1 ]]; then
subcmd2+="targetcli /iscsi/${iqn_prefix}:${metadata["GBID"]} create tpg${no}\n"
fi
if [[ "${NODE}" == "${new_node}" ]]; then
subcmd2+="targetcli /iscsi/${iqn_prefix}:${gbid}/tpg${no}/luns create /backstores/user:glfs/${block_name}\n
targetcli /iscsi/${iqn_prefix}:${gbid}/tpg${no}/portals create ${NODE}\n
targetcli /iscsi/${iqn_prefix}:${gbid}/tpg${no} enable\n
targetcli /iscsi/${iqn_prefix}:${gbid}/tpg${no} set attribute generate_node_acls=1 demo_mode_write_protect=0\n"
else
subcmd2+="targetcli /iscsi/${iqn_prefix}:${gbid}/tpg${no}/luns create /backstores/user:glfs/${block_name}\n
targetcli /iscsi/${iqn_prefix}:${gbid}/tpg${no}/portals create ${NODE}\n
targetcli /iscsi/${iqn_prefix}:${gbid}/tpg${no} set attribute tpg_enabled_sendtargets=0 generate_node_acls=1 demo_mode_write_protect=0\n"
fi
if [[ "x${metadata["PASSWORD"]}" != "x" ]]; then
subcmd2+="targetcli /iscsi/${iqn_prefix}:${gbid}/tpg${no} set auth userid=${gbid} password=${metadata["PASSWORD"]}\n"
fi
done
subcmd2+="targetcli / saveconfig"
cmd="if [[ ${subcmd1} -eq 0 ]]; then ${subcmd2}; else echo "skipped"; fi"
unset metadata
IFS=' '
eval $(printf "${cmd}") # exec
}
function runReplace() {
eval "declare -A metadata="${1#*=}
local old_node=${2}
local new_node=${3}
local iqn_prefix="iqn.2016-12.org.gluster-block"
local gbid=${metadata["GBID"]}
local tpgno=$(targetcli /iscsi/${iqn_prefix}:${gbid} ls | grep -e tpg -e " ${old_node}:" | grep -B1 " ${old_node}:" | grep -o "tpg[0-9]*")
local subcmd="targetcli /iscsi/${iqn_prefix}:${gbid}/${tpgno}/portals create ${new_node};
targetcli /iscsi/${iqn_prefix}:${gbid}/${tpgno}/portals delete ip_address=${old_node} ip_port=3260;
targetcli / saveconfig"
cmd="if [[ "x" != "${tpgno}x" ]]; then ${subcmd}; else echo "skipped"; fi"
unset metadata
IFS=' '
eval $(printf "${cmd}") # exec
}
function runDelete() {
eval "declare -A metadata="${1#*=}
local block_name=${2}
local iqn_prefix="iqn.2016-12.org.gluster-block"
local gbid=${metadata["GBID"]}
local subcmd1="\$(targetcli /backstores/user:glfs ls | grep ' ${block_name} ' | grep '/${gbid} ' -c)"
local subcmd2="targetcli /backstores/user:glfs delete ${block_name};
targetcli /iscsi delete ${iqn_prefix}:${gbid};
targetcli / saveconfig"
cmd="if [[ ${subcmd1} -gt 0 ]]; then ${subcmd2}; else echo "skipped"; fi"
unset metadata
IFS=' '
eval $(printf "${cmd}") # exec
}
function parseCreateOutput() {
eval "declare -A metadata="${1#*=}
local block_name=${2}
local new_node=${3}
local output=()
output="$(cat /tmp/gb_create)"
if [[ "${output}" == "skipped" ]]; then
printLog "WARNING: create: creating ${block_name} on ${new_node} skipped"
return 1;
fi
output=("$(cat /tmp/gb_create | awk '/Created user-backed storage/{flag=1} /Created TPG 1/{flag=0} flag')")
local i=1;
while [ $i -le ${metadata["HA"]} ]; do
output+=("$(cat /tmp/gb_create | awk "/Created TPG $i/{flag=1} /Created TPG $(expr $i + 1)/{flag=0} flag")")
i=`expr $i + 1`
done
for index in ${!output[@]}; do
if [[ ${index} -eq 0 ]]; then
if [[ ${output["${index}"]} != *"Created user-backed storage object ${block_name} size ${metadata["SIZE"]}."* ]]; then
printLog "ERROR: create: create user-backed storage object for ${block_name} with size ${metadata["SIZE"]} failed"
return 1;
fi
if [[ ${output["${index}"]} != *"Parameter cmd_time_out is now '0'."* ]]; then
printLog "ERROR: create: setting cmd_time_out=0 for ${block_name} failed"
return 1;
fi
if [[ ${output["${index}"]} != *"Created target iqn.2016-12.org.gluster-block:${metadata["GBID"]}."* ]]; then
printLog "ERROR: create: create target for ${block_name} failed"
return 1;
fi
else
if [[ ${output["${index}"]} != *"Created TPG ${index}."* ]]; then
printLog "ERROR: create: create TPG ${index} failed for ${block_name}"
return 1;
fi
if [[ ${output["${index}"]} != *"Created LUN 0."* ]]; then
printLog "ERROR: create: creation of LUN 0 for ${block_name} on tpg ${index} failed"
return 1;
fi
if [[ ${output["${index}"]} != *"Using default IP port 3260"* ]]; then
printLog "ERROR: create: using default portal failed for ${block_name} on tpg ${index}"
return 1;
fi
if [[ ${output["${index}"]} != *"Created network portal"* ]]; then
printLog "ERROR: create: creation of portal failed for ${block_name} on tpg ${index}"
return 1;
fi
if [[ ${output["${index}"]} != *"Parameter generate_node_acls is now '1'."* ]]; then
printLog "ERROR: create: setting generate_node_acls=1 failed for ${block_name} on tpg ${index}"
return 1;
fi
if [[ ${output["${index}"]} != *"Parameter demo_mode_write_protect is now '0'."* ]]; then
printLog "ERROR: create: setting demo_mode_write_protect=0 failed for ${block_name} on tpg ${index}"
return 1;
fi
if [[ ${output["${index}"]} == *"${new_node}"* ]]; then
if [[ ${output["${index}"]} != *"The TPGT has been enabled."* ]]; then
printLog "ERROR: create: enabling TPGT failed for ${block_name} on tpg ${index} & portal ${new_node}"
return 1;
fi
else
if [[ ${output["${index}"]} != *"Parameter tpg_enabled_sendtargets is now '0'."* ]]; then
printLog "ERROR: create: setting tpg_enabled_sendtargets=0 failed for ${block_name} on tpg ${index}"
return 1;
fi
fi
fi
done
unset metadata
return 0;
}
function parseReplaceOutput() {
local output=${1}
local block_name=${2}
local old_node=${3}
local new_node=${4}
if [[ "${output}" == "skipped" ]]; then
printLog "WARNING: replace: replacing network portal ${old_node}:3260 for ${block_name} skipped"
return 1;
fi
if [[ ${output} != *"Deleted network portal ${old_node}:3260"* ]]; then
printLog "ERROR: replace: deleting network portal ${old_node}:3260 for ${block_name} failed"
return -1;
fi
if [[ ${output} != *"Using default IP port 3260"* ]]; then
printLog "ERROR: replace: using default portal for ${block_name} failed"
return -1;
fi
if [[ ${output} != *"Created network portal ${new_node}:3260."* ]]; then
printLog "ERROR: replace: creation of portal ${new_node} for ${block_name} failed"
return -1;
fi
return 0;
}
function parseDeleteOutput() {
local output=${1}
local block_name=${2}
local gbid=${3}
local iqn_prefix="iqn.2016-12.org.gluster-block"
if [[ "${output}" == "skipped" ]]; then
printLog "WARNING: delete: deleting storage object ${block_name} skipped"
return 1;
fi
if [[ ${output} != *"Deleted storage object ${block_name}."* ]]; then
printLog "ERROR: delete: deleting storage object ${block_name} failed"
return -1;
fi
if [[ ${output} != *"Deleted Target ${iqn_prefix}:${gbid}."* ]]; then
printLog "ERROR: delete: deleting target ${iqn_prefix}:${gbid} of ${block_name} failed"
return -1;
fi
return 0;
}
function readMetaInfo() {
while read line; do
METADATA+=(["$(echo ${line} | cut -d: -f1)"]=$(echo ${line} | cut -d' ' -f2 | tr -d " \n"))
done < ${1}
}
function takeLockInit() {
local fd=${1}
# ignore signals till trap setting
trap '' INT TERM QUIT
flock -x ${fd}
if [[ ${?} -ne 0 ]]; then
printLog "failed to take lock"
exit 1;
fi
}
function releaseLockExit() {
local fd=${1}
flock -u ${fd}
if [[ ${?} -ne 0 ]]; then
printLog "failed to release lock"
exit 1;
fi
# trap open for very short duration
trap schedule_terminate INT TERM QUIT
sleep 1;
}
function usage() {
cat <<USAGE
Usage:
./replace-node.sh \${MOUNTPOINT} \${OLDNODE} \${NEWNODE}
USAGE
}
# start main
if [[ ${#} -ne 3 ]]; then
usage
exit 1;
fi
MOUNTPOINT=${1}
OLDNODE=${2}
NEWNODE=${3}
DIR=${MOUNTPOINT}/block-meta/
if [[ ! -d "${DIR}" ]]; then
echo "Fuse mount point, does not have directory '${DIR}'"
usage
exit 1;
fi
mkdir -p ${LOGDIR}
printLog "Starting replace node job, mount-point=${MOUNTPOINT} old-node=${OLDNODE} new-node=${NEWNODE}"
# Fetch an available fd
fd=$(getAvailableFd)
if [[ ${?} -ne 0 ]]; then
printLog "no free fd's available on the node"
exit 1;
fi
fdOpen ${fd} ${DIR}/meta.lock
SAFE_EXIT=0
for BLOCKNAME in $(ls ${DIR}); do
declare -A METADATA
# handle last signal (aka safe point)
if [[ ${SAFE_EXIT} -eq 1 ]]; then
echo "exiting in a safe point :)"
printLog "exiting in a safe point..."
exit 1;
fi
takeLockInit ${fd}
if [[ ${BLOCKNAME} == "meta.lock" ]]; then
continue;
fi
readMetaInfo "${DIR}/${BLOCKNAME}"
HOSTS=( $(getValidHosts "$(declare -p METADATA)") )
echo "blockname: ${BLOCKNAME}"
skip=0;
if [[ $(echo "${!METADATA[@]} " | grep -c " ${OLDNODE} ") -eq 0 ]]; then
echo "${OLDNODE} not configured for this block."
echo "-------------------------------------"
printLog "INFO: ${BLOCKNAME} not configured on ${OLDNODE}, skipping replace..."
skip=1;
fi
if [[ skip -eq 1 ]]; then
# unset variables
unset HOSTS
unset METADATA
releaseLockExit ${fd}
continue;
fi
ssh root@${NEWNODE} "LOGFILE=${LOGDIR}/gluster-block-configshell.log; $(declare -f isStrPartOfArray isStatusValid getValidHosts runCreate); runCreate '$(declare -p METADATA)' ${BLOCKNAME} ${OLDNODE} ${NEWNODE}" > /tmp/gb_create
parseCreateOutput "$(declare -p METADATA)" ${BLOCKNAME} ${NEWNODE}
ret=$?
echo "" > /tmp/gb_create # clear
if [[ ${ret} -eq 0 ]]; then
echo "${OLDNODE}: CLEANUPSUCCESS" >> "${DIR}/${BLOCKNAME}"
echo "${NEWNODE}: CONFIGSUCCESS" >> "${DIR}/${BLOCKNAME}"
echo "create on '${NEWNODE}' success"
printLog "INFO: create of ${BLOCKNAME} on ${NEWNODE} success"
elif [[ ${ret} -eq 1 ]]; then
echo "create on '${NEWNODE}' skipped"
printLog "WARNING: create of ${BLOCKNAME} on ${NEWNODE} skipped"
else
echo "create on '${NEWNODE}' failed"
printLog "ERROR: create of ${BLOCKNAME} on ${NEWNODE} failed"
printLog "INFO: skipping replace and delete for ${BLOCKNAME}"
echo "-------------------------------------"
# unset variables
unset HOSTS
unset METADATA
releaseLockExit ${fd}
continue;
fi
for NODE in ${HOSTS[@]}; do
if [[ "${NODE}" != "${OLDNODE}" && "${NODE}" != "${NEWNODE}" ]]; then
REPLACEOUT=$(ssh root@${NODE} "$(declare -f runReplace); runReplace '$(declare -p METADATA)' ${OLDNODE} ${NEWNODE}")
parseReplaceOutput "${REPLACEOUT}" ${BLOCKNAME} ${OLDNODE} ${NEWNODE}
ret=$?
if [[ ${ret} -eq 0 ]]; then
echo "replace on '${NODE}' success"
printLog "INFO: replace of ${BLOCKNAME} on ${NODE} success"
elif [[ ${ret} -eq 1 ]]; then
echo "replace on '${NODE}' skipped"
printLog "WARNING: replace of ${BLOCKNAME} on ${NODE} skipped"
else
echo "replace on '${NODE}' failed"
printLog "ERROR: replace of ${BLOCKNAME} on ${NODE} failed"
fi
unset REPLACEOUT
fi
done
DELETEOUT=$(ssh root@${OLDNODE} "$(declare -f runDelete); runDelete '$(declare -p METADATA)' ${BLOCKNAME}")
parseDeleteOutput "${DELETEOUT}" ${BLOCKNAME} ${METADATA["GBID"]}
ret=$?
if [[ ${ret} -eq 0 ]]; then
echo "delete on '${OLDNODE}' success"
printLog "INFO: delete of ${BLOCKNAME} on ${OLDNODE} success"
elif [[ ${ret} -eq 1 ]]; then
echo "delete on '${OLDNODE}' skipped"
printLog "WARNING: delete of ${BLOCKNAME} on ${OLDNODE} skipped"
else
echo "delete on '${OLDNODE}' failed"
printLog "ERROR: delete of ${BLOCKNAME} on ${OLDNODE} failed"
fi
unset DELETEOUT
echo "-------------------------------------"
# unset variables
unset HOSTS
unset METADATA
releaseLockExit ${fd}
done
printLog "Finished replace node job, mount-point=${MOUNTPOINT} old-node=${OLDNODE} new-node=${NEWNODE}"
fdClose ${fd}