#!/bin/bash ############################################################ # # Find the differences of instance A and instance B and produce helper files. # Note: This script does not use AWS CLI but instead uses results from # connect_save on instance A and B. # VERSION=1.3.5 SCRIPT_VERSION="$(basename $0) $VERSION" USAGE=$(cat <<EOD Usage: $(basename $0) [-?fev] [-l lambda_prefix_a=lambda_prefix_b] [-b lex_bot_prefix_a=lex_bot_prefix_b] instance_alias_a instance_alias_b helper Based on connect_save result on Amazon Connect instance A and B, find the differences and produce helper files to safely copy components from A to B. instance_alias_a Alias of the Connect instance A instance_alias_b Alias of the Connect instance B (Aliases can be a path to the directory where the instance was saved using connect_save.) helper Name of the helper directory -f Force removal of existing helper directory -e Proceed even when the system may not encode Extended ASCII characters properly -v Show version of this script -l lambda_prefix_a=lambda_prefix_b Lambda function name prefixes for instances A and B (if different) to be replaced during copying -b lex_bot_prefix_a=lex_bot_prefix_b Lex bot (Classic) name prefixes for instances A and B (if different) to be replaced during copying -? Help Note: This script create files in the helper directory without changing any instance component files. EOD ) usage() { echo -e "$USAGE" >&2; exit 2; } version() { echo -e "$SCRIPT_VERSION"; exit; } dos2unix() { tr -d '\r'; } error() { echo -e "Error: $1" >&2; exit 1; } hex_cmd= if [ -x "$(command -v xxd)" ]; then hex_cmd="xxd -u -p -c1" elif [ -x "$(command -v hexdump)" ]; then hex_cmd="hexdump -v -e '/1 \"%02X\n\"'" elif [ -x "$(command -v od)" ]; then hex_cmd="od -An -vtx1 | tr [:lower:] [:upper:] | for i in \$(cat); do echo \$i; done" fi test -z "$hex_cmd" && error "Cannot find any hex conversion commands. Please install one of these: xxd, hexdump, od" hex_code() { printf '%s' "$1" | eval "$hex_cmd" | while read x; do printf "%%%s" "$x"; done } path_encode() { old_lc_collate=$LC_COLLATE LC_COLLATE=C local length="${#1}" for (( i = 0; i < length; i++ )); do local c="${1:$i:1}" case $c in [a-zA-Z0-9.~_-]) printf '%s' "$c";; *) x=$(hex_code "$c"); echo -n ${x//%0D/};; esac done LC_COLLATE=$old_lc_collate } add_file() { alias_dir="$1" file_suffix="$2" helper_file="$3" if [ ! -s "$alias_dir/$file_suffix" ]; then error "File missing or empty: $alias_dir/$file_suffix" exit 1 else echo "$file_suffix" >> $helper_file fi } forced= ignore_improper_extended_ascii= lambda_prefix_a= lambda_prefix_b= lex_bot_prefix_a= lex_bot_prefix_b= while getopts "?fevl:b:" arg; do case "$arg" in f) forced=on;; e) ignore_improper_extended_ascii=on;; v) version;; l) lambda_prefix_a=${OPTARG%%=*} lambda_prefix_b=${OPTARG#*=} ;; b) lex_bot_prefix_a=${OPTARG%%=*} lex_bot_prefix_b=${OPTARG#*=} ;; *) usage;; esac done shift $((OPTIND-1)) if [ "$(hex_code "é")" != "%C3%A9" ]; then echo "WARNING: This system may not encode Extended ASCII characters properly." >&2 if [ -n "$ignore_improper_extended_ascii" ]; then echo "Proceed regardless as the -e option is specified." >&2 else cat <<EOD >&2 If your instance component names contain Extended ASCII characters, such as accented letters like é, this system will encode those names differently from standard encoding. If you are sure that your component names do not contain Extended ASCII characters, you may proceed regardless by running the command again with the -e option. EOD exit 1 fi fi instance_alias_dir_a=$1 instance_alias_a=$(basename "$instance_alias_dir_a") instance_alias_dir_b=$2 instance_alias_b=$(basename "$instance_alias_dir_b") # helper=${3:-${instance_alias_a}_TO_${instance_alias_b}} helper=$3 # Backward compatibility - if they are set, ignore the arguments lambda_prefix_a=${lambda_prefix_a:-$4} lambda_prefix_b=${lambda_prefix_b:-$5} if [ -z "$instance_alias_a" -o -z "$instance_alias_b" -o -z "$helper" ]; then usage fi if [ -d $helper ]; then if [ -n "$forced" ]; then echo "Existing Helper directory forcefully removed: $helper" rm -fr $helper else error "Helper directory already exists. Remove and try again (or use -f): $helper" fi fi # routing_profile_to_ignore="Basic Routing Profile" flow_template=$helper/flow_template.json module_template=$helper/module_template.json cat <<EOD Instance Alias A: $instance_alias_a (in directory "$instance_alias_dir_a") Instance Alias B: $instance_alias_b (in directory "$instance_alias_dir_b") Helper: $helper EOD errorMsg= if [ ! -d "$instance_alias_dir_a" ]; then errorMsg="$errorMsg \"$instance_alias_dir_a\"" fi if [ ! -d "$instance_alias_dir_b" ]; then errorMsg="$errorMsg \"$instance_alias_dir_b\"" fi if [ -n "$errorMsg" ]; then errorMsg="Cannot find instance directories:$errorMsg" error "$errorMsg" fi mkdir -p $helper for ext in var sed new old; do eval helper_$ext=$helper/helper.$ext eval fn=\$helper_$ext > $fn done ############################################################ # # Instance # echo "instance_alias_a=\"$instance_alias_a\"" | tee -a $helper_var echo "instance_alias_dir_a=\"$instance_alias_dir_a\"" | tee -a $helper_var echo "instance_alias_b=\"$instance_alias_b\"" | tee -a $helper_var echo "instance_alias_dir_b=\"$instance_alias_dir_b\"" | tee -a $helper_var . "$instance_alias_dir_a/instance.var" instance_id_a=$instance_Id instance_arn_a=$instance_Arn eval $(echo $instance_arn_a | (IFS=: read x x x r a x; echo "region_a=$r; aws_ac_a=$a")) region_a=$region_a aws_ac_a=$aws_ac_a echo "instance_id_a=\"$instance_id_a\"" | tee -a $helper_var echo "instance_arn_a=\"$instance_arn_a\"" | tee -a $helper_var echo "region_a=\"$region_a\"" | tee -a $helper_var echo "aws_ac_a=\"$aws_ac_a\"" | tee -a $helper_var echo "aws_profile_a=\"$aws_Profile\"" | tee -a $helper_var echo "lambda_prefix_a=\"$lambda_prefix_a\"" | tee -a $helper_var echo "lex_bot_prefix_a=\"$lex_bot_prefix_a\"" | tee -a $helper_var . "$instance_alias_dir_b/instance.var" instance_id_b=$instance_Id instance_arn_b=$instance_Arn eval $(echo $instance_arn_b | (IFS=: read x x x r a x; echo "region_b=$r; aws_ac_b=$a")) region_b=$region_b aws_ac_b=$aws_ac_b echo "instance_id_b=\"$instance_id_b\"" | tee -a $helper_var echo "instance_arn_b=\"$instance_arn_b\"" | tee -a $helper_var echo "region_b=\"$region_b\"" | tee -a $helper_var echo "aws_ac_b=\"$aws_ac_b\"" | tee -a $helper_var echo "aws_profile_b=\"$aws_Profile\"" | tee -a $helper_var echo "lambda_prefix_b=\"$lambda_prefix_b\"" | tee -a $helper_var echo "lex_bot_prefix_b=\"$lex_bot_prefix_b\"" | tee -a $helper_var # Use Instance B contact flow prefix echo "contact_flow_prefix=\"$instance_contact_flow_prefix\"" | tee -a $helper_var ############################################################ # # General SED commands # connect_arn_prefix_a="arn:aws:connect:$region_a:$aws_ac_a" connect_arn_prefix_b="arn:aws:connect:$region_b:$aws_ac_b" cat <<EOD >> $helper_sed # General SED commands s%$instance_id_a%$instance_id_b%g s%$connect_arn_prefix_a%$connect_arn_prefix_b%g EOD lambda_arn_prefix_a="arn:aws:lambda:$region_a:$aws_ac_a:function:$lambda_prefix_a" lambda_arn_prefix_b="arn:aws:lambda:$region_b:$aws_ac_b:function:$lambda_prefix_b" if [ "$lambda_arn_prefix_a" != "$lambda_arn_prefix_b" ]; then echo "s%$lambda_arn_prefix_a%$lambda_arn_prefix_b%g" >> $helper_sed fi echo ############################################################ # # Prompts # echo Checking Prompts ... jq -r ".Id + \" \" + .Name" "$instance_alias_dir_a/prompts.json" | dos2unix | while read prompt_id_a prompt_name; do prompt_name_encoded=$(path_encode "$prompt_name") # prompt_id_b=$(jq -r "select(.Name == \"${prompt_name//\"/\\\"}\") | .Id" "$instance_alias_dir_b/prompts.json") prompt_id_b=$(sed -e's/\\"/%22/g' "$instance_alias_dir_b/prompts.json" | jq -r "select(.Name == \"${prompt_name//\"/%22}\") | .Id" | dos2unix) if [ -z "$prompt_id_b" ]; then echo "prompt_$prompt_name" >> $helper_new else echo "prompt_$prompt_name" >> $helper_old cat <<EOD >> $helper_sed # Prompt: $prompt_name s%$prompt_id_a%$prompt_id_b%g EOD fi done test $? -eq 0 || error ############################################################ # # Hours of operations # echo Checking Hours of operations ... jq -r ".Id + \" \" + .Name" "$instance_alias_dir_a/hours.json" | dos2unix | while read hour_id_a hour_name; do hour_name_encoded=$(path_encode "$hour_name") # hour_id_b=$(jq -r "select(.Name == \"${hour_name//\"/\\\"}\") | .Id" "$instance_alias_dir_b/hours.json") hour_id_b=$(sed -e's/\\"/%22/g' "$instance_alias_dir_b/hours.json" | jq -r "select(.Name == \"${hour_name//\"/%22}\") | .Id" | dos2unix) if [ -z "$hour_id_b" ]; then add_file "$instance_alias_dir_a" "hour_$hour_name_encoded.json" $helper_new else add_file "$instance_alias_dir_b" "hour_$hour_name_encoded.json" $helper_old cat <<EOD >> $helper_sed # Hour of operation: $hour_name s%$hour_id_a%$hour_id_b%g EOD fi done test $? -eq 0 || error ############################################################ # # Queues # echo Checking Queues ... jq -r ".Id + \" \" + .Name" "$instance_alias_dir_a/queues.json" | dos2unix | while read queue_id_a queue_name; do queue_name_encoded=$(path_encode "$queue_name") # queue_id_b=$(jq -r "select(.Name == \"${queue_name//\"/\\\"}\") | .Id" "$instance_alias_dir_b/queues.json") queue_id_b=$(sed -e's/\\"/%22/g' "$instance_alias_dir_b/queues.json" | jq -r "select(.Name == \"${queue_name//\"/%22}\") | .Id" | dos2unix) if [ -z "$queue_id_b" ]; then add_file "$instance_alias_dir_a" "queue_$queue_name_encoded.json" $helper_new else add_file "$instance_alias_dir_b" "queue_$queue_name_encoded.json" $helper_old cat <<EOD >> $helper_sed # Queue: $queue_name s%$queue_id_a%$queue_id_b%g EOD fi done test $? -eq 0 || error ############################################################ # # Routing Profiles # echo Checking Routing Profiles ... jq -r ".Id + \" \" + .Name" "$instance_alias_dir_a/routings.json" | dos2unix | while read routing_id_a routing_name; do # if [ "$routing_name" == "$routing_profile_to_ignore" ]; then # continue # fi routing_name_encoded=$(path_encode "$routing_name") # routing_id_b=$(jq -r "select(.Name == \"${routing_name//\"/\\\"}\") | .Id" "$instance_alias_dir_b/routings.json") routing_id_b=$(sed -e's/\\"/%22/g' "$instance_alias_dir_b/routings.json" | jq -r "select(.Name == \"${routing_name//\"/%22}\") | .Id" | dos2unix) if [ -z "$routing_id_b" ]; then add_file "$instance_alias_dir_a" "routing_$routing_name_encoded.json" $helper_new add_file "$instance_alias_dir_a" "routingQs_$routing_name_encoded.json" $helper_new else add_file "$instance_alias_dir_b" "routing_$routing_name_encoded.json" $helper_old add_file "$instance_alias_dir_b" "routingQs_$routing_name_encoded.json" $helper_old cat <<EOD >> $helper_sed # Routing Profile: $routing_name s%$routing_id_a%$routing_id_b%g EOD fi done test $? -eq 0 || error ############################################################ # # Contact Flow Modules # echo Checking Contact Flow Modules ... jq -r ".Id + \" \" + .Name" "$instance_alias_dir_a/modules.json" | dos2unix | while read module_id_a module_name; do module_name_encoded=$(path_encode "$module_name") # module_id_b=$(jq -r "select(.Name == \"${module_name//\"/\\\"}\") | .Id" "$instance_alias_dir_b/modules.json") module_id_b=$(sed -e's/\\"/%22/g' "$instance_alias_dir_b/modules.json" | jq -r "select(.Name == \"${module_name//\"/%22}\") | .Id" | dos2unix) if [ -z "$module_id_b" ]; then add_file "$instance_alias_dir_a" "module_$module_name_encoded.json" $helper_new else add_file "$instance_alias_dir_b" "module_$module_name_encoded.json" $helper_old cat <<EOD >> $helper_sed # Contact Flow Module: $module_name s%$module_id_a%$module_id_b%g EOD fi done test $? -eq 0 || error ############################################################ # # Contact Flows # echo Checking Contact Flows ... jq -r ".Id + \" \" + .Name" "$instance_alias_dir_a/flows.json" | dos2unix | while read flow_id_a flow_name; do # flow_id_b=$(jq -r "select(.Name == \"${flow_name//\"/\\\"}\") | .Id" "$instance_alias_dir_b/flows.json") flow_id_b=$(sed -e's/\\"/%22/g' "$instance_alias_dir_b/flows.json" | jq -r "select(.Name == \"${flow_name//\"/%22}\") | .Id" | dos2unix) flow_name_encoded=$(path_encode "$flow_name") if [ -z "$flow_id_b" ]; then add_file "$instance_alias_dir_a" "flow_$flow_name_encoded.json" $helper_new else add_file "$instance_alias_dir_b" "flow_$flow_name_encoded.json" $helper_old cat <<EOD >> $helper_sed # Contact Flow: $flow_name s%$flow_id_a%$flow_id_b%g EOD fi done test $? -eq 0 || error cat > $flow_template <<EOD { "Version": "2019-10-30", "StartAction": "e093fb75-2263-4594-875e-2d8e9974595f", "Metadata": { "entryPointPosition": { "x": 20, "y": 20 }, "snapToGrid": false, "ActionMetadata": { "e093fb75-2263-4594-875e-2d8e9974595f": { "position": { "x": 120, "y": 20 } } } }, "Actions": [ { "Identifier": "e093fb75-2263-4594-875e-2d8e9974595f", "Type": "DisconnectParticipant", "Parameters": {}, "Transitions": {} } ] } EOD cat > $module_template <<EOD { "Version": "2019-10-30", "StartAction": "13f850a8-4882-4b78-ac83-508273b6a3d6", "Metadata": { "entryPointPosition": { "x": 20, "y": 20 }, "ActionMetadata": { "13f850a8-4882-4b78-ac83-508273b6a3d6": { "position": { "x": 120, "y": 20 } } } }, "Actions": [ { "Parameters": {}, "Identifier": "13f850a8-4882-4b78-ac83-508273b6a3d6", "Type": "EndFlowModuleExecution", "Transitions": {} } ], "Settings": { "InputParameters": [], "OutputParameters": [], "Transitions": [] } } EOD cat <<EOD These helper files are created: $helper_var: About the source and target Amazon Connect instances $helper_new: Components to add to "$instance_alias_dir_b" $helper_old: Components to update for "$instance_alias_dir_b" based on "$instance_alias_dir_a" $helper_sed: SED script used to update components $flow_template: Contact Flow template json All done EOD