#!/usr/bin/env python3
#-*- coding:utf-8 -*-
"""
Copyright (c): 2021, Huawei Tech. Co., Ltd.
Description  : A utility to install gds or roach_client.
"""
try:
    import os
    import sys
    import getopt
    import pwd
    import subprocess
    import time
    import shlex
    import re

    sys.path.append(os.path.split(os.path.realpath(__file__))[0] + "/../../script/")
    from gspylib.common.ErrorCode import ErrorCode
    from gspylib.common.Common import DefaultValue
    from gspylib.common.GaussLog import GaussLog
    from gspylib.os.gsfile import g_file
    from gspylib.threads.SshTool import SshTool
    from gspylib.os.gsplatform import g_Platform
    from common_tools import GDSUtils
except ImportError as e:
    sys.exit("[GAUSS-52200] : Unable to import module: %s." % str(e))

# APP_NAME: gds or roach_client
APP_NAME = __file__[(0 if __file__.rfind("/") == -1 else __file__.rfind("/") + 1):__file__.rfind("_")]

# action name
#set the tools environment variable
ACTION_PREPARE_USER_CRON_SERVICE = "prepare_user_cron_service"

# global variables
pkg_path = ""
pkg_name = ""
install_dir = ""
gds_user = ""
gds_user_group = ""
install_hosts = []
ping_hosts = []
root_passwd = ""
gds_user_passwd = ""
log_uuid = ""
local_flag = False

install_log_path = ""
install_tools_path = ""
temp_env_file = "/tmp/.%s_temp_env" % APP_NAME
temp_super_sshtool_log = "/tmp/super_ssh_tool.log"
temp_common_sshtool_log = "/tmp/common_ssh_tool.log"
key = 'gds_install'


def usage():
    """
Usage:
    %s_install -I /path/to/install_dir -U user --pkg /path/to/pkg.tar.gz -G user_group --host\
     [/path/to/hostfile | ipaddr1,ipaddr2...] [--ping-host [/path/to/hostfile | ipaddr1,ipaddr2...]]
Common options:
    -I                                The install direcotry of %s.
    -U                                The OS user of %s.
    -G                                The OS user's group of %s.
    --pkg                             The path to %s package.
    --host                            The path of ip address list for nodes, or ip address string separated by comma.
    --ping-host                       The path of ip address list for ping check,\
     or ip address string separated by comma.
    --help                            Show help information.
    -V                                Show version information.
    """
    print(usage.__doc__ % ((APP_NAME,) * 5))


def parse_command_line():
    """
    function: Check parameter from command line
    """
    global install_dir
    global gds_user
    global gds_user_group
    global install_hosts
    global ping_hosts
    global pkg_path

    try:
        opts, args = getopt.getopt(sys.argv[1:], "I:U:G:Vh", ["host=", "help", "pkg=", "ping-host="])

        if len(args) > 0:
            GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50000"] % str(args[0]))

        for (key, value) in opts:
            if key in ('-h', "--help"):
                usage()
                sys.exit(0)
            elif key == "-I":
                install_dir = value
            elif key == "-U":
                gds_user = value
            elif key == "-G":
                gds_user_group = value
            elif key == "-V":
                GDSUtils.get_version_info(APP_NAME)
                sys.exit(0)
            elif key == "--host":
                install_hosts = GDSUtils.get_hosts_from_param(value)
            elif key == "--ping-host":
                ping_hosts = GDSUtils.get_hosts_from_param(value)
            elif key == "--pkg":
                pkg_path = value
            else:
                GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50000"] % key)
    except Exception as e:
        GaussLog.printMessage(ErrorCode.GAUSS_500["GAUSS_50015"] % str(e))
        usage()
        sys.exit()


