#!/bin/bash

VERSION="beta_v0.1.1"
# Fix the issue of adding shards

# Usage example
# ultipa.sh image upload --config example.sh
# ultipa.sh image info --config example.sh
# ultipa.sh cluster create --config example.sh
# ultipa.sh cluster start --server name --config example.sh
# ultipa.sh cluster stop --server name --config example.sh
# ultipa.sh cluster info --config example.sh
# ultipa.sh cluster stat --config example.sh
# ultipa.sh cluster reconfig --config example.sh
# ultipa.sh cluster destroy --config example.sh
# ultipa.sh cluster update --config example.sh
# ultipa.sh cluster genconf
# ultipa.sh lic upload --config example.sh

function gen_example_config(){
cat << EOF > example.sh
CLUSTER_NAME="v5-t1"

LICENSE_FILE_PATH="./ultipa.lic"
ALGO_LICENSE_FILE_PATH="./ultipa_algo.lic"

# container config
DOCKER_MOUNT_PATH="/data/docker_mounts"

# SSH config
SSH_USER="root"
SSH_PRIVATE_KEY="/home/ultipa/.ssh/id_rsa"

META_IMAGE="docker-registry.ultipa-inc.org:5000/ultipa/meta-server:beta.5.0.67-b5.0.0-gql"
SHARD_IMAGE="docker-registry.ultipa-inc.org:5000/ultipa/distribute-graphdb-htap:beta.5.0.67-b5.0.0-gql"
NAME_IMAGE="docker-registry.ultipa-inc.org:5000/ultipa/distribute-graphdb-htap:beta.5.0.67-b5.0.0-gql"
HDC_IMAGE="docker-registry.ultipa-inc.org:5000/ultipa/hdc-server:beta.5.0.67-b5.0.0-gql"

# docker image tar file, name server and shard server use same docker image
META_IMAGE_TAR=""
SHARD_NAME_IMAGE_TAR=""
HDC_IMAGE_TAR=""

# Each name server node occupies 2 ports, with private_port = public_port + 1. 
# When using this script to deploy multiple clusters, 
# be sure to calculate the port ranges carefully and set the starting port accordingly.
# NAME_SERVER_PUBLIC_START_PORT="60060"
NAME_SERVER_PUBLIC_START_PORT="61060"
# Use spaces to separate the host IPs.
NAME_SERVER_LIST="192.168.58.151 192.168.58.152 192.168.58.153"

# META_SERVER_START_PORT="50060"
META_SERVER_START_PORT="51060"
# Use spaces to separate the host IPs.
META_SERVER_LIST="192.168.58.171 192.168.58.172 192.168.58.173"

# HDC_SERVER_START_PORT="55555"
HDC_SERVER_START_PORT="56555"
# Use spaces to separate the host IPs.
HDC_SERVER_LIST="192.168.58.181"

# Each shard server node occupies 2 ports, with stream_port = shard_port + 1. 
# When using this script to deploy multiple clusters, 
# make sure to calculate the port ranges carefully and set the starting port accordingly.
# SHARD_SERVER_START_PORT="40061"
SHARD_SERVER_START_PORT="41061"
# Use spaces to separate replicas and commas to separate shards.
SHARD_SERVER_LIST="192.168.58.161 192.168.58.164, 192.168.58.162, 192.168.58.163"

# Modify the configuration file
# Space-separated key-value pairs
# CONFIG='k1=v1 k2=v2 k3=v3 ...'
# You can also write them on separate lines, but they will be interpreted as a single line
# CONFIG='
# k1=v1
# k2=v2
# k3=v3
# ...
# '
# META
META_CONFIG='
'
# NAME
NAME_CONFIG='
'

# SHARD
SHARD_CONFIG='
'

# HDC
HDC_CONFIG='
'
EOF
}


#        -------*** meta ***-------
function calc_meta_server_htap_conf(){
    if [ -z "$META_SERVER_START_PORT" ]
    then
        meta_port=50060
    else
        meta_port=$META_SERVER_START_PORT
    fi

    meta_conf=""
    for i in $META_SERVER_LIST
    do
        m=$i:$meta_port
        if [ "$meta_conf" != "" ]
        then
            meta_conf=$meta_conf,$m
        else
            meta_conf=$m
        fi
        meta_port=$(($meta_port+1))
    done
}
function destroy_meta_server(){
    calc_meta_server_htap_conf
    for i in `echo $meta_conf | tr -s ',' ' '`
    do
        one_meta_ip=`echo $i | awk -F: '{print $1}'`
        one_meta_port=`echo $i | awk -F: '{print $2}'`
        cmd=`echo "docker rm -f meta-${CLUSTER_NAME}-${one_meta_ip}-${one_meta_port} && \
                  rm -rf ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/conf && \
                  rm -rf ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/data && \
                  rm -rf ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/log && \
                  rm -rf ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/cert && \
                  rmdir ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}" | base64 -w0`
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_meta_ip}  "echo $cmd | base64 -d | bash"
        
        unset cmd
    done

}
function init_config_meta_server(){
    calc_meta_server_htap_conf
    for i in `echo $meta_conf | tr -s ',' ' '`
    do
        one_meta_ip=`echo $i | awk -F: '{print $1}'`
        one_meta_port=`echo $i | awk -F: '{print $2}'`

        cmd=`echo "docker start meta-${CLUSTER_NAME}-$one_meta_ip-$one_meta_port && \
        docker exec meta-${CLUSTER_NAME}-$one_meta_ip-$one_meta_port start; \
        sleep 5; \
        mv ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/conf/meta-server-example.config ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/conf/meta-server.config" | base64 -w0`

        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_meta_ip}  "echo $cmd | base64 -d | bash"

        unset one_meta_ip
        unset one_meta_port
    done
}

