# vim: set ft=sh ts=4 sw=4:

. `dirname $0`/autoscripts/functions

THIS_SCRIPT_NAME="`basename $0`"

KILLALL="/usr/bin/killall"

PRODUCT_VENDOR_INTERNAL="scutech"
PRODUCT_NAME_INTERNAL="dbackup3"
OPT_PREFIX="/opt/${PRODUCT_VENDOR_INTERNAL}/${PRODUCT_NAME_INTERNAL}"
ETC_PREFIX="/etc/opt/${PRODUCT_VENDOR_INTERNAL}"

VAR_PREFIX="/var/opt/${PRODUCT_VENDOR_INTERNAL}"
PRODUCT_VAR_PREFIX="${VAR_PREFIX}/${PRODUCT_NAME_INTERNAL}"
PRODUCT_ETC_PREFIX="${ETC_PREFIX}/${PRODUCT_NAME_INTERNAL}"

KEEPALIVED_PATH="$PRODUCT_ETC_PREFIX/keepalived"
CONFIG_PATH="$KEEPALIVED_PATH/keepalived.conf"
INIT_SCRIPT="/etc/init.d/@PRODUCT_NAME_INTERNAL@-keepalived"
BAK_FILE_NAME=$CONFIG_PATH".$(date "+%Y-%m-%d_%H:%M:%S")"

BEST_PRACTICE_PATH="`dirname $0`"
BEST_PRACTICE_PATH="`realpath $BEST_PRACTICE_PATH`"

# Some basic default values ​​of keepalived.conf.
DEFAULT_VRRP_GARP_INTERVAL=1
DEFAULT_VRRP_GNA_INTERVAL=1
DEFAULT_INSTANCE_NAME_PREFIX="VI"
DEFAULT_VRRP_SYNC_GROUP_NAME="VG1"
DEFAULT_AUTH_PASS="a9a2502"
DEFAULT_SCRIPT_USER="root"
DEFAULT_VIRTUAL_ROUTER_ID=238
DEFAULT_INTERVAL="10"
DEFAULT_WEIGHT="2"
DEFAULT_ADVERT_INT=1
DEFAULT_PRIORITY=100
DEFAULT_VRRP_SCRIPT_NAME="check_run"
DEFAULT_TRACK_SCRIPT_DELAY=10

CHECK_MYSQLD_CMD="$KILLALL -0 mysqld"
NOTIFY_MASTER_CMD="\"$OPT_PREFIX/bin/hactl notify master\" root root"
NOTIFY_BACKUP_CMD="\"$OPT_PREFIX/bin/hactl notify backup\" root root"
NOTIFY_FAULT_CMD="\"$OPT_PREFIX/bin/hactl notify fault\" root root"

# Controls whether to skip user input.
AUTO_ROUTER_ID=false
AUTO_SCRIPT_USER=true
AUTO_CLOSE_EMAIL=true;
AUTO_VRRP_INSTANCE_NAME=true
AUTO_PRIORITY=true
AUTO_NOPREEMPT=true
AUTO_AUTH_PASS=true

# Controls whether multiple entries are allowed.
MULTIPLE_UNICAST_PEERS=false
MULTIPLE_VIP=false

LIST_IP_CMD="ip -o -4 addr list"


show_ip_info () {
    local network_info="$1"
    echo "$network_info" | while read -r line; do
        iface=`echo $line | awk '{print $1}'`
        ipaddr=`echo $line | awk '{print $2}'`
        if [ -n "$iface" -a -n "$ipaddr" ]; then
            echo "$iface  IP: $ipaddr"
        fi
    done
}