def check_user_param():
    """
    function: check -U and -G parameter, namely gds_user and gds_user_group.
    """
    if gds_user == "":
        GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % 'U' + ".")
    elif ":" in gds_user:
        GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50004"] % 'U')

    # check group info
    if gds_user_group == "":
        GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % 'G' + ".")
    if gds_user == "root" or gds_user_group == "root":
        GaussLog.exitWithError("[GAUSS-50301] : The user/group cannot be a root user/group.")

    # check if user exists
    try:
        if pwd.getpwnam(gds_user).pw_uid == 0:
            # user exists and uid is 0, exit.
            GaussLog.exitWithError(ErrorCode.GAUSS_503["GAUSS_50302"])
    except Exception:
        # user does not exists.
        pass


def check_parameters():
    """
    function: Check command line parameters, and init global variables related to those parameters
    input  : NA
    output : NA
    """
    global gds_user
    global gds_user_group
    global install_dir
    global super_ssh_tool
    global common_ssh_tool
    global install_log_path
    global install_tools_path
    global pkg_name
    global pkg_path
    global log_uuid
    global local_flag

    if pkg_path == "":
        GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50012"] % '--pkg')
    else:
        pkg_path_arg = pkg_path
        pkg_path = os.path.realpath(pkg_path)
        if not os.path.exists(pkg_path):
            GaussLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50201"] % pkg_path_arg)
        pkg_name = pkg_path.split("/")[-1]

    check_user_param()

    install_dir = "/opt/%s/packages/" % gds_user if install_dir == "" else install_dir
    install_dir = os.path.realpath(install_dir)
    install_log_path = os.path.normpath(os.path.join(install_dir, "./install_log/install_log.log"))
    install_tools_path = os.path.dirname(os.path.realpath(__file__))
    install_tools_path = os.path.normpath(os.path.join(install_tools_path, "./../"))

    if not install_hosts:
        GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % ('-host'))

    # check install_hosts
    for ip in install_hosts:
        if not GDSUtils.check_ip(ip):
            GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50011"] % ('--host', ip))

    # check local cluster
    _, local_flag, _ = GDSUtils.divide_local_remote(install_hosts)
    if not local_flag:
        GaussLog.exitWithError("[GAUSS-52605] : Current node's ip is not included in the '--host' option.")

    # init global variables
    super_ssh_tool = SshTool(install_hosts, key, temp_super_sshtool_log)
    common_ssh_tool = SshTool(install_hosts, key, temp_common_sshtool_log)
    log_uuid = GDSUtils.generate_log_uuid()


def create_install_dir_if_nonexist_on_one_node(ip):
    """
    function:
        Connect to a node, and check the install dir.If it does not exist then create it,
         finally change its owner to gds_user:gds_user_group.
    precondition:
        root's password is correct on each node.
    postcondition:
        NA
    input: ip
    """
    inner_cmd = "export LD_LIBRARY_PATH=/lib64:$LD_LIBRARY_PATH; ssh %s \'ls -ld %s\'" % (ip, install_dir)
    cmd = "su - %s -c \"%s\"" % (gds_user, inner_cmd)
    status, output = subprocess.getstatusoutput(cmd)
    if status != 0:
        # not exist, then create
        if output.find('No such file or directory') >= 0:
            toolpath = install_dir.split("/")
            toolpath[0] = "/" + toolpath[0]
            pathcmd = ""
            for path in toolpath:
                if path == "":
                    continue
                cmd = g_file.SHELL_CMD_DICT["createDir"] % (path, path, DefaultValue.MAX_DIRECTORY_MODE)
                pathcmd += "%s && cd %s && " % (cmd, path)
            inner_cmd = "export LD_LIBRARY_PATH=/lib64:$LD_LIBRARY_PATH; ssh %s \'%s\'" % (ip, pathcmd[:-4])
            cmd = "su - %s -c \"%s\"" % (gds_user, inner_cmd)
            status, output = subprocess.getstatusoutput(cmd)
            if status != 0:
                return {ip : ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + "With output: " + output.strip()}
            else:
                return {ip : ''}
        else:
            return {ip : ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + "With output: " + output.strip()}
    else:
        exist_dir_info = output.strip().split()
        # check rights
        if exist_dir_info[2] != gds_user:
            return {ip : (ErrorCode.GAUSS_503["GAUSS_50315"] % (gds_user, install_dir)) +
                " Please check if the path %s is already created by other users." % install_dir}
        # check whether directory
        if exist_dir_info[0][0] != 'd':
            return {ip : ErrorCode.GAUSS_502["GAUSS_50211"] % install_dir}
        # check whether empty
        inner_cmd = "export LD_LIBRARY_PATH=/lib64:$LD_LIBRARY_PATH; ssh %s \'ls -A %s|wc -w\'" % (ip, install_dir)
        cmd = "su - %s -c \"%s\"" % (gds_user, inner_cmd)
        status, output = subprocess.getstatusoutput(cmd)
        if status != 0:
            return {ip : ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + "With output: " + output.strip()}
        if output.strip() != "0":
            return {ip : ErrorCode.GAUSS_502["GAUSS_50202"] % install_dir}

    return {ip : ''}