function reconfig_meta_server(){
    calc_meta_server_htap_conf

    for i in `echo $meta_conf | tr -s ',' ' '`
    do
        unset one_meta_ip one_meta_port
        one_meta_ip=`echo $i | awk -F: '{print $1}'`
        one_meta_port=`echo $i | awk -F: '{print $2}'`

        echo > /tmp/meta_config.tmp
        # HTAP cluster modification, general/common settings
        echo "sed -i \"s/^conf=.*/conf=${meta_conf}/\" ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/conf/meta-server.config" >> /tmp/meta_config.tmp
        # modify addr
        echo "sed -i \"s/^addr=.*/addr=${i}/\" ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/conf/meta-server.config" >> /tmp/meta_config.tmp
        # Common settings in config.sh that need to be modified
        for c in ${META_CONFIG}
        do
            if [[ ${c} =~ ^\s*#.* ]]; then
                continue
            fi
            key=`echo $c | awk -F'=' '{print $1}'`
            value=`echo $c | awk -F'=' '{print $2}'`
            if [ "$key" != "" ] && [ "$value" != "" ]
            then
                echo "sed -i \"s/^${key}=.*/${key}=${value}/\" ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/conf/meta-server.config" >> /tmp/meta_config.tmp
            fi
        done
        unset c key value

        cmd=`cat /tmp/meta_config.tmp | base64 -w0`

        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_meta_ip}  "echo $cmd | base64 -d | bash"
        unset cmd
    done
    rm -f /tmp/meta_config.tmp
}

function stop_meta_server(){
    calc_meta_server_htap_conf
    for i in `echo $meta_conf | tr -s ',' ' '`
    do
        one_meta_ip=`echo $i | awk -F: '{print $1}'`
        one_meta_port=`echo $i | awk -F: '{print $2}'`
        cmd=`echo "docker exec meta-${CLUSTER_NAME}-${one_meta_ip}-${one_meta_port} /opt/meta-server/meta-server stop && docker stop meta-${CLUSTER_NAME}-${one_meta_ip}-${one_meta_port}" | base64 -w0`
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_meta_ip}  "echo $cmd | base64 -d | bash"
        
        unset cmd
    done
}

function start_meta_server(){
    calc_meta_server_htap_conf
    for i in `echo $meta_conf | tr -s ',' ' '`
    do
        one_meta_ip=`echo $i | awk -F: '{print $1}'`
        one_meta_port=`echo $i | awk -F: '{print $2}'`
        cmd=`echo "docker start meta-${CLUSTER_NAME}-${one_meta_ip}-${one_meta_port} && sleep 5;docker exec meta-${CLUSTER_NAME}-${one_meta_ip}-${one_meta_port} start" | base64 -w0`
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_meta_ip}  "echo $cmd | base64 -d | bash"
        
        unset cmd
    done
}

function status_meta_server(){
    echo "------- meta status ------- :"

    calc_meta_server_htap_conf
    for i in `echo $meta_conf | tr -s ',' ' '`
    do
        one_meta_ip=`echo $i | awk -F: '{print $1}'`
        one_meta_port=`echo $i | awk -F: '{print $2}'`

        echo -n "$one_meta_ip $one_meta_port: "

        cmd=`echo "docker exec meta-${CLUSTER_NAME}-${one_meta_ip}-${one_meta_port} ps -ef| grep meta-server | grep -v grep" | base64 -w0`
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_meta_ip}  "echo $cmd | base64 -d | bash" || echo
        
        unset cmd
    done
}

function create_meta_server(){
    calc_meta_server_htap_conf
    for i in `echo $meta_conf | tr -s ',' ' '`
    do
        one_meta_ip=`echo $i | awk -F: '{print $1}'`
        one_meta_port=`echo $i | awk -F: '{print $2}'`

        cmd=`echo "docker run -itd \
        --net=host \
        --ulimit nofile=90000:90000 --privileged --cap-add=SYS_PTRACE --security-opt seccomp=unconfined \
        -v ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/conf:/opt/meta-server/config \
        -v ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/data:/opt/meta-server/data \
        -v ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/log:/opt/meta-server/log \
        -v ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/cert:/opt/meta-server/resource/cert \
        -e TZ=UTC \
        --name meta-${CLUSTER_NAME}-${one_meta_ip}-${one_meta_port} ${META_IMAGE}" | base64 -w0`

        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_meta_ip}  "echo $cmd | base64 -d | bash"

        unset cmd
        unset one_meta_ip
        unset one_meta_port
    done

    # The initialization configs setup runs only once
    init_config_meta_server
    reconfig_meta_server
    start_meta_server
}

function update_meta_server(){
    calc_meta_server_htap_conf
    for i in `echo $meta_conf | tr -s ',' ' '`
    do
        one_meta_ip=`echo $i | awk -F: '{print $1}'`
        one_meta_port=`echo $i | awk -F: '{print $2}'`

        cmd=`echo "docker rm -f meta-${CLUSTER_NAME}-${one_meta_ip}-${one_meta_port} && \
        docker run -itd \
        --net=host \
        --ulimit nofile=90000:90000 --privileged --cap-add=SYS_PTRACE --security-opt seccomp=unconfined \
        -v ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/conf:/opt/meta-server/config \
        -v ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/data:/opt/meta-server/data \
        -v ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/log:/opt/meta-server/log \
        -v ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/cert:/opt/meta-server/resource/cert \
        -e TZ=UTC \
        --name meta-${CLUSTER_NAME}-${one_meta_ip}-${one_meta_port} ${META_IMAGE}" | base64 -w0`

        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_meta_ip}  "echo $cmd | base64 -d | bash"

        unset cmd
        unset one_meta_ip
        unset one_meta_port
    done
}



#        -------*** name ***-------

function calc_name_server_private_ip_port_list(){
    if [ -z "$NAME_SERVER_PUBLIC_START_PORT" ]
    then
        name_public_port=60060
    else
        name_public_port=$NAME_SERVER_PUBLIC_START_PORT
    fi

    name_public_conf=""

    name_private_port=$(($name_public_port+1))
    name_private_conf=""
    for i in $NAME_SERVER_LIST
    do
        # calc public conf
        m="0.0.0.0":$name_public_port
        if [ "$name_public_conf" != "" ]
        then
            name_public_conf=$name_public_conf,$m
        else
            name_public_conf=$m
        fi
        # calc private conf
        name_private_port=$(($name_public_port+1))
        m=$i:$name_private_port
        if [ "$name_private_conf" != "" ]
        then
            name_private_conf=$name_private_conf,$m
        else
            name_private_conf=$m
        fi
        name_public_port=$(($name_public_port+2))
    done
    # echo $name_public_conf
    # echo $name_private_conf
}

function destroy_name_server(){
    calc_name_server_private_ip_port_list
    for i in `echo $name_private_conf | tr -s ',' ' '`
    do
        one_name_ip=`echo $i | awk -F: '{print $1}'`
        one_name_port=`echo $i | awk -F: '{print $2}'`
        cmd=`echo "docker rm -f name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port} && \
                    rm -rf ${DOCKER_MOUNT_PATH}/name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}/conf && \
                    rm -rf ${DOCKER_MOUNT_PATH}/name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}/log && \
                    rmdir ${DOCKER_MOUNT_PATH}/name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}" | base64 -w0`
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_name_ip}  "echo $cmd | base64 -d | bash"
        
        unset cmd
    done
}

