#!/usr/bin/env python3
# -*- coding:utf-8 -*-
#############################################################################
# Copyright (c) 2020 Huawei Technologies Co.,Ltd.
#
# openGauss is licensed under Mulan PSL v2.
# You can use this software according to the terms
# and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#
#          http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
# ----------------------------------------------------------------------------
# Description  : gs_sshexkey is a utility to create SSH trust among nodes in
# a cluster.
#############################################################################

import sys
import warnings

warnings.simplefilter('ignore', DeprecationWarning)
sys.path.append(sys.path[0] + "/../lib")
import time
import os
import subprocess
import pwd
import grp
import socket
import getpass
import shutil
import secrets
import string
import platform
import gc
from gspylib.common.GaussLog import GaussLog
from gspylib.common.ErrorCode import ErrorCode
from gspylib.threads.parallelTool import parallelTool
from gspylib.common.Common import DefaultValue, ClusterCommand
from gspylib.common.ParameterParsecheck import Parameter
from base_utils.os.env_util import EnvUtil
from base_utils.os.file_util import FileUtil
from base_utils.os.grep_util import GrepUtil
from base_utils.os.password_util import PasswordUtil
from base_utils.os.net_util import NetUtil
from subprocess import PIPE
from base_utils.common.fast_popen import FastPopen
from gspylib.common.copy_python_lib import copy_lib
from base_utils.os.user_util import UserUtil

copy_lib()
DefaultValue.doConfigForParamiko()

SYSTEM_SSH_ENV = "export LD_LIBRARY_PATH=/usr/lib64"


try:
    import paramiko
except ImportError as ex:
    try:
        local_path = os.path.dirname(os.path.realpath(__file__))
        clib_path = os.path.realpath(os.path.join(local_path, "gspylib/clib/"))
        ld_path = os.getenv("LD_LIBRARY_PATH")
        if not ld_path or not ld_path.startswith(clib_path):
            if not ld_path:
                os.environ['LD_LIBRARY_PATH'] = clib_path
            else:
                os.environ['LD_LIBRARY_PATH'] = clib_path + ":" + ld_path
            try:
                os.execl(sys.executable, sys.executable, *sys.argv)
            except Exception as ex:
                sys.exit("Failed to set the enviroment variable: %s" % str(ex))
        import paramiko
    except ImportError as ex:
            raise Exception(ErrorCode.GAUSS_522["GAUSS_52200"] % str(ex))
from gspylib.threads.SshTool import SshTool

HOSTS_MAPPING_FLAG = "#Gauss OM IP Hosts Mapping"
ipHostInfo = ""
#the tmp path
tmp_files = ""
#tmp file name
TMP_TRUST_FILE = "step_preinstall_file.dat"


class PrintOnScreen():
    """
    class about print on screen
    """
    def __init__(self):
        '''
        function : Constructor
        input: NA
        output: NA
        '''
        pass

    def log(self, msg):
        '''
        function : print log
        input: msg: str
        output: NA
        '''
        print(msg)

    def debug(self, msg):
        '''
        function : debug
        input: msg: debug message string
        output: NA
        '''
        pass

    def error(self, msg):
        '''
        function : error
        input: msg: error message string
        output: NA
        '''
        pass

    def logExit(self, msg):
        '''
        function : print log and exit
        input: msg: str
        output: NA
        '''
        print(msg)
        sys.exit(1)