email_notification () {
    if ! $AUTO_CLOSE_EMAIL; then
        echo "Whether to enable email notification[N]:"
        if confirm_yes false; then
            echo -n "Please enter the notification email address:"
            segment_begin "notification_email"
            while true; do
                read input_email
                [ -z "$input_email" ] && break
                append_conf_item "$input_email"
            done
            segment_end
            append_conf_line

            echo -n "Please enter the notification_email_from:"
            while true; do
                read input_email_from
                if [ -z "$input_email_from" ]; then
                    echo "notification_email_from cannot be empty, please continue to enter."
                else
                    append_conf_key_value "notification_email_from" "$input_email_from"
                    break
                fi
            done

            echo -n "Please enter the smtp_server, ip address [<PORT>]:"
            read input_smtp_server
            append_conf_key_value "smtp_server" "$input_smtp_server"
            append_conf_key_value "smtp_connect_timeout" "30"
            append_conf_line
        else
            append_conf_item "no_email_faults"
        fi
    else
        append_conf_item "no_email_faults"
    fi
}

global_defs () {
    local router_id="$1"

    local script_user=$DEFAULT_SCRIPT_USER
    if ! $AUTO_SCRIPT_USER; then
        echo -n "Please enter script_user [$DEFAULT_SCRIPT_USER]:"
        read input_script_user
        [ -z "$input_script_user" ] || script_user="$input_script_user"
    fi

    segment_begin "global_defs"
    append_conf_key_value 'router_id' "$router_id"
    append_conf_key_value "script_user" "$script_user"
    append_conf_item "enable_script_security"
    append_conf_item "vrrp_skip_check_adv_addr"
    append_conf_key_value "vrrp_garp_interval" "$DEFAULT_VRRP_GARP_INTERVAL"
    append_conf_key_value "vrrp_gna_interval" "$DEFAULT_VRRP_GNA_INTERVAL"
    email_notification
    segment_end
}

vrrp_script () {
    local script="$1"
    segment_begin "vrrp_script" "$DEFAULT_VRRP_SCRIPT_NAME"
    append_conf_key_value "script" "\"$script\""
    append_conf_key_value "interval" "$DEFAULT_INTERVAL"
    segment_end
}

authentication () {
    local instance_name="$1"
    local auth_pass="$DEFAULT_AUTH_PASS"
    if ! $AUTO_AUTH_PASS; then
        echo -n "Please enter vrrp_instance $instance_name auth_pass:[$DEFAULT_AUTH_PASS]:"
        read input_pass
        [ -z "$input_pass" ] || auth_pass="$input_pass"
    fi

    segment_begin "authentication"
    append_conf_key_value "auth_type" "PASS"
    append_conf_key_value "auth_pass" "$auth_pass"
    segment_end
}

unicast_peer () {
    echo -n "Please enter the ip of unicast_peer:"
    segment_begin "unicast_peer"
    local have_peer_ip=false
    while true; do
        read input_peer_ip
        if [ -z "$input_peer_ip" ]; then
            $have_peer_ip && break
            echo "At least one peer IP must be configured!"
        else
            append_conf_item "$input_peer_ip"
            have_peer_ip=true
            ! $MULTIPLE_UNICAST_PEERS && break
        fi
    done

    segment_end
}

virtual_ipaddress () {
    echo -n "Please enter the ip of VIP:"
    segment_begin "virtual_ipaddress"
    local have_vip=false
    while true; do
        read input_vip
        if [ -z "$input_vip" ]; then
            $have_vip && break
            echo "virtual_ipaddress is required."
        else
            append_conf_item "$input_vip"
            have_vip=true
            ! $MULTIPLE_VIP && break
        fi
    done

    segment_end
}

instance_interface () {
    local instance_name="$1"
    local network_info="$2"
    echo "Currently valid network info are:"
    show_ip_info "$network_info"
    echo -n "Please enter vrrp_instance $instance_name interface:"
    while true; do
        read input_interface
        if [ -n "$input_interface" ]; then
            append_conf_key_value "interface" "$input_interface"
            break
        else
            echo "The interface property of vrrp_instance $instance_name must be provided."
        fi
    done
}