function init_config_name_server(){
    calc_name_server_private_ip_port_list
    for i in `echo $name_private_conf | tr -s ',' ' '`
    do
        one_name_ip=`echo $i | awk -F: '{print $1}'`
        one_name_port=`echo $i | awk -F: '{print $2}'`

        cmd=`echo "docker start name-${CLUSTER_NAME}-$one_name_ip-$one_name_port && \
        docker exec name-${CLUSTER_NAME}-$one_name_ip-$one_name_port name_start; \
        sleep 5; \
        mv ${DOCKER_MOUNT_PATH}/name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}/conf/name-server-example.config ${DOCKER_MOUNT_PATH}/name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}/conf/name-server.config" | base64 -w0`

        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_name_ip}  "echo $cmd | base64 -d | bash"

        unset one_name_ip
        unset one_name_port
    done
}

function reconfig_name_server(){
    calc_name_server_private_ip_port_list
    calc_meta_server_htap_conf

    pub_list=1

    for i in `echo $name_private_conf | tr -s ',' ' '`
    do
        unset one_name_ip
        one_name_ip=`echo $i | awk -F: '{print $1}'`
        one_name_port=`echo $i | awk -F: '{print $2}'`
        one_name_public_port=`echo $name_public_conf | awk -F, -v n=$pub_list '{print $n}' | awk -F: '{print $2}'`
        echo > /tmp/name_config.tmp
        # Common settings for modifying the cluster public address
        echo "sed -i \"s/^addr=.*/addr="0.0.0.0:${one_name_public_port}"/\" ${DOCKER_MOUNT_PATH}/name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}/conf/name-server.config" >> /tmp/name_config.tmp
        # New configuration item: Use the public port for the name server ID
        echo "sed -i \"s/^id=.*/id="${pub_list}"/\" ${DOCKER_MOUNT_PATH}/name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}/conf/name-server.config" >> /tmp/name_config.tmp
        # modify addr
        echo "sed -i \"s/^private_addr=.*/private_addr=${i}/\" ${DOCKER_MOUNT_PATH}/name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}/conf/name-server.config" >> /tmp/name_config.tmp

        echo "sed -i \"s/^meta_server_addrs=.*/meta_server_addrs=${meta_conf}/\" ${DOCKER_MOUNT_PATH}/name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}/conf/name-server.config" >> /tmp/name_config.tmp
        # Items to be modified in config.sh, common settings
        for c in ${NAME_CONFIG}
        do
            if [[ ${c} =~ ^\s*# ]]; then
                continue
            fi

            if [ "${c:0:1}" = "#" ]
            then
                continue
            fi
            key=`echo $c | awk -F'=' '{print $1}'`
            value=`echo $c | awk -F'=' '{print $2}'`
            if [ "$key" != "" ] && [ "$value" != "" ]
            then
                echo "sed -i \"s/^${key}=.*/${key}=${value}/\" ${DOCKER_MOUNT_PATH}/name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}/conf/name-server.config" >> /tmp/name_config.tmp
            fi
        done
        unset c key value

        cmd=`cat /tmp/name_config.tmp | base64 -w0`

        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_name_ip}  "echo $cmd | base64 -d | bash"
        # cat /tmp/name_config.tmp
        unset cmd
        pub_list=$((pub_list+1))
    done
    # rm -f /tmp/name_config.tmp
}

function stop_name_server(){
    calc_name_server_private_ip_port_list
    for i in `echo $name_private_conf | tr -s ',' ' '`
    do
        one_name_ip=`echo $i | awk -F: '{print $1}'`
        one_name_port=`echo $i | awk -F: '{print $2}'`
        cmd=`echo "docker exec name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port} /opt/distribute-graphdb/name-server stop && docker stop name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}" | base64 -w0`
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_name_ip}  "echo $cmd | base64 -d | bash"
        
        unset cmd
    done
}

function start_name_server(){
    calc_name_server_private_ip_port_list
    for i in `echo $name_private_conf | tr -s ',' ' '`
    do
        one_name_ip=`echo $i | awk -F: '{print $1}'`
        one_name_port=`echo $i | awk -F: '{print $2}'`
        cmd=`echo "docker start name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port} && sleep 5;docker exec name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port} name_start" | base64 -w0`
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_name_ip}  "echo $cmd | base64 -d | bash"
        
        unset cmd
    done
}

function status_name_server(){
    echo "------- name status ------- :"

    calc_name_server_private_ip_port_list
    for i in `echo $name_private_conf | tr -s ',' ' '`
    do
        one_name_ip=`echo $i | awk -F: '{print $1}'`
        one_name_port=`echo $i | awk -F: '{print $2}'`
        echo -n "$one_name_ip $one_name_port :"
        cmd=`echo "docker exec name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port} ps -ef| grep name-server | grep -v grep" | base64 -w0`
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_name_ip}  "echo $cmd | base64 -d | bash" || echo
        
        unset cmd
    done
}

function create_name_server(){
    calc_name_server_private_ip_port_list
    for i in `echo $name_private_conf | tr -s ',' ' '`
    do
        one_name_ip=`echo $i | awk -F: '{print $1}'`
        one_name_port=`echo $i | awk -F: '{print $2}'`

        cmd=`echo "docker run -itd \
        --net=host \
        --ulimit nofile=90000:90000 --privileged --cap-add=SYS_PTRACE --security-opt seccomp=unconfined \
        -v ${DOCKER_MOUNT_PATH}/name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}/conf:/opt/distribute-graphdb/config \
        -v ${DOCKER_MOUNT_PATH}/name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}/log:/opt/distribute-graphdb/log \
        -e TZ=UTC \
        --name name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port} ${NAME_IMAGE}" | base64 -w0`

        # echo "------------------ *********************** debug *********************** ------------------"
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_name_ip}  "echo $cmd | base64 -d | bash"

        unset cmd
        unset one_name_ip
        unset one_name_port
    done

    # The initialization setup runs only once
    init_config_name_server
    reconfig_name_server
    start_name_server
}

function update_name_server(){
    calc_name_server_private_ip_port_list
    for i in `echo $name_private_conf | tr -s ',' ' '`
    do
        one_name_ip=`echo $i | awk -F: '{print $1}'`
        one_name_port=`echo $i | awk -F: '{print $2}'`

        cmd=`echo "docker rm -f name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port} && \
        docker run -itd \
        --net=host \
        --ulimit nofile=90000:90000 --privileged --cap-add=SYS_PTRACE --security-opt seccomp=unconfined \
        -v ${DOCKER_MOUNT_PATH}/name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}/conf:/opt/distribute-graphdb/config \
        -v ${DOCKER_MOUNT_PATH}/name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}/log:/opt/distribute-graphdb/log \
        -e TZ=UTC \
        --name name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port} ${NAME_IMAGE}" | base64 -w0`

        # echo "------------------ *********************** debug *********************** ------------------"
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_name_ip}  "echo $cmd | base64 -d | bash"

        unset cmd
        unset one_name_ip
        unset one_name_port
    done
}