def decompress_pkg_on_one_node(ip):
    """
    function:
        Connect to all nodes, then decompress the package and change mode to 755.
    precondition:
        gds_user is created and granted trust.
    postcondition:
        NA
    input: ip
    """
    # decompress cmd
    src_package = "'%s'/'%s'" % (install_dir, pkg_name)
    cmd = g_Platform.getDecompressFilesCmd(src_package, install_dir)
    # mkdir logs cmd
    logs_dir = "%s/logs" % install_dir
    cmd += " > /dev/null;" + g_file.SHELL_CMD_DICT["createDir"] % (logs_dir, logs_dir, DefaultValue.MAX_DIRECTORY_MODE)
    # chmod cmd
    dest_path = "'%s'/*" % install_dir
    cmd += ";" + g_Platform.getChmodCmd(str(DefaultValue.MAX_DIRECTORY_MODE), dest_path, True)
    # chown cmd
    cmd += ";" + g_Platform.getChownCmd(gds_user, gds_user_group, install_dir, True)
    return GDSUtils.exec_command_by_paramiko_on_one_node(ip, cmd, "root", root_passwd)


def scp_files(ssl_tool, src_file, target_dir, host_list=(), env_file="", gp_path="", parallel_num=300):
    """
    function: copy files to other path
    input : src_file, target_dir, host_list, env_file, gp_path, parallel_num
    output: NA
    """
    scp_cmd = "source /etc/profile"
    host_list = list(host_list)
    try:
        if env_file != "":
            mpp_rcfile = env_file
        else:
            mpp_rcfile = DefaultValue.getEnv(DefaultValue.MPPRC_FILE_ENV)
        if (mpp_rcfile != "") and (mpp_rcfile is not None):
            scp_cmd += " && source %s" % mpp_rcfile

        if gp_path == "":
            cmdpre = "%s && echo $TEMP_GDS_INSTALL_HOME" % scp_cmd
            (status, output) = subprocess.getstatusoutput(cmdpre)
            if (status != 0) or (output is None) or (output.strip() == ""):
                raise Exception(ErrorCode.GAUSS_518["GAUSS_51802"] % "INSTALL_HOME")
            install_home = output.strip()
        else:
            install_home = gp_path.strip()
        pscppre = "python3 %s/script/gspylib/pssh/bin/pscp" % install_home

        if len(host_list) == 0:
            scp_cmd += " && %s -r -v -t %s -p %s -h %s -o %s -e %s %s %s 2>&1 | tee %s" % \
                        (pscppre, ssl_tool._SshTool__timeout, parallel_num, ssl_tool._SshTool__hostsFile,
                         ssl_tool._SshTool__outputPath, ssl_tool._SshTool__errorPath, src_file,
                         target_dir, ssl_tool._SshTool__resultFile)
            host_list = ssl_tool.hostNames
        else:
            scp_cmd += " && %s -r -v -t %s -p %s -H %s -o %s -e %s %s %s 2>&1 | tee %s" % \
                        (pscppre, ssl_tool._SshTool__timeout, parallel_num, " -H ".join(host_list),
                         ssl_tool._SshTool__outputPath, ssl_tool._SshTool__errorPath, src_file,
                         target_dir, ssl_tool._SshTool__resultFile)
        scp_cmd = "su - %s -c \"%s\"" % (gds_user, scp_cmd)
        (status, output) = subprocess.getstatusoutput(scp_cmd)
        if status != 0:
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50216"] %
                            ("file [%s]" % src_file) + " To directory: %s." % target_dir + " Error:%s" % output)
        if output.find("Timed out") > 0:
            raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % scp_cmd + " Error:%s" % output)

        # ip and host name should match here
        result_map, output_collect = ssl_tool.parseSshResult(scp_cmd, host_list)
    except Exception as e:
        ssl_tool.clenSshResultFiles()
        raise e

    for host in host_list:
        if result_map.get(host) != DefaultValue.SUCCESS:
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50216"] %
                            ("file [%s]" % src_file) + " To directory: %s." % target_dir + " Error:%s" % output_collect)