instance_state () {
    local instance_name="$1"
    local priority=$DEFAULT_PRIORITY
    local state_name="MASTER"
    if ! $AUTO_NOPREEMPT; then
        echo -n "Whether to enable nopreempt? [Y]:"
        if confirm_yes true; then
            append_conf_key_value "state" "BACKUP"
            state_name="BACKUP"
            append_conf_item "nopreempt"
        else
            echo -n "Please enter vrrp_instance $instance_name state:[MASTER(M)|BACKUP(B)]:"
            while true; do
                read input_state
                input_state=`echo $input_state | tr "[a-z]" "[A-Z]"`
                if [ -z "$input_state" -o "$input_state" = "M" -o "$input_state" = "MASTER" ]; then
                    echo "The state of vrrp_instance $instance_name is set to MASTER."
                    append_conf_key_value "state" "MASTER"
                    break
                elif [ "$input_state" = "B" -o "$input_state" = "BACKUP" ]; then
                    append_conf_key_value "state" "BACKUP"
                    state_name="BACKUP"
                    break
                fi

                echo "Valid state are either M or B."
            done
        fi
    else
        append_conf_key_value "state" "BACKUP"
        append_conf_item "nopreempt"
    fi

    [ "$state_name" != "MASTER" ] && priority=80

    if ! $AUTO_PRIORITY; then
        echo "Please enter vrrp_instance $instance_name priority:[$priority]"
        read input_priority
        [ -z "$input_priority" ] || priority="$input_priority"
    fi

    append_conf_key_value "priority" "$priority"
}

track_script () {
    segment_begin "track_script"
    append_conf_item "$DEFAULT_VRRP_SCRIPT_NAME"
    segment_end
    append_conf_line
}

vrrp_sync_group () {
    local all_instance_names="$1"
    if expr `echo "$all_instance_names" | wc -w` \> 1 >/dev/null; then
        segment_begin "vrrp_sync_group" "$DEFAULT_VRRP_SYNC_GROUP_NAME"
        segment_begin "group"
        for i in $all_instance_names; do
            append_conf_item "$i"
        done
        segment_end

        append_conf_key_value "notify_master" "\"$BEST_PRACTICE_PATH/notify.sh master $router_id\""
        append_conf_key_value "notify_backup" "\"$BEST_PRACTICE_PATH/notify.sh backup $router_id\""
        append_conf_key_value "notify_stop" "\"$BEST_PRACTICE_PATH/notify.sh stop $router_id\""
        append_conf_key_value "notify_fault" "\"$BEST_PRACTICE_PATH/notify.sh fault $router_id\""
        segment_end
    fi
}

unicast_src_ip () {
    local instance_name="$1"
    echo -n "Please enter vrrp_instance $instance_name unicast_src_ip:"
    while true; do
        read input_src_ip
        if [ -n "$input_src_ip" ]; then
            append_conf_key_value "unicast_src_ip" "$input_src_ip"
            break
        else
            echo "unicast_src_ip is required."
        fi
    done
}

create_config () {
    local network_info="$1"
    local router_id=`uuidgen | head -c 8`
    if ! $AUTO_ROUTER_ID; then
        while true; do
            echo -n "Please enter router_id:"
            read input_router_id
            [ -n "$input_router_id" ] && router_id="$input_router_id" && break
        done
    fi

    global_defs "$router_id"
    append_conf_line
    vrrp_script "$CHECK_MYSQLD_CMD"
    append_conf_line

    local all_instance_names=""
    local instance_index=1
    while true; do
        if [ -z "$all_instance_names" ]; then
            echo "Start configuration of the first vrrp_instance."
        else
            echo -n "Do you want to continue add vrrp_instance? [N]:"
            if confirm_yes false; then
                instance_index=$((instance_index + 1))
            else
                break
            fi
        fi

        local instance_name=$DEFAULT_INSTANCE_NAME_PREFIX"_"$instance_index
        if ! $AUTO_VRRP_INSTANCE_NAME; then
            echo -n "Please enter vrrp_instance name:[$instance_name]:"
            read input_inst_name
            [ -z "$input_inst_name" ] || instance_name="$input_inst_name"
        fi

        all_instance_names="$all_instance_names $instance_name"

        segment_begin "vrrp_instance" "$instance_name"
        instance_state "$instance_name"
        instance_interface "$instance_name" "$network_info"

        append_conf_key_value "virtual_router_id" "$DEFAULT_VIRTUAL_ROUTER_ID"
        append_conf_key_value "advert_int" "$DEFAULT_ADVERT_INT"
        append_conf_line

        authentication "$instance_name"
        append_conf_line

        unicast_src_ip "$instance_name"
        unicast_peer
        append_conf_line

        virtual_ipaddress
        append_conf_line

        track_script

        append_conf_key_value "notify_master" "$NOTIFY_MASTER_CMD"
        append_conf_key_value "notify_backup" "$NOTIFY_BACKUP_CMD"
        append_conf_key_value "notify_fault" "$NOTIFY_FAULT_CMD"
        segment_end
        append_conf_line
    done

    vrrp_sync_group "$all_instance_names"
}