#        -------*** shard ***-------
function calc_shard_config () {
    if [ -z "$SHARD_SERVER_START_PORT" ]
    then
        port_base=40061
    else
        port_base=$SHARD_SERVER_START_PORT
    fi

    group_number=1

    clean_list=$(echo $SHARD_SERVER_LIST | tr -s ' ')

    IFS=',' read -r -a group_array <<< "$clean_list"

    result=""

    for group in "${group_array[@]}"; do
        # Remove extra spaces within each group and split into individual IPs
        group=$(echo "$group" | tr -s ' ')
        IFS=' ' read -r -a ip_array <<< "$group"

        # Iterate through each IP in the group and add the port and number
        new_group=""
        for ip in "${ip_array[@]}"; do
            new_group="$new_group$ip:$port_base:$group_number "
            port_base=$((port_base + 2))  # Port number increments automatically
        done

        # Remove the last space within the group and add commas for separation
        new_group=$(echo "$new_group" | sed 's/ $//')
        result="$result$new_group, "

        # Group number auto-increments
        group_number=$((group_number + 1))
    done

    # Remove the trailing comma and space from the result string
    shard_conf=$(echo "$result" | sed 's/, $//')
    # echo $shard_conf
}
function destroy_shard_server(){
    calc_shard_config

    IFS=','
    for i in $shard_conf
    do
        unset IFS
        for j in $i
        do
            IFS=':'
            read -r one_shard_ip one_shard_port one_shard_id <<< "$j"
            cmd=`echo "docker rm -f shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port} && \
                        rm -rf ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/conf && \
                        rm -rf ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/shard_data && \
                        rm -rf ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/log && \
                        rmdir ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}" | base64 -w0`

            ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_shard_ip}  "echo $cmd | base64 -d | bash"
            
            unset IFS
        done

        IFS=','
    done
    unset IFS
}
function init_config_shard_server(){
    calc_shard_config

    IFS=','
    for i in $shard_conf
    do
        unset IFS
        for j in $i
        do
            IFS=':'
            read -r one_shard_ip one_shard_port one_shard_id <<< "$j"
            cmd=`echo "docker start shard-${CLUSTER_NAME}-$one_shard_ip-$one_shard_port && \
                docker exec shard-${CLUSTER_NAME}-$one_shard_ip-$one_shard_port shard_start; \
                sleep 5; \
                mv ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/conf/shard-server-example.config ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/conf/shard-server.config" | base64 -w0`

            ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_shard_ip}  "echo $cmd | base64 -d | bash"
            
            unset IFS
        done

        IFS=','
    done

    unset IFS
}

function reconfig_shard_server(){
    calc_shard_config
    calc_meta_server_htap_conf

    IFS=','
    for i in $shard_conf
    do
        unset IFS
            g_shard_id=`echo $i | awk -F'[ :]' '{print $3}'`
            one_conf=`for k in $i;do echo -n $k | sed 's/:[^:]*$/ /g';done | tr -s " " "," | sed 's/,$//'`

        for j in $i
        do
            IFS=':'
                read -r one_shard_ip one_shard_port one_shard_id <<< "$j"
            unset IFS

            stream_port=$(($one_shard_port+1))

            echo > /tmp/shard_config.tmp
            # Cluster common items
            echo "sed -i \"s/^shard_id=.*/shard_id=$g_shard_id/\" ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/conf/shard-server.config" >> /tmp/shard_config.tmp
            echo "sed -i \"s/^addr=.*/addr=${one_shard_ip}:${one_shard_port}/\" ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/conf/shard-server.config" >> /tmp/shard_config.tmp
            echo "sed -i \"s/^stream_addr=.*/stream_addr=${one_shard_ip}:${stream_port}/\" ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/conf/shard-server.config" >> /tmp/shard_config.tmp
            echo "sed -i \"s/^meta_server_addrs=.*/meta_server_addrs=${meta_conf}/\" ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/conf/shard-server.config" >> /tmp/shard_config.tmp
            echo "sed -i \"s/^conf=.*/conf=${one_conf}/\" ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/conf/shard-server.config" >> /tmp/shard_config.tmp
            
            # config.sh common items
            for c in ${SHARD_CONFIG}
            do
                if [[ ${c} =~ ^\s*# ]]; then
                    continue
                fi

                if [ "${c:0:1}" = "#" ]
                then
                    continue
                fi
                key=`echo $c | awk -F'=' '{print $1}'`
                value=`echo $c | awk -F'=' '{print $2}'`
                if [ "$key" != "" ] && [ "$value" != "" ]
                then
                    echo "sed -i \"s/^${key}=.*/${key}=${value}/\" ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/conf/shard-server.config" >> /tmp/shard_config.tmp
                fi
            done
            unset c key value 

            cmd=`cat /tmp/shard_config.tmp | base64 -w0`
            # cat /tmp/shard_config.tmp
            ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_shard_ip}  "echo $cmd | base64 -d | bash"
            # echo $cmd
        done

        unset g_shard_id one_conf
        IFS=','
    done
    
    unset IFS
}

function start_shard_server(){
    calc_shard_config

    IFS=','
    for i in $shard_conf
    do
        unset IFS
        for j in $i
        do
            IFS=':'
            read -r one_shard_ip one_shard_port one_shard_id <<< "$j"
            cmd=`echo "docker start shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port} && docker exec shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port} shard_start"  | base64 -w0`

            ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_shard_ip}  "echo $cmd | base64 -d | bash"
            
            unset IFS 
        done

        IFS=','
    done
    unset IFS
}
function stop_shard_server(){
    calc_shard_config

    IFS=','
    for i in $shard_conf
    do
        unset IFS
        for j in $i
        do
            IFS=':'
            read -r one_shard_ip one_shard_port one_shard_id <<< "$j"
            cmd=`echo "docker exec shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port} /opt/distribute-graphdb/shard-server stop && docker stop shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}"  | base64 -w0`

            ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_shard_ip}  "echo $cmd | base64 -d | bash"
            
            unset IFS 
        done

        IFS=','
    done
    unset IFS
}
function status_shard_server(){
    calc_shard_config

    echo "------- shard status ------- :"

    IFS=','
    for i in $shard_conf
    do
        unset IFS
        for j in $i
        do
            IFS=':'
            read -r one_shard_ip one_shard_port one_shard_id <<< "$j"
            echo -n "$one_shard_ip $one_shard_port $one_shard_id :   "
            cmd=`echo "docker exec shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port} ps -ef| grep shard-server | grep -v grep "  | base64 -w0`

            ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_shard_ip}  "echo $cmd | base64 -d | bash" || echo
            
            unset IFS 
        done

        IFS=','
    done
    unset IFS
}