def clean_install_dir_if_failed(ip):
    cmd = g_file.SHELL_CMD_DICT["deleteDir"] % (install_dir, install_dir)
    return GDSUtils.exec_command_by_paramiko_on_one_node(ip, cmd, "root", root_passwd)


def check_exec_result(exec_result):
    """
    function: check parallelly execution result during installation, when encounting error messages then throw.
    """
    if not exec_result:
        return
    raise_str = ""
    for key in exec_result:
        if exec_result[key]:
            raise_str += "On host %s: %s" % (key, exec_result[key]) + "\n"
    if raise_str:
        raise Exception(raise_str)


def dispatch_package():
    """
    function:
        Dispatch gds package to all nodes and decompress by gds_user
    precondition:
        1. root's password is right.
        2. gds_user has been created and granted trust
    postcondition:
        NA
    """
    dest_package_dir = install_dir
    dir_created = False
    try:
        # Retry 3 times, if dispatch failed.
        for i in range(3):
            try:
                GaussLog.printMessage("Begin to dispatch gds package to install path.")
                # Check whether dest_package_dir is existing on hostname, done by root
                if not dir_created:
                    exec_result = GDSUtils.exec_command_remote_parallelly(create_install_dir_if_nonexist_on_one_node,
                                                                          install_hosts, timeout=GDSUtils.TIMEOUT)
                    check_exec_result(exec_result)
                    dir_created = True
                # Send compressed package to every host, done by gds_user
                scp_files(common_ssh_tool, pkg_path, dest_package_dir, install_hosts, temp_env_file)
                # Decompress package on every host and change permission mode, done by gds_user
                exec_result = GDSUtils.exec_command_remote_parallelly(decompress_pkg_on_one_node,
                                                                      install_hosts,
                                                                      timeout=GDSUtils.TIMEOUT)
                check_exec_result(exec_result)
            except Exception as e:
                error_msg = str(e).lower()
                escape_loop_situation = ["permission", "no space", "must be empty", "not match with the owner"]
                for situation in escape_loop_situation:
                    if situation in error_msg:
                        raise Exception(ErrorCode.GAUSS_535["GAUSS_53518"] % str(e))
                # loop 3 times, if still wrong, exit with error code.
                if i == 2:
                    raise Exception(ErrorCode.GAUSS_535["GAUSS_53512"] % str(e))
                # If error, continue loop.
                GaussLog.printMessage(ErrorCode.GAUSS_535["GAUSS_53518"] % str(e))
                continue
            # If scp success, exit loop.
            GaussLog.printMessage("Successfully dispatch package.")
            break
    except Exception as e:
        if dir_created:
            GDSUtils.exec_command_remote_parallelly(clean_install_dir_if_failed, install_hosts,
                                                        timeout=GDSUtils.TIMEOUT)
        GaussLog.exitWithError(str(e))