do_config_local_file () {
    echo -n "Whether to start local node configuration? [Y]: "
    if confirm_yes true; then
        local network_info="`list_ip_info`"
        create_config "$network_info"
        bak_file "$CONFIG_PATH" "$BAK_FILE_NAME"
        printf "$CONFIG_CONTENT" > $CONFIG_PATH
        if [ $? -ne 0 ]; then
            echo "Please check whether you have permission to write file $CONFIG_PATH"
            exit 1
        fi
        echo "Successfully saved configuration to $CONFIG_PATH."
        clear_conf

        echo -n "Whether to automatically reload keepalived for you? [N]: "
        if confirm_yes false; then
            if [ -x $INIT_SCRIPT ]; then
                $INIT_SCRIPT reload
            else
                echo "The script $INIT_SCRIPT does not exist or has no execution permission."
            fi
        fi
    fi
}

do_config_remote_file () {
    echo -n "Whether to start remote node configuration? [Y]: "
    if confirm_yes true; then
        echo -n "Please enter the IP address and account information for remote ssh.[user@host]:"

        ssh_info=""
        while true; do
            read input_ssh
            if [ -n "$input_ssh" ]; then
                ssh_info="$input_ssh"
                break
            fi
            echo "Remote user and IP address must be provided."
        done

        local ssh_output
        ssh_output=$(execute_ssh_cmd "$ssh_info" "$LIST_IP_CMD")
        if [ $? -ne 0 ]; then
            echo "Fialed to execute $LIST_IP_CMD at remote host $ssh_info."
            exist 1
        fi

        local network_info
        network_info=`echo "$ssh_output" | awk '$2 != "lo" {print $2, $4}'`
        create_config "$network_info"

        local auto_reload=false
        echo -n "Whether to automatically reload keepalived for you? [N]: "
        if confirm_yes false; then
            auto_reload=true
        fi

        ssh -T $ssh_info << EOF
        if ! [ -d $KEEPALIVED_PATH ]; then
            mkdir -p "$KEEPALIVED_PATH"
            if [ $? -ne 0 ]; then
                echo "Please check whether you have permission to create directory $KEEPALIVED_PATH"
                exit 1
            fi
        fi

        if [ -f $CONFIG_PATH ]; then
            cp $CONFIG_PATH $BAK_FILE_NAME
            if [ $? -ne 0 ]; then
                echo "Failed to back up file $CONFIG_PATH,"\
                    "Please check whether you have the relevant permissions."
                exit 1
            else
                echo "Successfully backed up the configuration to $BAK_FILE_NAME ($ssh_info)."
            fi
        fi

        printf '$CONFIG_CONTENT' > $CONFIG_PATH
        if [ $? -ne 0 ]; then
            echo "Please check whether you have permission to write file $CONFIG_PATH"
            exit 1
        fi
        echo "Successfully saved configuration to $CONFIG_PATH ($ssh_info)."

        if $auto_reload; then
            if [ -x $INIT_SCRIPT ]; then
                $INIT_SCRIPT reload
            else
                echo "The script $INIT_SCRIPT does not exist or has no"\
                     "execution permission, reload failed."
            fi
        fi
EOF
    fi
}