function create_shard_server(){
    calc_shard_config

    IFS=','
    for i in $shard_conf
    do
        unset IFS
        for j in $i
        do
            IFS=':'
            read -r one_shard_ip one_shard_port one_shard_id <<< "$j"
            cmd=`echo "docker run -itd \
                    --net=host \
                    --ulimit nofile=90000:90000 --privileged --cap-add=SYS_PTRACE --security-opt seccomp=unconfined \
                    -v ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/conf:/opt/distribute-graphdb/config \
                    -v ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/shard_data:/opt/distribute-graphdb/shard_data \
                    -v ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/log:/opt/distribute-graphdb/log \
                    -e TZ=UTC \
                    --name shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port} ${NAME_IMAGE}" | base64 -w0`

            ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_shard_ip}  "echo $cmd | base64 -d | bash"
            
            unset IFS 
        done

        IFS=','
    done

    init_config_shard_server
    reconfig_shard_server
    start_shard_server
    unset IFS
}

function update_shard_server(){
    calc_shard_config

    IFS=','
    for i in $shard_conf
    do
        unset IFS
        for j in $i
        do
            IFS=':'
            read -r one_shard_ip one_shard_port one_shard_id <<< "$j"
            cmd=`echo "docker rm -f shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port} && \
                    docker run -itd \
                    --net=host \
                    --ulimit nofile=90000:90000 --privileged --cap-add=SYS_PTRACE --security-opt seccomp=unconfined \
                    -v ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/conf:/opt/distribute-graphdb/config \
                    -v ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/shard_data:/opt/distribute-graphdb/shard_data \
                    -v ${DOCKER_MOUNT_PATH}/shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port}/log:/opt/distribute-graphdb/log \
                    -e TZ=UTC \
                    --name shard-${CLUSTER_NAME}-${one_shard_ip}-${one_shard_port} ${NAME_IMAGE}" | base64 -w0`

            ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_shard_ip}  "echo $cmd | base64 -d | bash"
            
            unset IFS 
        done

        IFS=','
    done
    unset IFS
}

function add_shard () {
    # ./ultipa_cluster_manager_cli add_shard --shard_id=$shard_id --meta_conf=$meta_conf --replicas_base64=$replicas_base64

    calc_shard_config
    calc_meta_server_htap_conf
    calc_name_server_private_ip_port_list

    unset one_name_ip one_name_port
    n=`echo $name_private_conf | awk -F, '{print $1}'`
    one_name_ip=`echo $n | awk -F: '{print $1}'`
    one_name_port=`echo $n | awk -F: '{print $2}'`
    name1="name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}"

    echo > /tmp/add_shard.tmp

    IFS=','
    for i in $shard_conf
    do
        unset IFS
            g_shard_id=`echo $i | awk -F'[ :]' '{print $3}'`
            one_conf=`for k in $i;do echo -n $k | sed 's/:[^:]*$/ /g';done | tr -s " " "," | sed 's/,$//'`

        unset replicas
        for j in $i
        do
            IFS=':'
                read -r one_shard_ip one_shard_port one_shard_id <<< "$j"
            unset IFS 

            stream_port=$(($one_shard_port+1))
            if [ -z $replicas ]
            then
                replicas="{\"addr\":\"$one_shard_ip:$one_shard_port\",\"streamAddr\":\"$one_shard_ip:$stream_port\"}"
            else
                replicas=$replicas,"{\"addr\":\"$one_shard_ip:$one_shard_port\",\"streamAddr\":\"$one_shard_ip:$stream_port\"}"
            fi

        done
        echo "adding shard $replicas"
        exec_in_docker=$(echo "/opt/distribute-graphdb/ultipa_cluster_manager_cli add_shard --shard_id=$g_shard_id --meta_conf=$meta_conf --replicas=[`echo $replicas`]" | sed 's/"/\\"/g' | sed 's/\]/"\]/g' | sed 's/\[/"\[/g' | base64 -w0)
        echo "docker exec $name1 sh -c \"echo $exec_in_docker | base64 -d | bash\"" >> /tmp/add_shard.tmp
        unset g_shard_id one_conf
        IFS=','
    done
    
    unset IFS

    cmd=`cat /tmp/add_shard.tmp | base64 -w0`
    ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_name_ip}  "echo $cmd | base64 -d | bash"
    rm -f /tmp/add_shard.tmp
}
# source config.sh
# add_shard

#        -------*** hdc ***-------
function calc_hdc_config () {
    if [ -z "$HDC_SERVER_START_PORT" ]
    then
        hdc_port=55555
    else
        hdc_port=$HDC_SERVER_START_PORT
    fi

    hdc_conf=""
    unset i m
    for i in $HDC_SERVER_LIST
    do
        m=$i:$hdc_port
        if [ "$hdc_conf" != "" ]
        then
            hdc_conf=$hdc_conf,$m
        else
            hdc_conf=$m
        fi
        hdc_port=$(($hdc_port+1))
    done      
}

function destroy_hdc_server(){
    calc_hdc_config
    unset i
    for i in `echo $hdc_conf | tr -s ',' ' '`
    do
        one_hdc_ip=`echo $i | awk -F: '{print $1}'`
        one_hdc_port=`echo $i | awk -F: '{print $2}'`

        cmd=`echo "docker rm -f hdc-${CLUSTER_NAME}-${one_hdc_ip}-${one_hdc_port} && \
                   rm -rf ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}/conf && \
                   rm -rf ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}/data && \
                   rm -rf ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}/log && \
                   rmdir ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}" | base64 -w0`

        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_hdc_ip}  "echo $cmd | base64 -d | bash"

        unset cmd
        unset one_hdc_ip
        unset one_hdc_port
    done
}

function init_config_hdc_server(){
    calc_hdc_config
    unset i
    for i in `echo $hdc_conf | tr -s ',' ' '`
    do
        one_hdc_ip=`echo $i | awk -F: '{print $1}'`
        one_hdc_port=`echo $i | awk -F: '{print $2}'`

        cmd=`echo "docker start hdc-${CLUSTER_NAME}-${one_hdc_ip}-${one_hdc_port} && docker exec hdc-${CLUSTER_NAME}-${one_hdc_ip}-${one_hdc_port} start; \
            sleep 5; \
            mv ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}/conf/hdc-server-example.config ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}/conf/hdc-server.config" | base64 -w0`

        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_hdc_ip}  "echo $cmd | base64 -d | bash"

        unset cmd
        unset one_hdc_ip
        unset one_hdc_port
    done
}