def create_common_user():
    """
    function: create common user, i.e. gds_user
    """
    global root_passwd
    global gds_user_passwd
    GaussLog.printMessage("Creating user [%s]." % gds_user)
    try:
        # get root password
        root_passwd = GDSUtils.get_user_password("root")
        # check the input password
        root_passwd = GDSUtils.two_more_chances_for_passwd(install_hosts, "root", root_passwd)

        # get gds_user password
        gds_user_passwd = GDSUtils.get_user_password("%s user [%s]" % (APP_NAME, gds_user))
        # check the input password
        while (gds_user_passwd == ""):
            gds_user_passwd = GDSUtils.get_user_password("%s user [%s]" % (APP_NAME, gds_user), "again")
    except Exception as e:
        if str(e).find("[GAUSS-") != -1:
            raise e
        raise Exception(ErrorCode.GAUSS_535["GAUSS_53514"] % str(e))

    try:
        exec_result = GDSUtils.exec_command_remote_parallelly(create_common_user_on_one_node,
                                                              install_hosts,
                                                              timeout=GDSUtils.TIMEOUT)
        check_exec_result(exec_result)
    except Exception as e:
        GaussLog.exitWithError("Failed to create user [%s] with error:\n%s" % (gds_user, str(e)))
    GaussLog.printMessage("Successfully created user [%s]." % gds_user)


def create_common_user_on_one_node(ip):
    """
    function:
        Connect to a node, then create common os user. Refer to PreInstallUtility.createOSUser.
    precondition:
        root's password is correct on each node
    postcondition:
        NA
    input: ip
    """
    client = GDSUtils.connect_paramiko_ssh_host(ip, "root", root_passwd)
    user_home_path = '/home/' + gds_user
    cmd = "id %s; echo $?; ls -ld %s; echo $?; getent group %s;" % (gds_user, user_home_path, gds_user_group)
    status, result = GDSUtils.paramiko_cmd_raw(client, cmd, get_pty=True)
    if not status:
        client.close()
        return {ip : ErrorCode.GAUSS_514["GAUSS_51400"] % cmd}
    result = [x.strip() for x in result.split('\n')]
    user_exist = (result[1] == "0")
    group_exist = (len(result) >= 5 and result[4])
    user_home_exist = (result[3] == "0")

    # user exist, then check if user is ok.
    if user_exist:
        # uid=1(user) gid=2(user_group) groups=16(dialout),33(video),100(users)
        exist_user_info = re.search(r'uid=(\d*).* gid=(\d*)\((.*)\) ', result[0])
        exist_user_group_name = exist_user_info.group(3)
        try:
            cmd = g_file.SHELL_CMD_DICT["checkPassword"] % (gds_user, "'^Password expires'")
            check_expire_status, check_expire = GDSUtils.paramiko_cmd_raw(client, cmd, get_pty=True)
            if not check_expire_status:
                raise Exception
        except Exception:
            return {ip : ErrorCode.GAUSS_514["GAUSS_51400"] % cmd}
        finally:
            client.close()
        expire_time_str = check_expire.split(':')[1].strip()
        expire_time_flag = True
        try:
            expire_time = time.strptime(expire_time_str, "%b %d, %Y")
        except Exception:
            expire_time_flag = False
        if expire_time_flag:
            local_time_string = time.strftime("%b %d, %Y")
            local_time = time.strptime(local_time_string, "%b %d, %Y")
            local_time_seconds = int(time.mktime(local_time))
            expire_seconds = int(time.mktime(expire_time))
            expire_time_flag = (expire_seconds < local_time_seconds)
            if expire_time_flag:
                return {ip: ErrorCode.GAUSS_503["GAUSS_50307"]}

        # user exists and input group not exists
        if not group_exist:
            return {ip: ErrorCode.GAUSS_503["GAUSS_50305"]}
        # user exists and group exists
        if exist_user_info.group(1) == 0:
            return {ip: "[GAUSS-50302] : The %s user cannot be a user with the root permission." % APP_NAME}
        if gds_user_group != exist_user_group_name:
            return {ip: ErrorCode.GAUSS_503["GAUSS_50305"]}
        return {ip: ''}

    # user not exist, then check and try to create it.
    if user_home_exist:
        user_home_type = result[2].split()[0][0]
        user_home_owner = result[2].split()[2]
        if user_home_owner != gds_user:
            client.close()
            return {ip : ErrorCode.GAUSS_503["GAUSS_50315"] % (gds_user, user_home_path) +
                " Please check if the path %s is already created by other users." % user_home_path}
        if user_home_type != 'd':
            client.close()
            return {ip : ErrorCode.GAUSS_502["GAUSS_50211"] % user_home_path}
    # user not exists and group exist
    if group_exist:
        cmd = "useradd -m -g %s %s" % (gds_user_group, gds_user)
    # user not exists and group not exist
    else:
        cmd = "groupadd %s && useradd -m -g %s %s" % (gds_user_group, gds_user_group, gds_user)
    cmd += " && echo '%s:%s' | chpasswd; id %s" % (gds_user, gds_user_passwd, gds_user)
    status, output = GDSUtils.paramiko_cmd_raw(client, cmd, get_pty=True)
    client.close()
    if status and output.startswith("uid="):
        return {ip: None}
    else:
        return {ip: ("User not exist." + output)}