do_config_file () {
    mkdir_p "$KEEPALIVED_PATH"
    do_config_local_file
    do_config_remote_file
}

start_best_practice_config () {
    mkdir_p "$KEEPALIVED_PATH"
    local router_id=`uuidgen | head -c 8`
    if ! $AUTO_ROUTER_ID; then
        while true; do
            echo -n "Please enter router_id:"
            read input_router_id
            [ -n "$input_router_id" ] && router_id="$input_router_id" && break
        done
    fi

    local vrrp_script_path="$BEST_PRACTICE_PATH/mysql_check.sh $router_id"

    global_defs "$router_id"
    append_conf_line
    vrrp_script "$vrrp_script_path"
    append_conf_line
    local network_info="`list_ip_info`"
    local all_instance_names=""

    local instance_amount=0
    while true; do
        read -p "How many network interfaces are there? " number
        if is_valid_number "$number"; then
            instance_amount=$number
            break
        else
            echo "Invalid input value!"
        fi
    done

    for i in `seq 1 $instance_amount`; do
        echo "Start configuration of vrrp_instance $i"

        local instance_name=$DEFAULT_INSTANCE_NAME_PREFIX"_"$i
        if ! $AUTO_VRRP_INSTANCE_NAME; then
            echo -n "Please enter vrrp_instance name:[$instance_name]:"
            read input_inst_name
            [ -z "$input_inst_name" ] || instance_name="$input_inst_name"
        fi

        all_instance_names="$all_instance_names $instance_name"

        segment_begin "vrrp_instance" "$instance_name"
        instance_state "$instance_name"
        instance_interface "$instance_name" "$network_info"

        append_conf_key_value "virtual_router_id" "$DEFAULT_VIRTUAL_ROUTER_ID"
        append_conf_key_value "advert_int" "$DEFAULT_ADVERT_INT"
        append_conf_line

        authentication "$instance_name"
        append_conf_line

        unicast_src_ip "$instance_name"
        unicast_peer
        append_conf_line

        virtual_ipaddress
        append_conf_line

        track_script

        if [ $instance_amount -eq 1 ]; then
            append_conf_key_value "notify_master" "\"$BEST_PRACTICE_PATH/notify.sh master $router_id\""
            append_conf_key_value "notify_backup" "\"$BEST_PRACTICE_PATH/notify.sh backup $router_id\""
            append_conf_key_value "notify_stop" "\"$BEST_PRACTICE_PATH/notify.sh stop $router_id\""
            append_conf_key_value "notify_fault" "\"$BEST_PRACTICE_PATH/notify.sh fault $router_id\""
        fi

        segment_end
        append_conf_line
    done

    vrrp_sync_group "$all_instance_names"

    bak_file "$CONFIG_PATH" "$BAK_FILE_NAME"
    printf "$CONFIG_CONTENT" > $CONFIG_PATH
    if [ $? -ne 0 ]; then
        echo "Please check whether you have permission to write file $CONFIG_PATH"
        exit 1
    fi
    echo "Successfully saved configuration to $CONFIG_PATH."
    clear_conf
}

help () {
    cat <<EOF
Usage: ./$THIS_SCRIPT_NAME [OPTIONS]

  -h|--help                   Show help info.
  -n|--normal                 Used for dbackup3.
  -b|--best_practice          Best Practices for dbackup3.
EOF
    exit 1
}

if [ $# -eq 0 ]; then
    help
fi

while true; do
    case "$1" in
    -h|--help)
        help
        break
        ;;
    -n|--normal)
        do_config_file
        break
        ;;
    -b|--best_practice)
        start_best_practice_config
        break
        ;;
    --)
        break
        ;;
    *)
        echo "Internal error!"
        exit 1
        ;;
    esac
done