function reconfig_hdc_server () {
    calc_hdc_config
    calc_meta_server_htap_conf

    unset i
    for i in `echo $hdc_conf | tr -s ',' ' '`
    do
        one_hdc_ip=`echo $i | awk -F: '{print $1}'`
        one_hdc_port=`echo $i | awk -F: '{print $2}'`

        echo > /tmp/hdc_config.tmp
        # Cluster HTAP modification, common items
        echo "sed -i \"s/^addr=.*/addr=${one_hdc_ip}:${one_hdc_port}/\" ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}/conf/hdc-server.config" >> /tmp/hdc_config.tmp
        echo "sed -i \"s/^server_name=.*/server_name=hdc-${one_hdc_port}/\" ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}/conf/hdc-server.config" >> /tmp/hdc_config.tmp
        echo "sed -i \"s/^meta_server_addrs=.*/meta_server_addrs=${meta_conf}/\" ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}/conf/hdc-server.config" >> /tmp/hdc_config.tmp

        # config.sh common items
        for c in ${HDC_CONFIG}
        do
            if [[ ${c} =~ ^\s*# ]]; then
                continue
            fi

            key=`echo $c | awk -F'=' '{print $1}'`
            value=`echo $c | awk -F'=' '{print $2}'`
            if [ "$key" != "" ] && [ "$value" != "" ]
            then
                echo "sed -i \"s/^${key}=.*/${key}=${value}/\" ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}/conf/hdc-server.config" >> /tmp/hdc_config.tmp
            fi
        done
        unset c key value

        cmd=`cat /tmp/hdc_config.tmp | base64 -w0`

        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_hdc_ip}  "echo $cmd | base64 -d | bash"

        unset cmd
        unset one_hdc_ip
        unset one_hdc_port
    done
}

function start_hdc_server(){
    calc_hdc_config
    unset i
    for i in `echo $hdc_conf | tr -s ',' ' '`
    do
        one_hdc_ip=`echo $i | awk -F: '{print $1}'`
        one_hdc_port=`echo $i | awk -F: '{print $2}'`

        cmd=`echo "docker start hdc-${CLUSTER_NAME}-${one_hdc_ip}-${one_hdc_port} && docker exec hdc-${CLUSTER_NAME}-${one_hdc_ip}-${one_hdc_port} start" | base64 -w0`

        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_hdc_ip}  "echo $cmd | base64 -d | bash"

        unset cmd
        unset one_hdc_ip
        unset one_hdc_port
    done
}

function stop_hdc_server(){
    calc_hdc_config
    unset i
    for i in `echo $hdc_conf | tr -s ',' ' '`
    do
        one_hdc_ip=`echo $i | awk -F: '{print $1}'`
        one_hdc_port=`echo $i | awk -F: '{print $2}'`

        cmd=`echo "docker exec hdc-${CLUSTER_NAME}-${one_hdc_ip}-${one_hdc_port} /opt/hdc-server/hdc-server stop && docker stop hdc-${CLUSTER_NAME}-${one_hdc_ip}-${one_hdc_port}" | base64 -w0`

        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_hdc_ip}  "echo $cmd | base64 -d | bash"

        unset cmd
        unset one_hdc_ip
        unset one_hdc_port
    done
}

function status_hdc_server(){
    calc_hdc_config
    echo "------- hdc status ------- :"
    unset i
    for i in `echo $hdc_conf | tr -s ',' ' '`
    do
        one_hdc_ip=`echo $i | awk -F: '{print $1}'`
        one_hdc_port=`echo $i | awk -F: '{print $2}'`
        echo -n "$one_hdc_ip $one_hdc_port :"
        cmd=`echo "docker exec hdc-${CLUSTER_NAME}-${one_hdc_ip}-${one_hdc_port} ps -ef| grep hdc-server | grep -v grep" | base64 -w0`

        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_hdc_ip}  "echo $cmd | base64 -d | bash" || echo

        unset cmd
        unset one_hdc_ip
        unset one_hdc_port
    done
}

function create_hdc_server(){
    calc_hdc_config
    unset i
    for i in `echo $hdc_conf | tr -s ',' ' '`
    do
        one_hdc_ip=`echo $i | awk -F: '{print $1}'`
        one_hdc_port=`echo $i | awk -F: '{print $2}'`

        cmd=`echo "docker run -itd \
        --net=host \
        --ulimit nofile=90000:90000 --privileged --cap-add=SYS_PTRACE --security-opt seccomp=unconfined \
        -v ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}/conf:/opt/hdc-server/config \
        -v ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}/data:/opt/hdc-server/data \
        -v ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}/log:/opt/hdc-server/log \
        -e TZ=UTC \
        --name hdc-${CLUSTER_NAME}-${one_hdc_ip}-${one_hdc_port} ${HDC_IMAGE}" | base64 -w0`

        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_hdc_ip}  "echo $cmd | base64 -d | bash"

        unset cmd
        unset one_hdc_ip
        unset one_hdc_port
    done
    init_config_hdc_server
    reconfig_hdc_server
    start_hdc_server
}

function update_hdc_server(){
    calc_hdc_config
    unset i
    for i in `echo $hdc_conf | tr -s ',' ' '`
    do
        one_hdc_ip=`echo $i | awk -F: '{print $1}'`
        one_hdc_port=`echo $i | awk -F: '{print $2}'`

        cmd=`echo "docker rm -f hdc-${CLUSTER_NAME}-${one_hdc_ip}-${one_hdc_port} && \
        docker run -itd \
        --net=host \
        --ulimit nofile=90000:90000 --privileged --cap-add=SYS_PTRACE --security-opt seccomp=unconfined \
        -v ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}/conf:/opt/hdc-server/config \
        -v ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}/data:/opt/hdc-server/data \
        -v ${DOCKER_MOUNT_PATH}/hdc-${CLUSTER_NAME}-${one_hdc_port}/log:/opt/hdc-server/log \
        -e TZ=UTC \
        --name hdc-${CLUSTER_NAME}-${one_hdc_ip}-${one_hdc_port} ${HDC_IMAGE}" | base64 -w0`

        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_hdc_ip}  "echo $cmd | base64 -d | bash"

        unset cmd
        unset one_hdc_ip
        unset one_hdc_port
    done
}

function add_hdc(){
    # ./ultipa_cluster_manager_cli add_hdc --name=$name --addr=$addr --meta_conf=$meta_conf
    calc_hdc_config
    calc_meta_server_htap_conf
    calc_name_server_private_ip_port_list

    unset one_name_ip one_name_port
    n=`echo $name_private_conf | awk -F, '{print $1}'`
    one_name_ip=`echo $n | awk -F: '{print $1}'`
    one_name_port=`echo $n | awk -F: '{print $2}'`
    name1="name-${CLUSTER_NAME}-${one_name_ip}-${one_name_port}"

    echo > /tmp/add_hdc.tmp
    unset i a_hdc_addr a_hdc_port
    for i in `echo $hdc_conf | tr -s ',' ' '`
    do
        a_hdc_addr=`echo $i|awk -F: '{print $1}'`
        a_hdc_port=`echo $i|awk -F: '{print $2}'`
        echo "adding hdc server $a_hdc_addr:$a_hdc_port"
        echo "docker exec $name1 /opt/distribute-graphdb/ultipa_cluster_manager_cli add_hdc --name=hdc-$a_hdc_port --addr=$a_hdc_addr:$a_hdc_port --meta_conf=$meta_conf" >> /tmp/add_hdc.tmp
    done

    cmd=`cat /tmp/add_hdc.tmp | base64 -w0`
    ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_name_ip}  "echo $cmd | base64 -d | bash"

    rm -f /tmp/add_hdc.tmp
}