def create_trust_for_common_user():
    """
    function:
        create SSH trust for common user
    input: NA
    output: NA
    """
    GaussLog.printMessage("Creating SSH trust for user [%s]." % gds_user)
    g_file.changeOwner(gds_user, install_tools_path, True)
    try:
        # firstly we check execution permission of gs_sshexkey for gds_user.
        create_trust_tool = "gs_sshexkey"
        cmd = "su - %s -c \'source %s;if [ ! -x $TEMP_GDS_INSTALL_HOME ];then echo Permission denied;fi; %s -V\'" % \
              (gds_user, temp_env_file, create_trust_tool)
        status, output = subprocess.getstatusoutput(cmd)
        if status != 0:
            if output.find("Permission denied") >= 0:
                raise Exception(ErrorCode.GAUSS_501["GAUSS_50101"] % (create_trust_tool, gds_user))
            raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " With output: " + output.strip())
        # create trust
        super_ssh_tool.createTrust(gds_user, gds_user_passwd, install_hosts, temp_env_file, logUuid=log_uuid)
    except Exception as e:
        GaussLog.exitWithError("Failed to create trust for common user with error:\n%s" % str(e))
    GaussLog.printMessage("Successfully created SSH trust for user [%s]." % gds_user)


def prepare_cron_service():
    """
    function: preparing CRON service
    input: NA
    output: NA
    """
    try:
        # Preparing CRON service
        local_path_of_pre_install_utility = os.path.join(install_dir, "script/local/PreInstallUtility.py")
        cmd = "%s -t %s -u %s -l %s --log-action=%s --log-uuid=%s" % (local_path_of_pre_install_utility,
                                                                      ACTION_PREPARE_USER_CRON_SERVICE,
                                                                      gds_user,
                                                                      install_log_path,
                                                                      install_tools_path,
                                                                      log_uuid)

        # an inner function
        def ssh_cmd_handler(_ip):
            return GDSUtils.exec_command_by_paramiko_on_one_node(_ip, cmd, "root", root_passwd)
        GDSUtils.exec_command_remote_parallelly(ssh_cmd_handler, install_hosts, timeout=GDSUtils.TIMEOUT)
    except Exception as e:
        GaussLog.exitWithError(str(e))
    GaussLog.printMessage("Successfully prepared CRON service.")