class GaussCreateTrust():
    """
    class about create trust for user
    """
    def __init__(self):
        '''
        function : Constructor
        input: NA
        output: NA
        '''
        self.logger = None
        self.hostFile = ""
        self.hostList = []
        self.passwd = []
        self.hosts_paswd_list = []
        self.logFile = ""
        self.localHost = ""
        self.flag = False
        self.localID = ""
        self.user = pwd.getpwuid(os.getuid()).pw_name
        self.group = grp.getgrgid(os.getgid()).gr_name
        self.incorrectPasswdInfo = ""
        self.failedToAppendInfo = ""
        self.homeDir = os.path.expanduser("~" + self.user)
        self.sshDir = "%s/.ssh" % self.homeDir
        self.authorized_keys_fname = DefaultValue.SSH_AUTHORIZED_KEYS
        self.known_hosts_fname = DefaultValue.SSH_KNOWN_HOSTS
        self.id_rsa_fname = DefaultValue.SSH_PRIVATE_KEY
        self.id_rsa_pub_fname = DefaultValue.SSH_PUBLIC_KEY
        self.skipHostnameSet = False
        self.isKeyboardPassword = False
        # init SshTool
        self.ssh_tool = None
        self.secret_word = ""
        self.correct_passwd_map = {}
        self.host_name_list = []

    def usage(self):
        """
gs_sshexkey is a utility to create SSH trust among nodes in a cluster.

Usage:
  gs_sshexkey -? | --help
  gs_sshexkey -V | --version
  gs_sshexkey -f HOSTFILE [--skip-hostname-set] [...] [-l LOGFILE]

General options:
  -f                          Host file containing the IP address of nodes.
  -l                          Path of log file.
      --skip-hostname-set     Whether to skip hostname setting. (The default value is set.)
  -?, --help                  Show help information for this utility,
                              and exit the command line mode.
  -V, --version               Show version information.
        """
        print(self.usage.__doc__)

    def parseCommandLine(self):
        """
        function: Check parameter from command line
        input : NA
        output: NA
        """
        paraObj = Parameter()
        paraDict = paraObj.ParameterCommandLine("sshexkey")
        if "helpFlag" in list(paraDict.keys()):
            self.usage()
            sys.exit(0)

        if "hostfile" in list(paraDict.keys()):
            self.hostFile = paraDict.get("hostfile")
        if "logFile" in list(paraDict.keys()):
            self.logFile = paraDict.get("logFile")
        if "skipHostnameSet" in list(paraDict.keys()):
            self.skipHostnameSet = paraDict.get("skipHostnameSet")

    def checkParameter(self):
        """
        function: Check parameter from command line
        input : NA
        output: NA
        """
        # check required parameters
        if self.hostFile == "":
            self.usage()
            GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % 'f' + ".")
        if not os.path.exists(self.hostFile):
            GaussLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50201"] % self.hostFile)
        if not os.path.isabs(self.hostFile):
            GaussLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50213"] % self.hostFile)

        #read host file to hostList
        self.readHostFile()    
        
        if not self.hostList:
            GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50004"] % 'f' +
                                   " It cannot be empty.")
       
        #check logfile  
        if self.logFile != "":
            if not os.path.isabs(self.logFile):
                GaussLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50213"] % self.logFile)

        if not self.passwd:
            self.passwd = self.getUserPasswd()
            self.isKeyboardPassword = True
    
    def readHostFile(self):
        """
        function: read host file to hostList
        input : NA
        output: NA
        """
        inValidIp = []
        try:
            with open(self.hostFile, "r") as f:
                for readLine in f:
                    hostname = readLine.strip().split("\n")[0]
                    if hostname != "" and hostname not in self.hostList:
                        if not NetUtil.isIpValid(hostname):
                            inValidIp.append(hostname)
                            continue
                        self.hostList.append(hostname)
            if len(inValidIp) > 0:
                GaussLog.exitWithError(ErrorCode.GAUSS_506["GAUSS_50603"]
                                       + "The IP list is:%s." % inValidIp)
        except Exception as e:
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50204"] % "host file"
                            + " Error: \n%s" % str(e))

    def getAllHostsName(self, ip):
        """
        function:
          Connect to all nodes ,then get all hostaname by threading
        precondition:
          1.User's password is correct on each node
        postcondition:
           NA
        input: ip
        output:Dictionary ipHostname,key is IP  and value is hostname
        hideninfo:NA
        """

        ipHostname = {}
        try:
            ssh = paramiko.Transport((ip, 22))
        except Exception as e:
            raise Exception(ErrorCode.GAUSS_512["GAUSS_51220"] % ip
                            + " Error: \n%s" % str(e))
        try:
            ssh.connect(username=self.user, password=self.passwd[0])
        except Exception as e:
            ssh.close()
            raise Exception(ErrorCode.GAUSS_503["GAUSS_50306"] % ip)

        check_channel = ssh.open_session()
        cmd = "cd"
        check_channel.exec_command(cmd)
        env_msg = check_channel.recv_stderr(9999).decode().strip()
        while True:
            channel_read = check_channel.recv(9999).decode().strip()
            if len(channel_read) != 0:
                env_msg += str(channel_read)
            else:
                break
        if env_msg != "":
            ipHostname["Node[%s]" % ip] = "Output: [" + env_msg \
                                          + " ] print by /etc/profile or" \
                                            " ~/.bashrc, please check it."
            ssh.close()
            return ipHostname

        channel = ssh.open_session()
        cmd = "hostname"
        channel.exec_command(cmd)
        hostname = channel.recv(9999).decode().strip()
        ipHostname[ip] = hostname
        ssh.close()
        return ipHostname

    def verifyPasswd(self, ssh, pswd=None):
        try:
            ssh.connect(username=self.user, password=pswd)
            return True
        except Exception:
            ssh.close()
            return False

    def parallelGetHosts(self, sshIps):
        parallelResult = {}
        ipHostname = parallelTool.parallelExecute(self.getAllHostsName, sshIps)

        err_msg = ""
        for i in ipHostname:
            for (key, value) in list(i.items()):
                if key.find("Node") >= 0:
                    err_msg += str(i)
                else:
                    parallelResult[key] = value
                    self.correct_passwd_map[key] = self.passwd[0]
        if len(err_msg) > 0:
            raise Exception(ErrorCode.GAUSS_518["GAUSS_51808"] % err_msg)
        return parallelResult

    def serialGetHosts(self, sshIps):
        serialResult = {}
        invalidIP = ""
        boolInvalidIp = False
        for sshIp in sshIps:
            isPasswdOK = False
            for pswd in self.passwd:
                try:
                    ssh = paramiko.Transport((sshIp, 22))
                except Exception as e:
                    self.logger.debug(str(e))
                    invalidIP += "Incorrect IP address: %s.\n" % sshIp
                    boolInvalidIp = True
                    break
                finally:
                    if ssh is not None:
                        ssh.close()

                isPasswdOK = self.verifyPasswd(ssh, pswd)
                if isPasswdOK:
                    self.hosts_paswd_list.append([sshIp, pswd])
                    self.correct_passwd_map[sshIp] = pswd
                    break

            if boolInvalidIp:
                boolInvalidIp = False
                continue

            if not isPasswdOK and self.isKeyboardPassword:
                GaussLog.printMessage("Please enter password for current user[%s] on the "
                                      "node[%s]." % (self.user, sshIp))
                # Try entering the password 3 times interactively
                for i in range(3):
                    try:
                        KeyboardPassword = getpass.getpass()
                        if not PasswordUtil.checkPasswordVaild(KeyboardPassword):
                            if i < 2:
                                GaussLog.printMessage("The password can only contain letters, numbers, and symbols, " \
                                                      "cannot start with a space, and cannot be empty.")
                                continue
                            else:
                                raise Exception("The password can only contain letters, numbers, and symbols, " \
                                                "cannot start with a space, and cannot be empty.")

                        ssh = paramiko.Transport((sshIp, 22))
                        isPasswdOK = self.verifyPasswd(ssh, KeyboardPassword)
                        if isPasswdOK:
                            self.passwd.append(KeyboardPassword)
                            self.hosts_paswd_list.append([sshIp, KeyboardPassword])
                            self.correct_passwd_map[sshIp] = KeyboardPassword
                            break
                        else:
                            if i < 2:
                                GaussLog.printMessage("The password is incorrect, please input again.")
                            continue
                    except Exception as e:
                        raise Exception(ErrorCode.GAUSS_512["GAUSS_51220"] % sshIp +
                                        " Error: \n%s" % str(e))
                    finally:
                        del KeyboardPassword
                        gc.collect()
            # if isKeyboardPassword is true, 3 times after the password is
            # also wrong to throw an unusual exit
            if not isPasswdOK:
                raise Exception(ErrorCode.GAUSS_503["GAUSS_50306"] % sshIp)

            cmd = "cd"
            check_channel = ssh.open_session()
            check_channel.exec_command(cmd)
            check_result = check_channel.recv_stderr(9999).decode()
            while True:
                channel_read = check_channel.recv(9999).decode()
                if len(channel_read) != 0:
                    check_result += str(channel_read)
                else:
                    break

            if check_result != "":
                raise Exception(ErrorCode.GAUSS_518["GAUSS_51808"] % check_result +
                                "Please check %s node /etc/profile or ~/.bashrc" % sshIp)
            else:
                cmd = "hostname"
                channel = ssh.open_session()
                channel.exec_command(cmd)
                while True:
                    hostname = channel.recv(9999).decode().strip()
                    if len(hostname) != 0:
                        serialResult[sshIp] = hostname
                    else:
                        break
                ssh.close()

        if invalidIP:
            raise Exception(ErrorCode.GAUSS_511["GAUSS_51101"] % invalidIP.rstrip("\n"))
        return serialResult

    def getAllHosts(self, sshIps):
        """
        function:
          Connect to all nodes ,then get all hostaname
        precondition:
          1.User's password is correct on each node
        postcondition:
           NA
        input: sshIps,username,passwd
        output:Dictionary ipHostname,key is IP  and value is hostname
        hideninfo:NA
        """
        if self.logFile != "":
            if not os.path.exists(tmp_files):
                self.logger.debug("Get hostnames for all nodes.", "addStep")
            else:
                self.logger.debug("Get hostnames for all nodes.")
        if len(self.passwd) == 0:
            self.isKeyboardPassword = True
            GaussLog.printMessage("Please enter password for current user[%s]." % self.user)
            passwd = getpass.getpass()
            self.passwd.append(passwd)
            del passwd
            gc.collect()

        if len(self.passwd) == 1:
            try:
                result = self.parallelGetHosts(sshIps)
            except Exception as e:
                if (self.isKeyboardPassword and str(e).startswith(
                        "[GAUSS-50306] : The password of")):
                    GaussLog.printMessage(
                        "Notice :The password of some nodes is incorrect.")
                    result = self.serialGetHosts(sshIps)
                else:
                    raise Exception(str(e))
        else:
            result = self.serialGetHosts(sshIps)
        if self.logFile != "":
            if not os.path.exists(tmp_files):
                self.logger.debug("Successfully get hostnames for all nodes.", "constant")
            else:
                self.logger.debug("Successfully get hostnames for all nodes.")
        return result

    def writeLocalHosts(self, result):
        """
        function:
         Write hostname and Ip into /etc/hosts when there's not the same one in /etc/hosts file 
        precondition:
          NA
        postcondition:
           NA
        input: Dictionary result,key is IP and value is hostname
        output: NA
        hideninfo:NA
        """
        self._debug("Write local hostname and Ip into /etc/hosts.", "addStep")
        hostIPInfo = ""
        if os.getuid() == 0:
            tmpHostIpName = "./tmp_hostsiphostname_%d" % os.getpid()
            # Check if /etc/hosts exists.
            if not os.path.exists("/etc/hosts"):
                raise Exception(ErrorCode.GAUSS_512["GAUSS_51221"] +
                                " Error: \nThe /etc/hosts does not exist.")
            (status, output) = GrepUtil.getGrepValue("-v", " #Gauss.* IP Hosts Mapping",
                                                     '/etc/hosts')
            result["::1"] = "localhost"
            result["127.0.0.1"] = "localhost"
            FileUtil.createFile(tmpHostIpName)
            FileUtil.changeMode(DefaultValue.KEY_FILE_MODE, tmpHostIpName)
            FileUtil.writeFile(tmpHostIpName, [output])
            shutil.copyfile(tmpHostIpName, '/etc/hosts')
            FileUtil.removeFile(tmpHostIpName)
            for (key, value) in list(result.items()):
                hostIPInfo += '%s  %s  %s\n' % (key, value, HOSTS_MAPPING_FLAG)
            hostIPInfo = hostIPInfo[:-1]
            ipInfoList = [hostIPInfo]
            FileUtil.writeFile("/etc/hosts", ipInfoList)
        self._debug("Successfully write local hostname and Ip into /etc/hosts.", "constant")

    def writeRemoteHostName(self, ip):
        """
        function:
         Write hostname and Ip into /etc/hosts when there's not the same one
         in /etc/hosts file by threading
        precondition:
          NA
        postcondition:
           NA
        input: ip
        output: NA
        hideninfo:NA
        """
        writeResult = []
        result = {}
        tmpHostIpName = "./tmp_hostsiphostname_%d_%s" % (os.getpid(), ip)
        username = pwd.getpwuid(os.getuid()).pw_name
        global ipHostInfo
        try:
            ssh = paramiko.Transport((ip, 22))
        except Exception as e:
            raise Exception(ErrorCode.GAUSS_511["GAUSS_51107"] + " Error: \n%s" % str(e))
        try:
            ssh.connect(username=username, password=self.correct_passwd_map[ip])
        except Exception as e:
            ssh.close()
            raise Exception(ErrorCode.GAUSS_503["GAUSS_50317"] + " Error: \n%s" % str(e))
        cmd = "grep -v '%s' %s > %s && cp %s %s && rm -rf %s" % (" #Gauss.* IP Hosts Mapping",
                                                                 '/etc/hosts', tmpHostIpName,
                                                                 tmpHostIpName, '/etc/hosts',
                                                                 tmpHostIpName)
        channel = ssh.open_session()
        channel.exec_command(cmd)
        ipHosts = channel.recv(9999).decode().strip()
        errInfo = channel.recv_stderr(9999).decode().strip()
        if(errInfo):
            writeResult.append(errInfo)
        else:
            if not ipHosts:
                cmd = "echo '%s' >> /etc/hosts" % (ipHostInfo)
                channel = ssh.open_session()
                channel.exec_command(cmd)
                errInfo = channel.recv_stderr(9999).decode().strip()
                if errInfo:
                    writeResult.append(errInfo)
        if channel:
            channel.close()
        result[ip] = writeResult
        if len(writeResult) > 0:
            return False, result
        else:
            return True, result

    def writeRemoteHosts(self, result):
        """
        function:
         Write hostname and Ip into /etc/hosts when there's not the same one
         in /etc/hosts file
        precondition:
          NA
        postcondition:
           NA
        input: Dictionary result,key is IP and value is hostname
                    rootPasswd
        output: NA
        hideninfo:NA
        """
        self._debug("Write remote hostname and Ip into /etc/hosts.", "addStep")
        global ipHostInfo
        ipHostInfo = ""
        if os.getuid() == 0:
            result1 = {}
            for (key, value) in list(result.items()):
                ipHostInfo += '%s  %s  %s\n' % (key, value, HOSTS_MAPPING_FLAG)
                if value not in (self.localHost, "localhost"):
                    if not value in list(result1.keys()):
                        result1[key] = value

            sshIps = list(result1.keys())
            ipHostInfo = ipHostInfo[:-1]
            if sshIps:
                ipRemoteHostname = parallelTool.parallelExecute(self.writeRemoteHostName, sshIps)
                errorMsg = ""
                for (key, value) in ipRemoteHostname:
                    if not key:
                        errorMsg = errorMsg + '\n' + str(value)
                if errorMsg != "":
                    raise Exception(ErrorCode.GAUSS_512["GAUSS_51221"] + " Error: %s" %
                                    errorMsg)
        self._debug("Successfully write remote hostname and Ip into /etc/hosts.", "constant")

    def initLogger(self):
        """
        function: Init logger
        input : NA
        output: NA
        """
        if self.logFile != "":
            self.logger = GaussLog(self.logFile, "gs_sshexkey")
        else:
            self.logger = PrintOnScreen()

    def checkNetworkInfo(self):
        """
        function: check  local node to other node Network Information
        input : NA
        output: NA
        """
        self._log("Checking network information.", "addStep")
        try:
            netWorkList = DefaultValue.checkIsPing(self.hostList)
            if not netWorkList:
                self.logger.log("All nodes in the network are Normal.")
            else:
                self.logger.logExit(ErrorCode.GAUSS_506["GAUSS_50600"] +
                                    "The IP list is:%s." % netWorkList)
        except Exception as e:
            self.logger.logExit(str(e))
        self._log("Successfully checked network information.", "constant")
    
    def check_current_user(self):
        """
        function: Check if the current user is root
        input : NA
        output: NA
        """
        user_info = UserUtil.getUserInfo()
        if user_info['uid'] != 0:
            self.skipHostnameSet = True
        

    def run(self):
        """
        function: Do create SSH trust
        input : NA
        output: NA
        """
        self.check_current_user()
        self.parseCommandLine()
        self.checkParameter()
        self.localHost = socket.gethostname()
        self.init_sshtool()
        self.initLogger()
        global tmp_files
        tmp_files = "/tmp/%s" % TMP_TRUST_FILE
        if self.logFile != "":
            if not os.path.exists(tmp_files):
                self.logger.debug("gs_sshexkey execution takes %s steps in total" %
                                  ClusterCommand.countTotalSteps("gs_sshexkey", "",
                                                                 self.skipHostnameSet))
        Ips = []
        Ips.extend(self.hostList)
        result = self.getAllHosts(Ips)
        self.checkNetworkInfo()

        if not self.skipHostnameSet:
            self.writeLocalHosts(result)
            self.writeRemoteHosts(result)
            self.write_hostname_to_list(result)

        self.logger.log("Creating SSH trust.")
        try:                      
            self.retry_create_public_private_keyfile()
            self.addLocalAuthorized()
            self.updateKnow_hostsFile(result)
            self.addRemoteAuthorization()
            self.determinePublicAuthorityFile()
            self.synchronizationLicenseFile(result)
            self.retry_register_other_ssh_agent()
            self.verifyTrust()
            self.set_user_crontab(result)
            self.logger.log("Successfully created SSH trust.")
        except Exception as e:
            self.logger.logExit(str(e))
        finally:
            self.passwd = []

    def set_user_crontab(self, hostnames_ips):
        if os.getuid() == 0:
            return
        hostnames = list(hostnames_ips.values())
        self.logger.log("Start set cron for %s" % self.user)
        package_path = os.path.dirname(os.path.realpath(__file__))
        gp_home = os.path.join(package_path, '../')
        check_cron = True
        try:
            # create cron tmp file
            cron_file = "/tmp/gauss_cron_%s" % self.user
            set_cron_cmd = "crontab -l > %s && " % cron_file
            set_cron_cmd += "sed -i '/CheckSshAgent.py/d' %s;" % cron_file
            set_cron_cmd += "echo '*/1 * * * * source ~/.bashrc;python3 %s/script/local/CheckSshAgent.py >>/dev/null 2>&1 &' >> %s" % \
                            (gp_home, cron_file)
            set_cron_cmd += "&& crontab %s" % cron_file
            set_cron_cmd += "&& rm -f '%s';" % cron_file
            self.logger.debug("Command for setting CRON: %s" % set_cron_cmd)
            ssh_tool = SshTool(hostnames)
            os.environ['GPHOME'] = gp_home
            ssh_tool.executeCommand(set_cron_cmd, DefaultValue.SUCCESS, '', '')
            ssh_tool.clenSshResultFiles()
        except Exception as e:
            check_cron = False
            self.logger.log("Warning: The %s user does not have permission for crontab." % self.user)
        if check_cron:
            self.logger.log("Successfully to set cron for %s" % self.user)

    def createPublicPrivateKeyFile(self):
        """
        function: create  local public private key file
        input : NA
        output: NA
        """
        if self.logFile != "" and not os.path.exists(tmp_files):
            self.logger.log("Creating the local key file.", "addStep")
        else:
            self.logger.log("Creating the local key file.")

        FileUtil.removeFile(self.id_rsa_fname)
        FileUtil.removeFile(self.id_rsa_pub_fname)
        secret_word = self.get_secret(32)
        self.secret_word = secret_word
        localDirPath = os.path.dirname(os.path.realpath(__file__))
        encrypt_shell_file = os.path.join(localDirPath, "./local/sshexkey_encrypt_tool.sh")
        cmd = "echo \"%s\" | /bin/sh %s %s %s %s" % (secret_word, encrypt_shell_file,
                                                     "sshkeygen", self.id_rsa_fname,
                                                     self.id_rsa_pub_fname)
        self.logger.debug("ssh-keygen cmd is:%s" % cmd)
        proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE)
        stdout, stderr = proc.communicate()
        output = stdout + stderr
        status = proc.returncode
        if status != 0:
            raise Exception(ErrorCode.GAUSS_511["GAUSS_51108"] + " Error:\n%s" % output)
        f = None
        try:
            try: 
                f = open(self.id_rsa_pub_fname, 'r') 
                return f.readline().strip()
            except IOError as e:
                self.logger.debug(str(e))
                raise Exception(ErrorCode.GAUSS_511["GAUSS_51108"] +
                                " Unable to read the generated file." + self.id_rsa_pub_fname)
        finally:
            if f:
                f.close()
            # register ssh agent for ssh passphrase
            self.encrypt_pass_phrase(secret_word)
            self.logger.debug("encrypt passphrase successfully.")
            mpprcfile = EnvUtil.getMpprcFile()
            DefaultValue.register_ssh_agent(mpprcfile, self.logger)

            #Mounting private keys to ssh-agent
            bashrc_file = os.path.join(pwd.getpwuid(os.getuid()).pw_dir,
                                       ".bashrc")
            localDirPath = os.path.dirname(os.path.realpath(__file__))
            shell_file = os.path.join(localDirPath, "./local/ssh-agent.sh")
            DefaultValue.add_ssh_id_rsa(secret_word, bashrc_file, shell_file, self.logger)
            self.logger.debug("Ssh agent register successfully.")
            self._log("Successfully created the local key files.", "constant")

    def addLocalAuthorized(self):
        """
        function: append the local id_rsa.pub value provided to authorized_keys
        input : NA
        output: NA
        """
        self._log("Appending local ID to authorized_keys.", "addStep")
        f = None
        try:
            FileUtil.createFileInSafeMode(self.authorized_keys_fname)
            f = open(self.authorized_keys_fname, 'a+')
            for line in f:
                if line.strip() == self.localID + " #OM":
                    # The localID is already in authorizedKeys; no need to add
                    return
            f.write(self.localID + " #OM")
            f.write('\n')
            self._log("Successfully appended local ID to authorized_keys.", "constant")
        finally:
            if f:
                f.close()
        FileUtil.changeMode(DefaultValue.KEY_FILE_MODE, self.authorized_keys_fname)

    def checkAuthentication(self, hostname):
        """
        function: Ensure the proper password-less access to the remote host.
        input : hostname
        output: True/False, hostname
        """
        bashrc_file = os.path.join(pwd.getpwuid(os.getuid()).pw_dir, ".bashrc")
        cmd = 'source %s;%s;/usr/bin/ssh -n %s %s true' % (bashrc_file, SYSTEM_SSH_ENV,
                                               DefaultValue.SSH_OPTION, hostname)
        (status, output) = subprocess.getstatusoutput(cmd)
        if status != 0:
            self.logger.debug("Failed to check authentication.cmd:%s Hostname:%s. Error: \n%s" %
                              (cmd, hostname, output))
            return False, hostname
        return True, hostname

    def updateKnow_hostsFile(self, result):
        """
        function: keyscan all hosts and update known_hosts file
        input : result
        output: NA
        """
        self._log("Updating the known_hosts file.", "addStep")
        hostnameList = []
        hostnameList.extend(self.hostList)
        for(key, value) in list(result.items()):
            hostnameList.append(value)
        for hostname in hostnameList:
            cmd = '%s;/usr/bin/ssh-keyscan -t ed25519 %s >> %s ' % (SYSTEM_SSH_ENV, hostname, self.known_hosts_fname)
            cmd += '&& sed -i "$ s/$/ #OM/" %s ' % self.known_hosts_fname
            cmd += "&& chmod %s %s" % (DefaultValue.KEY_FILE_MODE, self.known_hosts_fname)
            (status, output) = subprocess.getstatusoutput(cmd)
            if status != 0 or "Name or service not known".lower() in output.lower():
                raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error:\n%s" % output)
        (status, output) = self.checkAuthentication(self.localHost)
        if not status:
            raise Exception(ErrorCode.GAUSS_511["GAUSS_51100"] % self.localHost)
        self._log("Successfully updated the known_hosts file.", "constant")

    def tryParamikoConnect(self, hostname, client, pswd = None, silence = False):
        """
        function: try paramiko connect
        input : hostname, client, pswd, silence
        output: True/False
        """
        try:
            client.connect(hostname, password=pswd, allow_agent=False, look_for_keys=False)
            return True
        except paramiko.AuthenticationException as e:
            if not silence: 
                self.logger.debug("Incorrect password. Node: %s." % hostname +
                                  " Error:\n%s" % str(e))
            client.close()
            return False
        except Exception as e:
            if not silence: 
                self.logger.debug('[SSHException %s] %s' % (hostname, str(e)))
            client.close()
            raise Exception(str(e))

    def addRemoteAuthorization(self):
        """
        function: Send local ID to remote over SSH, and append to authorized_key
        input : NA
        output: NA
        """
        self._log("Appending authorized_key on the remote node.", "addStep")
        try:
            parallelTool.parallelExecute(self.sendRemoteAuthorization, self.hostList)
            if self.incorrectPasswdInfo != "":
                self.logger.logExit(ErrorCode.GAUSS_511["GAUSS_51101"] %
                                    (self.incorrectPasswdInfo.rstrip("\n")))
            if self.failedToAppendInfo != "":
                self.logger.logExit(ErrorCode.GAUSS_511["GAUSS_51101"] %
                                    (self.failedToAppendInfo.rstrip("\n")))
        except Exception as e:
            self.logger.logExit(ErrorCode.GAUSS_511["GAUSS_51111"] + " Error:%s." % str(e))
        self._log("Successfully appended authorized_key on all remote node.", "constant")

    def sendRemoteAuthorization(self, hostname): 
        """
        function: send remote authorization
        input : hostname
        output: NA
        """
        if hostname != self.localHost:
            p = None
            cin = cout = cerr = None
            try:
                #ssh Remote Connection other node
                p = paramiko.SSHClient()
                p.load_system_host_keys()               
                ok = self.tryParamikoConnect(hostname, p, self.correct_passwd_map[hostname], silence = True)
                if not ok:
                    self.incorrectPasswdInfo += "Without this node[%s] of the correct password.\n"\
                                                % hostname
                    return
                # Create .ssh directory and ensure content meets permission requirements 
                # for password-less SSH
                cmd = ('mkdir -p .ssh; ' +
                       "chown -R %s:%s %s; " % (self.user, self.group, self.sshDir) +
                       'chmod %s .ssh; ' % DefaultValue.KEY_DIRECTORY_MODE +
                       'touch .ssh/authorized_keys; ' +
                       'touch .ssh/known_hosts; ' +
                       'chmod %s .ssh/auth* .ssh/id* .ssh/known_hosts; ' %
                       DefaultValue.KEY_FILE_MODE)
                (cin, cout, cerr) = p.exec_command(cmd)
                cin.close()
                cout.close()
                cerr.close()

                # Append the ID to authorized_keys;
                cnt = 0
                cmd = 'echo \"%s #OM\" >> .ssh/authorized_keys && echo ok ok ok' % self.localID
                (cin, cout, cerr) = p.exec_command(cmd)
                cin.close()
                #readline will read other msg.
                line = cout.read().decode()
                while line.find("ok ok ok") < 0:
                    time.sleep(cnt * 2)
                    cmd = 'echo \"%s #OM\" >> .ssh/authorized_keys && echo ok ok ok' % self.localID
                    (cin, cout, cerr) = p.exec_command(cmd)
                    cin.close()
                    cnt += 1
                    line = cout.readline()
                    if cnt >= 3:
                        break
                    if line.find("ok ok ok") < 0:
                        continue
                    else:
                        break

                if line.find("ok ok ok") < 0:
                    self.failedToAppendInfo += "...send to %s\nFailed to append local ID to " \
                                               "authorized_keys on remote node %s.\n" % \
                                               (hostname, hostname)
                    return
                cout.close()
                cerr.close()
                self.logger.debug("Send to %s\nSuccessfully appended authorized_key on"
                                  " remote node %s." % (hostname, hostname))
            finally:
                if cin:
                    cin.close()
                if cout:
                    cout.close()
                if cerr:
                    cerr.close()
                if p:
                    p.close()

    def determinePublicAuthorityFile(self):
        '''
        function: determine common authentication file content
        input : NA
        output: NA
        '''
        self._log("Checking common authentication file content.", "addStep")
        # eliminate duplicates in known_hosts file
        try:
            tab = self.readKnownHosts()
            self.writeKnownHosts(tab)
        except IOError as e:
            self.logger.logExit(ErrorCode.GAUSS_502["GAUSS_50230"] % "known hosts file" +
                                " Error:\n%s" % str(e))
        
        # eliminate duplicates in authorized_keys file
        try:
            tab = self.readAuthorizedKeys()
            self.writeAuthorizedKeys(tab)
        except IOError as e:
            self.logger.logExit(ErrorCode.GAUSS_502["GAUSS_50230"] % "authorized keys file" +
                                " Error:\n%s" % str(e))
        self._log("Successfully checked common authentication content.", "constant")

    def addRemoteID(self, tab, line):
        """
        function: add remote node id
        input : tab, line
        output: True/False
        """
        key = line.strip().split()
        if line[0] == "#":
            return True
        elif len(key) != 4:
            tab[line] = line
        else:
            tab[key[2] + key[3]] = line

    def readAuthorizedKeys(self, tab=None, keysFile=None):
        """
        function: read authorized keys
        input : tab, keysFile
        output: tab
        """
        if not keysFile:
            keysFile = self.authorized_keys_fname
        if not tab:
            tab = {}
        with open(keysFile, 'r') as f:
            for line in f:
                self.addRemoteID(tab, line)
        return tab

    def writeAuthorizedKeys(self, tab, keysFile=None):
        """
        function: write authorized keys
        input : tab, keysFile
        output: True/False
        """
        if not keysFile:
            keysFile = self.authorized_keys_fname
        with open(keysFile, 'w') as f:
            for IDKey in tab:
                f.write(tab[IDKey])

    def addKnownHost(self, tab, line):
        """
        function: add known host
        input : tab, line
        output: True/False
        """
        key = line.strip().split()
        if line[0] == "#":
            return True
        elif len(key) != 4:
            tab[line] = line
        else:
            tab[key[0] + key[3]] = line

    def readKnownHosts(self, tab=None, hostsFile=None):
        """
        function: read known host
        input : tab, hostsFile
        output: tab
        """
        if not hostsFile:
            hostsFile = self.known_hosts_fname
        if not tab:
            tab = {}
        with open(hostsFile, 'r') as f:
            for line in f:
                self.addKnownHost(tab, line)
        return tab

    def writeKnownHosts(self, tab, hostsFile=None):
        """
        function: write known host
        input : tab, hostsFile
        output: NA
        """
        if not hostsFile:
            hostsFile = self.known_hosts_fname
        with open(hostsFile, 'w') as f:
            for key in tab:
                f.write(tab[key])

    def send_trust_file(self, hostname):
        '''
        function: Set or update the authentication files on  hostname
        input : hostname
        output: NA
        '''

        bashrc_file = os.path.join(pwd.getpwuid(os.getuid()).pw_dir, ".bashrc")
        cmd = 'source %s;%s;' % (bashrc_file, SYSTEM_SSH_ENV)
        hostIp = hostname
        if NetUtil.get_ip_version(hostname) == NetUtil.NET_IPV6:
            hostIp = f"[{hostname}]"
        cmd += ('/usr/bin/scp -q -o "BatchMode yes" -o "NumberOfPasswordPrompts 0" ' +
                '%s %s %s:.ssh/' % (self.id_rsa_fname, self.id_rsa_pub_fname, hostIp))
        cmd += ''' && temp_auth=$(grep '#OM' %s)''' \
               ''' && /usr/bin/ssh %s "sed -i '/#OM/d' %s; echo '${temp_auth}' >> %s"''' % (
                    self.authorized_keys_fname, hostname, self.authorized_keys_fname,
                    self.authorized_keys_fname)
        cmd += ''' && temp_auth=$(grep '#OM' %s)''' \
               ''' && /usr/bin/ssh %s "sed -i '/#OM/d' %s; echo '${temp_auth}' >> %s"''' % (
                    self.known_hosts_fname, hostname, self.known_hosts_fname,
                    self.known_hosts_fname)
        (status, output) = subprocess.getstatusoutput(cmd)
        return status, output, cmd

    def synchronizationLicenseFile(self, result):
        '''
        function: Distribution of documents through concurrent execution ThreadPool.
        input : NA
        output: NA
        '''
        self._log("Distributing SSH trust file to all node.", "addStep")
        local_ip = ""
        for ip in result:
            if result[ip] == self.localHost:
                local_ip = ip
                break
        try:
            for hostip in self.hostList:
                if hostip == local_ip:
                    continue

                max_try_times = 3
                status, output, cmd = self.send_trust_file(hostip)
                
                while status != 0 and max_try_times > 0:
                    self.logger.debug(f"send_trust_file failed, countdown {max_try_times}, retry again.")
                    self.logger.debug("errorinfo: hostip: %s, status: %d, output: %s, "
                                      % (hostip, status, output))
                    self.logger.debug("check os info: %s\n %s" % (
                        subprocess.getoutput(f"ls -la {self.homeDir} | grep .ssh"),
                        subprocess.getoutput(f"ls -la {self.sshDir}")
                    ))
                    time.sleep(10)
                    max_try_times -= 1
                    status, output, cmd = self.send_trust_file(hostip)
                
                if status != 0 and max_try_times == 0:
                    raise Exception(ErrorCode.GAUSS_502["GAUSS_50223"] %"the authentication"
                            + "cmd is %s; Node:%s. Error:\n %d, %s" % (cmd, hostip, status, output))
                
            self.logger.log("Distributing trust keys file to all node successfully.")
            # send protect file to remote
            parallelTool.parallelExecute(self.send_protect_file, self.hostList)
        except Exception as e:
            self.logger.logExit(str(e))
        self._log("Successfully distributed SSH trust file to all node.", "constant")

    def write_hostname_to_list(self, ip_hostname):
        """
        function: Add hostname to the list
        input : NA
        output: NA
        """
        for hostname in ip_hostname.values():
            self.host_name_list.append(hostname)

    def verify_trust_by_hostname(self):
        """
        function: Verify creating SSH trust is successful
        input : NA
        output: NA
        """
        self._log("Verifying SSH trust on all hosts by hostname.", "addStep")
        try:
            results = parallelTool.parallelExecute(self.checkAuthentication, self.host_name_list)
            hostnames = ""
            for (key, value) in results:
                if not key:
                    hostnames = hostnames + ',' + value
            if hostnames != "":
                raise Exception(ErrorCode.GAUSS_511["GAUSS_51100"] % hostnames.lstrip(','))
        except Exception as e:
            self.logger.logExit(str(e))
        self._log("Successfully verified SSH trust on all hosts by hostname.", "constant")

    def verify_trust_by_ip(self):
        """
        function: Verify creating SSH trust is successful
        input : NA
        output: NA
        """
        self._log("Verifying SSH trust on all hosts by ip.", "addStep")
        try:
            results = parallelTool.parallelExecute(self.checkAuthentication, self.hostList)
            ips = ""
            for (key, value) in results:
                if not key:
                    ips = ips + ',' + value
            if ips != "":
                raise Exception(ErrorCode.GAUSS_511["GAUSS_51100"] % ips.lstrip(','))
        except Exception as e:
            self.logger.logExit(str(e))
        self._log("Successfully verified SSH trust on all hosts by ip.", "constant")

    def verifyTrust(self):
        """
        function: Verify creating SSH trust is successful
        input : NA
        output: NA
        """
        self._log("Verifying SSH trust on all hosts.", "addStep")
        self.verify_trust_by_ip()
        if not self.skipHostnameSet:
            self.verify_trust_by_hostname()
        self._log("Successfully verified SSH trust on all hosts.", "constant")

    def getUserPasswd(self):
        """
        function: get user passwd from cache
        input: NA
        output: NA
        """
        user_passwd = []
        if sys.stdin.isatty():
            GaussLog.printMessage("Please enter password for current user[%s]." % self.user)
            user_passwd.append(getpass.getpass())
        else:
            user_passwd.append(sys.stdin.readline().strip('\n'))

        if not user_passwd:
            GaussLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50203"] % "Password")

        return user_passwd

    def send_protect_file(self, hostname):
        """
        function: Scp the protect files to hostname
        input : hostname
        output: NA
        """
        ipadds = DefaultValue.get_local_ips(NetUtil.get_ip_version(hostname))
        if (hostname == self.localHost or
                hostname in ipadds):
            return

        bashrc_file = os.path.join(pwd.getpwuid(os.getuid()).pw_dir, ".bashrc")
        tmp_path = os.path.expanduser("~/gaussdb_tmp/ssh_protect/")
        protect_path = os.path.expanduser("~/gaussdb_tmp/ssh_protect/*")
        local_path = os.path.dirname(os.path.realpath(__file__))
        pssh_path = os.path.realpath(os.path.join(local_path, "./gspylib/pssh/bin/pssh"))
        #Creating a Remote Directory
        create_cmd = "source ~/.bashrc && %s -s -H %s 'mkdir -p %s'" \
                     %(pssh_path, hostname, tmp_path)
        (status, output) = subprocess.getstatusoutput(create_cmd)
        self.logger.debug("Creating a Remote Directory:%s" % create_cmd)
        if status != 0:
            raise Exception(
                ErrorCode.GAUSS_502["GAUSS_50206"] % tmp_path
                + "cmd is %s; Node:%s. Error:\n%s" % (create_cmd, hostname, output))
        self.logger.debug("Creating a remote directory [%s] successfully on node "
                        "[%s]." %(tmp_path, hostname))
        # scp ssh_protect to remote node
        
        cmd = 'source %s;%s;/usr/bin/scp -q -r -2' % (bashrc_file, SYSTEM_SSH_ENV)
        cmd = '%s -o "BatchMode yes" -o ' % (cmd)
        cmd = '%s "NumberOfPasswordPrompts 0" %s' % (cmd, protect_path)
        cmd = '%s [%s]:%s' % (cmd, hostname, tmp_path)
        self.logger.debug("scp ssh_protect file cmd:%s" %cmd)
        (status, output) = subprocess.getstatusoutput(cmd)
        if status != 0:
            raise Exception(
                ErrorCode.GAUSS_502["GAUSS_50223"] % "the protect path"
                + "cmd is %s Node:%s. Error:\n%s" % (cmd, hostname, output))
        self.logger.debug("Send protect file successfully on node[%s]." % hostname)

    def get_secret(self, length=32):
        """
        function : random secret
        input : int
        output : string
        """
        types = string.ascii_letters + string.digits + string.punctuation
        while True:
            secret_word = ''.join(secrets.choice(types) for i in range(length))
            if (any(c.islower() for c in secret_word)
                    and any(c.isupper() for c in secret_word)
                    and any(c in string.punctuation for c in secret_word)
                    and sum(c.isdigit() for c in secret_word) >= 4):
                break
        illegal = ["`", "\"", "\'", "!", "}", "{", "[", "]", "-",
                   "\\", "!", "\n", "&", "$", "\n", "|", ";", "(", ")"]
        if secret_word and len(secret_word) == length:
            for word in secret_word:
                if word in illegal:
                    secret_word = secret_word.replace(word, "*")
            self.logger.debug("Generate secret word successfully.")
        else:
            self.logger.error("Generate secret word failed.")
            raise Exception(ErrorCode.GAUSS_511["GAUSS_51113"])
        return secret_word

    def encrypt_pass_phrase(self, secret_word):
        """
        function : encrypt passphrase
        input : secret word
        output : NA
        """
        ssh_protect_path = os.path.expanduser("~/gaussdb_tmp/ssh_protect")
        cipher_path = os.path.join(ssh_protect_path, "cipher")
        rand_path = os.path.join(ssh_protect_path, "rand")
        if not os.path.isdir(cipher_path) or not os.path.isdir(rand_path):
            FileUtil.createDirectory(cipher_path, True, DefaultValue.KEY_DIRECTORY_MODE)
            FileUtil.createDirectory(rand_path, True, DefaultValue.KEY_DIRECTORY_MODE)
            self.logger.debug("Create ssh_protect directory [%s] successfully." % ssh_protect_path)
        else:
            self.logger.debug("Exists ssh protect directory.")
        os_system_type = platform.machine()
        encrypt_dir_path = os.path.abspath(os.path.join(os.path.dirname(os.path.
                                                                        abspath(__file__)),
                                                        "gspylib",
                                                        "clib"))
        encrypt_path = os.path.join(encrypt_dir_path, "encrypt")
        if (not os.path.exists(encrypt_path)) :
            root = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')
            clib = os.path.join(root, "script/gspylib/clib")
            bin_files = ['./bin/encrypt']
            bin_cmd = 'tar -xpf `ls openGauss-Server*.tar.bz2`'
            cmd = 'cd {} && '.format(root)
            cmd += '{} {} && '.format(bin_cmd, ''.join(' '.join(bin_files)))
            cmd += '\mv {} {} && '.format(' '.join(bin_files), clib)
            cmd += 'cd {} && rm -rf bin'.format(root)
            status, output = subprocess.getstatusoutput(cmd)
            if status != 0:
                raise Exception("Failed to copy encrypt, error:%s." % output)
        cmd = " cd %s && ./encrypt '%s' %s %s" % (encrypt_dir_path, secret_word,
                                                  cipher_path, rand_path)
        if os_system_type.find("x86") != -1:
            self.logger.debug("[X86]:encrypt_user[%s]pwd_to_file" % self.user)
            cmd = "export LD_LIBRARY_PATH=%s && %s" % (encrypt_dir_path, cmd)
        else:
            self.logger.debug("[NON-X86]:encrypt_user[%s]pwd_to_file" % self.user)
        status, output = subprocess.getstatusoutput(cmd)
        if status != 0:
            raise Exception("Failed to encrypt secret words, error:%s." % output)
        change_file_list = []
        for main_dir, dirs, file_name in os.walk(ssh_protect_path):
            for f in file_name:
                change_file_list.append(os.path.join(main_dir, f))
        if change_file_list:
            cmd = "chmod 600 %s" % " ".join(change_file_list)
            proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE, preexec_fn=os.setsid)
            stdout, stderr = proc.communicate()
            if proc.returncode != 0:
                errmsg = "Failed to chmod user[%s]pwd file." % self.user
                self.logger.error("execute cmd:%s, error:%s" % (cmd, stderr))
                raise Exception("%s execute cmd:%s, error:%s" % (errmsg, cmd, stderr))
        self.logger.debug("Successfully to encrypt user[%s]pwd to file." % self.user)

    def retry_register_other_ssh_agent(self, retryTimes = 3, sleepTime = 2):
        """
        :param retryTimes:
        :param sleepTime:
        :return:
        """
        for retryTime in range(retryTimes):
            try:
                self.register_other_ssh_agent(self.user, self.hostList, self.passwd)
                break
            except Exception as err:
                self.logger.debug(
                    "Error: Failed to register other ssh-agent, "
                    "output is [%s] for %s times" % (str(err), str(retryTime)))
                if retryTime == retryTimes - 1:
                    if err:
                        self.logger.logExit("Error: Failed to register other ssh-agent,"
                                            "output is [%s]" % (str(err)))
                else:
                    time.sleep(sleepTime)

    def register_other_ssh_agent(self, user, ips, passwd):
        try:
            self.create_all_sessions(user, ips, passwd)
            bashrc_file = os.path.join(pwd.getpwuid(os.getuid()).pw_dir,
                                       ".bashrc")
            localDirPath = os.path.dirname(os.path.realpath(__file__))
            shell_file = os.path.join(localDirPath, "./local/ssh-agent.sh")
            for ip in ips:
                ipadds = DefaultValue.get_local_ips(NetUtil.get_ip_version(ip))
                if (ip == self.localHost or
                        ip in ipadds):
                    continue
                session = self.get_ssh_session(ip)
                DefaultValue.register_remote_ssh_agent(session, ip, self.logger)
                # Mounting private keys to ssh-agent
                self.copy_shell_to_remote_node(shell_file, ip)
                self.logger.debug("Copy shell file[%s] to rmote node [%s]successfully."
                                %(shell_file, ip))
                new_shell_file = os.path.join(self.sshDir, "./ssh-agent.sh")
                DefaultValue.add_remot_ssh_id_rsa(session, self.secret_word, bashrc_file,
                                                  new_shell_file, self.logger)
                delete_shell_cmd = "rm -rf %s" % new_shell_file
                (env_msg, channel_read) = DefaultValue.ssh_exec_cmd(
                    session, delete_shell_cmd)
                if env_msg:
                    self.logger.error("Failed to delete [%s] on node[%s]"
                                      %(new_shell_file, ip))
                self.logger.debug("Successfully to delete temp shell file [%s]"
                                % new_shell_file)
                self.logger.debug("Ssh agent register successfully.")
        except Exception as ex:
            self.close_all_session()
            raise Exception(str(ex))
        finally:
            self.close_all_session()

    def init_sshtool(self):
        """
        create ssh tool object
        :return:
        """
        self.ssh_tool = SshTool('')

    def get_ssh_session(self, remote_ip):
        """
        :param remote_ip:
        :return:
        """
        return self.ssh_tool.get_ssh_session(remote_ip)

    def create_all_sessions(self, user, all_ips, passwd):
        """
        :param all_ips:
        :return:
        """
        # the hosts have diffirent password.
        if len(self.hosts_paswd_list) == len(all_ips):
            for ip, pswd in self.hosts_paswd_list:
                self.ssh_tool.create_all_sessions(user, [ip], [pswd])
        else:
            self.ssh_tool.create_all_sessions(user, all_ips, passwd)

    def copy_shell_to_remote_node(self, shell_file, hostname):
        # scp ssh_protect to remote node

        if NetUtil.get_ip_version(hostname) == NetUtil.NET_IPV6:
            hostname = f"[{hostname}]"
        cmd = 'source ~/.bashrc;%s;' % SYSTEM_SSH_ENV
        cmd += ('/usr/bin/scp -q -o "BatchMode yes" -o "NumberOfPasswordPrompts 0" ' + '%s %s:.ssh/' % (
                shell_file, hostname))

        (status, output) = subprocess.getstatusoutput(cmd)
        if status != 0:
            raise Exception(
                ErrorCode.GAUSS_502["GAUSS_50214"] % "shell file to remote node;"
                + "cmd is %s; Node:%s. Error:\n%s" % (cmd, hostname, output))

    def close_all_session(self):
        """
        :return:
        """
        return self.ssh_tool.close_all_session()

    def retry_create_public_private_keyfile(self, retryTimes=3, sleepTime=2):
        for retryTime in range(retryTimes):
            try:
                self.localID = self.createPublicPrivateKeyFile()
                break
            except Exception as err:
                self.logger.debug(
                    "Error: Failed to create public private keyfile, "
                    "output is [%s] for %s times" % (str(err), str(retryTime)))
                if retryTime == retryTimes - 1:
                    if err:
                        self.logger.logExit("Error: Failed to create public private keyfile,"
                                            "output is [%s]" % (str(err)))
                else:
                    time.sleep(sleepTime)

    def _log(self, content, action):
        """
        inner log
        action: addStep, constant
        :return:
        """
        if self.logFile != "" and not os.path.exists(tmp_files):
            self.logger.log(content, action)
        else:
            self.logger.log(content)

    def _debug(self, content, action):
        """
        inner debug
        action: addStep, constant
        :return:
        """
        if self.logFile != "" and not os.path.exists(tmp_files):
            self.logger.debug(content, action)
        else:
            self.logger.debug(content)

if __name__ == '__main__':
    # main function
    createTrust = None
    try:
        createTrust = GaussCreateTrust()
        createTrust.run()
    except Exception as e:
        if str(e).startswith("[GAUSS-"):
            GaussLog.exitWithError(str(e))
        else:
            GaussLog.exitWithError("[GAUSS-50100]:"+str(e))

    sys.exit(0)