#        -------*** image ***-------
function image_upload(){
    unset i filename
    for i in $NAME_SERVER_LIST
    do
        {
            echo "uploading $SHARD_NAME_IMAGE_TAR to $i"
            filename=`basename $SHARD_NAME_IMAGE_TAR`
            scp -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SHARD_NAME_IMAGE_TAR $SSH_USER@$i:/tmp && \
            ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i "docker load < /tmp/$filename && rm -f /tmp/$filename"
        } &
    done

    unset i filename
    for i in $META_SERVER_LIST
    do
        {
            echo "uploading $META_IMAGE_TAR to $i"
            filename=`basename $META_IMAGE_TAR`
            scp -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $META_IMAGE_TAR $SSH_USER@$i:/tmp && \
            ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i "docker load < /tmp/$filename" && \
            rm -f /tmp/$filename
        } &
    done

    unset i filename
    for i in $HDC_SERVER_LIST
    do
        filename=`basename $HDC_IMAGE_TAR`
        {
            echo "uploading $HDC_IMAGE_TAR to $i"
            scp -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $HDC_IMAGE_TAR $SSH_USER@$i:/tmp && \
            ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i "docker load < /tmp/$filename" && \
            rm -f /tmp/$filename
        } &
    done

    unset i filename
    for i in `echo $SHARD_SERVER_LIST | tr -s ',' ' '`
    do
        filename=`basename $SHARD_NAME_IMAGE_TAR`
        {
            echo "uploading $SHARD_NAME_IMAGE_TAR to $i"
            scp -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SHARD_NAME_IMAGE_TAR $SSH_USER@$i:/tmp && \
            ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i "docker load < /tmp/$filename" && \
            rm -f /tmp/$filename
        } &
    done

    wait
}

function image_info () {
    unset i
    for i in $NAME_SERVER_LIST
    do
        echo "---------------------  name server $i images ---------------------"
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i docker images
        echo
    done

    unset i
    for i in $META_SERVER_LIST
    do
        echo "---------------------  meta server $i images ---------------------"
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i docker images
        echo
    done

    unset i
    for i in $HDC_SERVER_LIST
    do
        echo "---------------------  hdc server $i images ---------------------"
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i docker images
        echo
    done

    unset i
    for i in `echo $SHARD_SERVER_LIST | tr -s ',' ' '`
    do
        echo "---------------------  shard server $i images ---------------------"
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i docker images
        echo
    done
}

function image_delete_all () {

    # cmd="docker images | awk '{if($1 ~ /docker-registry.ultipa-inc.org:5000/) print $3}' | xargs -r docker rmi"
    cmd=$(echo "docker images | awk '{if(\$1 ~ /docker-registry.ultipa-inc.org:5000/) print \$3}' | xargs -r docker rmi " | base64 -w0)
    # ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_name_ip}  "echo $cmd | base64 -d | bash"

    unset i
    for i in $NAME_SERVER_LIST
    do
        echo "---------------------  name server $i images ---------------------"
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i "echo $cmd | base64 -d | bash"
        echo
    done

    unset i
    for i in $META_SERVER_LIST
    do
        echo "---------------------  meta server $i images ---------------------"
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i "echo $cmd | base64 -d | bash"
        echo
    done

    unset i
    for i in $HDC_SERVER_LIST
    do
        echo "---------------------  hdc server $i images ---------------------"
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i "echo $cmd | base64 -d | bash"
        echo
    done

    unset i
    for i in `echo $SHARD_SERVER_LIST | tr -s ',' ' '`
    do
        echo "---------------------  shard server $i images ---------------------"
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i "echo $cmd | base64 -d | bash"
        echo
    done
}



function image_delete () {

    # cmd="docker images | awk '{if($1 ~ /docker-registry.ultipa-inc.org:5000/) print $3}' | xargs -r docker rmi"
    # cmd=$(echo "docker images | awk '{if(\$1 ~ /docker-registry.ultipa-inc.org:5000/) print \$3}' | xargs -r docker rmi " | base64 -w0)
    # ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_name_ip}  "echo $cmd | base64 -d | bash"

    unset i
    for i in $NAME_SERVER_LIST
    do
        echo "---------------------  name server $i images ---------------------"
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i "docker rmi $NAME_IMAGE"
        echo
    done

    unset i
    for i in $META_SERVER_LIST
    do
        echo "---------------------  meta server $i images ---------------------"
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i "docker rmi $META_IMAGE"
        echo
    done

    unset i
    for i in $HDC_SERVER_LIST
    do
        echo "---------------------  hdc server $i images ---------------------"
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i "docker rmi $HDC_IMAGE"
        echo
    done

    unset i
    for i in `echo $SHARD_SERVER_LIST | tr -s ',' ' '`
    do
        echo "---------------------  shard server $i images ---------------------"
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@$i "docker rmi $SHARD_IMAGE"
        echo
    done
}