def set_install_env():
    """
    function: set environment variables
    input : NA
    output: NA
    """
    # clean temp files created by last installation
    remove_tmp_files()
    cmd = g_file.SHELL_CMD_DICT["createFile"] % (temp_env_file, DefaultValue.MAX_DIRECTORY_MODE, temp_env_file)
    (status, output) = subprocess.getstatusoutput(cmd)
    if (status != 0):
        GaussLog.exitWithError("Failed to create temp env file with output: %s" % output)

    #get the package path
    dirName = os.path.dirname(os.path.realpath(__file__))
    packageDir = os.path.join(dirName, "./../")
    packageDir = os.path.normpath(packageDir)
    try:
        # set mpprc file
        # set TEMP_GDS_INSTALL_HOME
        g_file.writeFile(temp_env_file, ["export TEMP_GDS_INSTALL_HOME=%s" % packageDir])
        # set PATH
        g_file.writeFile(temp_env_file, ["export PATH=$PATH:$TEMP_GDS_INSTALL_HOME/script/gspylib/pssh/bin:"
                                         "$TEMP_GDS_INSTALL_HOME/script"])
        # set LD_LIBRARY_PATH
        g_file.writeFile(temp_env_file, ["export LD_LIBRARY_PATH=$TEMP_GDS_INSTALL_HOME/lib:$LD_LIBRARY_PATH"])
        # set PYTHONPATH
        g_file.writeFile(temp_env_file, ["export PYTHONPATH=$TEMP_GDS_INSTALL_HOME/lib"])
    except Exception as e:
        GaussLog.exitWithError("Failed to set installation env with error: %s" % str(e))
    GaussLog.printMessage("Successfully set tool ENV.")


def set_user_profile_on_one_node(ip):
    """
    function: set user profile for execution, including:
                GDS_INSTALL_DIR
                PYTHONLIB (operating pc set twice, here is the second time, the first is in set_install_env)
                LD_LIBRARY_PATH
                PATH
    """
    # check if user profile exists
    user_profile = GDSUtils.EXEC_ENV_FILE
    env_profile = "\$%s/bin/%s_env" % (GDSUtils.ENV_NAME_GDS_INSTALL_DIR, APP_NAME)

    cmd = 'ls %s; (if [ $? -ne 0 ]; then touch %s; fi);' % (user_profile, user_profile)
    # delete old GDS_INSTALL_DIR, and set new
    cmd += 'sed -i "/^\\s*export\\s*%s=.*$/d" %s; echo "export %s=%s" >> %s;' % \
        (GDSUtils.ENV_NAME_GDS_INSTALL_DIR, user_profile, GDSUtils.ENV_NAME_GDS_INSTALL_DIR, install_dir, user_profile)
    # delete old environment PATH PYTHONPATH LD_LIBRARY_PATH, and set new
    cmd += 'sed -i "/^\\s*source\\s*%s$/d" %s; echo "source %s" >> %s;' % \
           (env_profile.replace('/', '\/'), user_profile, env_profile, user_profile)
    cmd += "cat %s" % user_profile
    cmd = "su - %s -c \'%s\'" % (gds_user, cmd)

    # exec by paramiko on node with ip
    return GDSUtils.exec_command_by_paramiko_on_one_node(ip, cmd, "root", root_passwd)


def set_exec_env():
    """
    function: set env for gds running, done by gds_user
    """
    GDSUtils.exec_command_remote_parallelly(set_user_profile_on_one_node, install_hosts, timeout=GDSUtils.TIMEOUT)
    GaussLog.printMessage("Successfully set execution env.")


def call_gds_check():
    """
    function: call gds_check to get all nodes status except nework.
    """
    GaussLog.printMessage("Start to do check first.")
    cmd = "%s/%s_check -t check " % (GDSUtils.WORK_PATH, APP_NAME)
    cmd += "--host " + ",".join(install_hosts)
    if ping_hosts:
        cmd += " --ping-host " + ",".join(ping_hosts)
    time_start = time.time()
    process = subprocess.Popen(shlex.split(cmd), stdin=subprocess.PIPE, stderr=sys.stderr, close_fds=True,
                               stdout=sys.stdout, universal_newlines=True, shell=False, bufsize=-1)
    pid = process.pid
    process.communicate()

    # read check result"
    CHECK_LOG = ""
    check_log_m = os.path.join(GDSUtils.WORK_PATH, GDSUtils.CHECK_LOG_FILE).replace('.log', '*.log')
    cmd = "grep %d %s -H| awk -F : '{print $1}' | xargs ls -t;" % (pid, check_log_m)
    status, output = subprocess.getstatusoutput(cmd)
    check_log_pattern = GDSUtils.CHECK_LOG_FILE.split('.')[0] + ".*\.log"
    if status == 0 and re.search(check_log_pattern, output):
        CHECK_LOG = (output.split()[0]).strip()
    else:
        GaussLog.exitWithError(ErrorCode.GAUSS_535['GAUSS_53515'])

    try:
        with open(CHECK_LOG) as f:
            all_log_file = f.readlines()
    except Exception:
        GaussLog.exitWithError(ErrorCode.GAUSS_535['GAUSS_53515'])
    check_result_line = ""
    pattern = r"\[Check_Process %d\]\[\d+\].*\[Install_Disallow_.*\]" % pid
    for line in reversed(all_log_file):
        res = re.search(pattern, line)
        if res:
            check_result_line = res.group()
            break
    if check_result_line:
        pattern2 = re.compile(r"\[Check_Process \d+]\[(\d+)].*\[(.*)]")
        time_check, install_disallow = re.search(pattern2, check_result_line).groups()
        if int(time_check) < time_start:
            GaussLog.exitWithError(ErrorCode.GAUSS_535['GAUSS_53515'])
        elif install_disallow == "Install_Disallow_True":
            GaussLog.exitWithError(ErrorCode.GAUSS_535['GAUSS_53516'])
        else:
            GaussLog.printMessage("Successfully check environment.")
    else:
        GaussLog.exitWithError(ErrorCode.GAUSS_535['GAUSS_53515'])


def remove_tmp_files():
    """
    function: remove temporary files during installation
    """
    cmd = g_file.SHELL_CMD_DICT["deleteFile"] % (temp_env_file, temp_env_file)
    cmd += ";" + g_file.SHELL_CMD_DICT["deleteBatchFiles"] % temp_super_sshtool_log[:-4]
    cmd += ";" + g_file.SHELL_CMD_DICT["deleteBatchFiles"] % temp_common_sshtool_log[:-4]
    (status, output) = subprocess.getstatusoutput(cmd)
    if status != 0:
        GaussLog.exitWithError("Failed to remove temp files with output: %s" % output)


def clean_resource():
    """
    function: clean_resource, dealloc resources, such as temp files and so on.
    """
    remove_tmp_files()
    GaussLog.printMessage("Successfully clean resources.")


if __name__ == '__main__':
    """
    main function
    """
    # check if user is root
    if os.getuid() != 0:
        GaussLog.exitWithError(ErrorCode.GAUSS_501["GAUSS_50104"])

    try:
        GDSUtils.load_gds_env()
        parse_command_line()
        check_parameters()
        call_gds_check()
        set_install_env()
        create_common_user()
        create_trust_for_common_user()
        dispatch_package()
        prepare_cron_service()
        set_exec_env()
        clean_resource()
        GaussLog.printMessage("\n============Successfully Installed============")
    except Exception as e:
        if str(e).find("[GAUSS-") != -1:
            GaussLog.exitWithError(str(e))
        GaussLog.exitWithError(ErrorCode.GAUSS_535["GAUSS_53514"] % str(e))