# ---------------------  upload license ---------------------
function license_upload () {
    calc_meta_server_htap_conf

    if [ ! -f "$LICENSE_FILE_PATH" ] || [ ! -f "$ALGO_LICENSE_FILE_PATH" ] ; then
        echo "Error: License file not found at path: $LICENSE_FILE_PATH $ALGO_LICENSE_FILE_PATH"
        exit 1
    fi

    for i in `echo $meta_conf | tr -s ',' ' '`
    do
        one_meta_ip=`echo $i | awk -F: '{print $1}'`
        one_meta_port=`echo $i | awk -F: '{print $2}'`
        cmd=`echo "mkdir -p ${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/cert" | base64 -w0`
        ssh -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $SSH_USER@${one_meta_ip}  "echo $cmd | base64 -d | bash"

        scp -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $LICENSE_FILE_PATH  $SSH_USER@${one_meta_ip}:${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/cert/ultipa.lic
        scp -o BatchMode=yes -o StrictHostKeyChecking=no -i $SSH_PRIVATE_KEY $ALGO_LICENSE_FILE_PATH  $SSH_USER@${one_meta_ip}:${DOCKER_MOUNT_PATH}/meta-${CLUSTER_NAME}-${one_meta_port}/cert/ultipa_algo.lic
    done    
}


# ---------------------  Calculate cluster information ---------------------
function calc_cluster_info(){
    calc_name_server_private_ip_port_list
    echo "name server:"
    # Extract the private IPs and port pairs
    private_pairs=$(echo "$name_private_conf" | tr ',' '\n')
    output=""
    for pair in $private_pairs; do
        ip=$(echo "$pair" | awk -F':' '{print $1}')           # Extract IP
        private_port=$(echo "$pair" | awk -F':' '{print $2}') # Extract private port
        public_port=$((private_port - 1))                     # Calculate the corresponding public port
        output+="${ip}:${public_port},"                       # Combine into a new format and add to the output string
    done

    output="${output%,}"
    echo "$output"
    echo

    calc_meta_server_htap_conf
    echo "meta server:"
    echo $meta_conf
    echo

    calc_shard_config
    echo "shard server:"
    echo $shard_conf
    echo

    calc_hdc_config
    echo "hdc server:"
    echo $hdc_conf
}

# --------------------- Parameter handling ---------------------

# Function to display usage
usage() {
    echo "Usage:"
    echo "$VERSION"
    echo "$0 image upload --config example.sh"
    echo "$0 image info --config example.sh"
    echo "$0 image delete --config example.sh # Delete the image defined in --config example.sh on the target machine"
    echo "$0 image DELALL --config example.sh # Delete all Docker images under the domain docker-registry.ultipa-inc.org:5000 on the target machine. Use with caution!!!"
    echo "$0 cluster create --config example.sh"
    echo "$0 cluster start --server name --config example.sh"
    echo "$0 cluster stop --server name --config example.sh"
    echo "$0 cluster info --config example.sh"
    echo "$0 cluster stat --config example.sh"
    echo "$0 cluster reconfig --config example.sh"
    echo "$0 cluster destroy --config example.sh"
    echo "$0 cluster update --config example.sh"
    echo "$0 cluster addhdc --config example.sh"
    echo "$0 cluster addshard --config example.sh"
    echo "$0 cluster genconf"
    echo "$0 lic upload --config example.sh"
    exit 1
}

# Ensure at least 3 arguments are provided
if [[ "$1" != "cluster" && "$2" != "genconf" ]]
then
    if [ "$#" -lt 3 ]; then
        usage
    fi
fi

# Variables to store options
CONFIG=""
SERVER=""

# Parse arguments
while [[ "$#" -gt 0 ]]; do
    case $1 in
        --config)
            CONFIG="$2"
            shift 2
            ;;
        --server)
            SERVER="$2"
            shift 2
            ;;
        image)
            ACTION_GROUP="image"
            ACTION="$2"
            shift 2
            ;;
        cluster)
            ACTION_GROUP="cluster"
            ACTION="$2"
            shift 2
            ;;
        lic)
            ACTION_GROUP="lic"
            ACTION="$2"
            shift 2
            ;;
        *)
            echo "Unknown parameter: $1"
            usage
            ;;
    esac
done

function config_check(){
    # Check if config is provided
    if [ -z "$CONFIG" ]; then
        echo "Error: --config must be provided."
        echo "generic example config with: $0 cluster genconfig"
        echo "for more help : $0 help"
        exit 1
    fi


    source $CONFIG

    PROTECTED_DIRS=(
    "/"                
    "/bin"             
    "/boot"            
    "/dev"             
    "/etc"             
    "/home"            
    "/lib"             
    "/lib64"           
    "/media"           
    "/mnt"             
    "/opt"             
    "/proc"            
    "/root"            
    "/run"             
    "/sbin"            
    "/srv"             
    "/sys"             
    "/tmp"             
    "/usr"             
    "/var"             
    )


    if [[ "$DOCKER_MOUNT_PATH" =~ \  ]]; then
        echo "ERROR! DOCKER_MOUNT_PATH can't include space！"
    exit 1
    fi

    for protected_dir in "${PROTECTED_DIRS[@]}"; do
    if [[ "$DOCKER_MOUNT_PATH" == "$protected_dir" || "$DOCKER_MOUNT_PATH" == "" ]]; then
        echo "ERROR! DOCKER_MOUNT_PATH can't be system path or empty !"
        exit 1
    fi
    done
}

if [[ "$ACTION_GROUP" != "cluster" || "$ACTION" != "genconf" ]]
then
    config_check
fi

# Call appropriate function based on action
case "$ACTION_GROUP" in
    image)
        case "$ACTION" in
            DELALL)
                image_delete_all
                ;;
            delete)
                image_delete
                ;;
            upload)
                image_upload
                ;;
            info) 
                image_info
                ;;
            *) 
                echo "Unknown image action: $ACTION"; usage 
                ;;
        esac
        ;;
    cluster)
        case "$ACTION" in
            create)
                license_upload
                create_meta_server
                create_name_server
                create_hdc_server
                create_shard_server
                add_hdc
                add_shard
                ;;
            addhdc)
                add_hdc
                ;;
            addshard)
                add_shard
                ;;
            start)
                if [ -z "$SERVER" ]; then
                    start_meta_server
                    start_name_server
                    start_hdc_server
                    start_shard_server
                else
                    case $SERVER in
                        meta)
                            start_meta_server
                            ;;
                        name)
                            start_name_server
                            ;;
                        hdc)
                            start_hdc_server
                            ;;
                        shard)
                            start_shard_server
                            ;;
                    esac
                fi
                ;;
            stop)
                if [ -z "$SERVER" ]; then
                    stop_shard_server
                    stop_hdc_server
                    stop_name_server
                    stop_meta_server
                else
                    case $SERVER in
                        meta)
                            stop_meta_server
                            ;;
                        name)
                            stop_name_server
                            ;;
                        hdc)
                            stop_hdc_server
                            ;;
                        shard)
                            stop_shard_server
                            ;;
                    esac               
                fi                
                ;;
            info)
                calc_cluster_info
                ;;
            stat)
                status_meta_server
                status_name_server
                status_shard_server
                status_hdc_server
                ;;
            reconfig)
                reconfig_meta_server
                reconfig_name_server
                reconfig_shard_server
                reconfig_hdc_server
                ;;
            destroy)
                destroy_hdc_server
                destroy_shard_server
                destroy_name_server
                destroy_meta_server
                echo
                ;;
            update)
                stop_shard_server
                stop_hdc_server
                stop_name_server
                stop_meta_server
                update_meta_server
                update_shard_server
                update_hdc_server
                update_name_server
                start_meta_server
                start_name_server
                start_hdc_server
                start_shard_server
                ;;
            genconf)
                gen_example_config
                ;;
            *) echo "Unknown cluster action: $ACTION"; usage ;;
        esac
        ;;
    lic)
        case "$ACTION" in
            upload)
                license_upload
                ;;
            *) echo "Unknown lic action: $ACTION"; usage ;;
        esac
        ;;
    *)
        echo "Unknown action group: $ACTION_GROUP"
        usage
        ;;
esac