#!/usr/bin/env python3
# -*- coding:utf-8 -*-
#############################################################################
# Copyright (c): 2012-2017, Huawei Tech. Co., Ltd.
# Description  : default value is a utility with a lot of default functions
#############################################################################

try:
    import os
    import platform
    import socket
    import sys
    import re
    import time
    import configparser
    import multiprocessing
    import _thread as thread
    import pwd
    import base64
    import struct
    import binascii
    import subprocess
    import string
    import secrets
    import math
    import fcntl
    import stat
    import time
    import copy

    localDirPath = os.path.dirname(os.path.realpath(__file__))
    sys.path.insert(0, localDirPath + "/../../../../lib")
    sys.path.append(localDirPath + "/../../../")
    from gspylib.common.DbClusterInfo import dbClusterInfo
    from gspylib.common.cluster_topology.parse_xml import ParseXml
    from gspylib.common.ErrorCode import ErrorCode
    from gspylib.os.platform import support_platform
    from gspylib.os.gsplatform import g_Platform, Platform
    from gspylib.os.gsfile import g_file
    from gspylib.os.gsOSlib import g_OSlib
    from gspylib.os.gsservice import g_service
    from gspylib.os.gsnetwork import g_network
    from gspylib.hardware.gsmemory import g_memory
    from gspylib.hardware.gsdisk import g_disk
    from gspylib.threads.parallelTool import parallelTool
    from gspylib.common.VersionInfo import VersionInfo
    from gspylib.common.AesCbcUtil import AesCbcUtil
except ImportError as ie:
    sys.exit("[GAUSS-52200] : Unable to import module: %s." % str(ie))

noPassIPs = []
g_lock = thread.allocate_lock()
parse_xml = ParseXml()


class DefaultValue():
    """
    Default value of some variables
    """

    def __init__(self):
        pass

    ###########################
    # DWS path info
    ###########################
    DWS_IMAGE_PATH = "/opt/dws/image"
    DWS_PACKAGE_PATH = "/opt/dws/package"
    DWS_APP_PATH = "/opt/dws/app"

    # CM reload signal
    SIGNAL_RELOAD_PARA = 1
    SIGNAL_RELOAD_FILE = 9

    IO_INTENSIVE_ACTION_DICT = {'install': 'install',
                                'uninstall': 'uninstall',
                                'expand': 'expand'}
    ###########################
    # init action timeout value
    ###########################
    # start timeout value
    TIMEOUT_CLUSTER_START = 300
    # restart nodegroup timeout value
    TIMEOUT_NODEGROUP_RESTART = 1800
    # stop timeout value
    TIMEOUT_CLUSTER_STOP = 300
    # failover timeout value
    TIMEOUT_CLUSTER_FAILOVER = 1800
    # syc timeout value
    TIMEOUT_CLUSTER_SYNC = 1800
    # switch reset timeout value
    TIMEOUT_CLUSTER_SWITCHRESET = 300

    ###########################
    # init pssh timeout value
    ###########################
    # preinstall timeoutvalue
    TIMEOUT_PSSH_PREINSTALL = 1800
    # install timeout value
    TIMEOUT_PSSH_INSTALL = 1800
    # uninstall timeout value
    TIMEOUT_PSSH_UNINSTALL = 43200
    # postpreinstall timeout value
    TIMEOUT_PSSH_POSTPREINSTALL = 1800
    # binary-upgrade timeout value
    TIMEOUT_PSSH_BINARY_UPGRADE = 14400
    # inplace-upgrade timeout value
    TIMEOUT_PSSH_INPLACE_UPGRADE = 14400
    # expand timeout value
    TIMEOUT_PSSH_EXPAND = 43200
    # replace timeout value
    TIMEOUT_PSSH_REPLACE = 86400
    # check timeout value
    TIMEOUT_PSSH_CHECK = 1800
    # backup timeout value
    TIMEOUT_PSSH_BACKUP = 1800
    # sshexkey timeout value
    TIMEOUT_PSSH_SSHEXKEY = 1800
    # collector timeout value
    TIMEOUT_PSSH_COLLECTOR = 1800
    # start etcd timeout value
    TIMEOUT_PSSH_STARTETCD = 600
    # delCN timeout value
    TIMEOUT_PSSH_DELCN = 1800
    # addCN timeout value
    TIMEOUT_PSSH_ADDCN = 86400
    # estimate timeout value
    TIMEOUT_PSSH_ESTIMATE = 1800
    # changeip timeout value
    TIMEOUT_PSSH_CHANGEIP = 1800
    # extension connector timeout value
    TIMEOUT_PSSH_EXTENSION = 1800
    # kill session timeout value
    TIMEOUT_PSSH_KILLSESSION = 1800
    # VC mode timeout value
    TIMEOUT_PSSH_VC = 43200
    # sql retry times
    RE_TIMES = 10

    ###########################
    # build timeout
    ###########################
    DEFAULT_TIMEOUT = 12 * 60 * 60  # 12 hours

    # gs_ctl timeout
    TIMEOUT_GS_CTL_START = 360
    TIMEOUT_GS_CTL_STOP = 360

    # instance build timeout value
    TIMEOUT_INSTANCE_BUILD = 86400

    ###########################
    # init authority parameter
    ###########################
    # directory mode
    DIRECTORY_MODE = 750
    # directory permission
    DIRECTORY_PERMISSION = 0o750
    MAX_DIRECTORY_PERMISSION = 0o755
    # file node
    FILE_MODE = 640
    KEY_DIRECTORY_PERMISSION = 0o700
    KEY_FILE_MODE = 600
    MIN_FILE_MODE = 400
    SPE_FILE_MODE = 500
    KEY_FILE_PERMISSION = 0o600
    KEY_DIRECTORY_MODE = 700
    MAX_DIRECTORY_MODE = 755
    TMP_EXE_FILE_MODE = 0o700
    # the host file permission. Do not changed it.
    HOSTS_FILE = 644

    # The available size of install app directory
    APP_DISK_SIZE = 100
    # The remaining space of device
    INSTANCE_DISK_SIZE = 200
    # lock cluster time
    CLUSTER_LOCK_TIME = 43200
    # lock cluster time for waiting mode
    CLUSTER_LOCK_TIME_WAIT = 43200

    # the guc paramter max_wal_senders's max value
    MAX_WAL_SENDERS = 100
    # min comm_max_stream
    MIN_COMM_MAX_STREAM = 1024
    # max comm_max_stream
    MAX_COMM_MAX_STREAM = 60000
    # min dn max_connections
    MIN_COMM_MAX_CONNECTIONS = 5000

    # env parameter
    OS_BASHRC = "/etc/bashrc"
    MPPRC_FILE_ENV = "MPPDB_ENV_SEPARATE_PATH"
    MPPDB_TMP_PATH_ENV = "PGHOST"
    TOOL_PATH_ENV = "GPHOME"
    SUCCESS = "Success"
    FAILURE = "Failure"
    # tablespace version directory name
    # it is from gaussdb kernel code
    TABLESPACE_VERSION_DIRECTORY = "PG_9.2_201611171"
    # gauss log dir
    GAUSSDB_DIR = "/var/log/gaussdb"
    # default database name
    DEFAULT_DB_NAME = "postgres"
    # database size file
    DB_SIZE_FILE = "total_database_size"

    # current  directory path
    GURRENT_DIR_FILE = ""
    # om_monitor log directory
    OM_MONITOR_DIR_FILE = "../cm/om_monitor"
    # om_kerberos log directory
    OM_KERBEROS_DIR_FILE = "../cm/kerberos_monitor"
    # action log file name
    DEFAULT_LOG_FILE = "gaussdb.log"
    LOCAL_LOG_FILE = "gs_local.log"
    PREINSTALL_LOG_FILE = "gs_preinstall.log"
    DEPLOY_LOG_FILE = "gs_install.log"
    REPLACE_LOG_FILE = "gs_replace.log"
    UNINSTALL_LOG_FILE = "gs_uninstall.log"
    OM_LOG_FILE = "gs_om.log"
    UPGRADE_LOG_FILE = "gs_upgradectl.log"
    SHRINK_LOG_FILE = "gs_shrink.log"
    DILATAION_LOG_FILE = "gs_expand.log"
    UNPREINSTALL_LOG_FILE = "gs_postuninstall.log"
    GSROACH_LOG_FILE = "gaussdb_roach.log"
    MANAGE_CN_LOG_FILE = "gs_om.log"
    GS_CHECK_LOG_FILE = "gs_check.log"
    GS_CHECKPERF_LOG_FILE = "gs_checkperf.log"
    GS_BACKUP_LOG_FILE = "gs_backup.log"
    GS_COLLECTOR_LOG_FILE = "gs_collector.log"
    GAUSS_REPLACE_LOG_FILE = "GaussReplace.log"
    GAUSS_OM_LOG_FILE = "GaussOM.log"
    TPCDS_INSTALL_LOG_FILE = "tpcd_install.log"
    LCCTL_LOG_FILE = "gs_lcctl.log"
    RESIZE_LOG_FILE = "gs_resize.log"
    HOTPATCH_LOG_FILE = "gs_hotpatch.log"
    SYNCDATA_LOG_CILE = "gs_syncdata.log"

    COO_CONNECTION_FILE = "gauss_connection.info"
    # cluster lock file
    CLUSTER_LOCK_PID = "gauss_cluster_lock.pid"
    # default cluster config xml
    CLUSTER_CONFIG_PATH = "/opt/huawei/wisequery/clusterconfig.xml"
    # default alarm tools
    ALARM_COMPONENT_PATH = "/opt/huawei/snas/bin/snas_cm_cmd"
    # GPHOME
    CLUSTER_TOOL_PATH = "/opt/huawei/wisequery"
    # tmptoken file
    TMP_TOKEN_FILE = "/DWS/manager/tmptoken"
    # package backup file name
    PACKAGE_BACK_NAME = "%s-Package-bak.tar.gz" % VersionInfo.PRODUCT_NAME_PACKAGE
    # package bak file name list
    PACKAGE_BACK_LIST = ["Gauss200-OLAP-Package-bak.tar.gz", "Gauss200-Package-bak.tar.gz",
                         "GaussDB-Kernel-Package-bak.tar.gz"]
    # network scripts file for RHEL
    REDHAT_NETWORK_PATH = "/etc/sysconfig/network-scripts"
    # cert files list,the order of these files SHOULD NOT be modified
    CERT_FILES_LIST = ["cacert.pem",
                       "server.crt",
                       "server.key",
                       "server.key.cipher",
                       "server.key.rand",
                       "sslcrl-file.crl"]
    SSL_CRL_FILE = CERT_FILES_LIST[5]
    CERT_ROLLBACK_LIST = ["cacert.pem",
                          "server.crt",
                          "server.key",
                          "server.key.cipher",
                          "server.key.rand",
                          "sslcrl-file.crl",
                          "gsql_cert_backup.tar.gz",
                          "certFlag"]
    CLIENT_CERT_LIST = ["client.crt",
                        "client.key",
                        "client.key.cipher",
                        "client.key.rand"]
    GDS_CERT_LIST = ["cacert.pem",
                     "server.crt",
                     "server.key",
                     "server.key.cipher",
                     "server.key.rand",
                     "client.crt",
                     "client.key",
                     "client.key.cipher",
                     "client.key.rand"]
    GRPC_CERT_LIST = ["client.crt",
                      "client.key",
                      "client.key.cipher",
                      "client.key.rand",
                      "cacert.pem",
                      "server.crt",
                      "server.key",
                      "server.key.cipher",
                      "server.key.rand",
                      "openssl.cnf"]
    GRPC_GENERAL_LIST = ["cacert.pem",
                         "openssl.cnf",
                         "server.crt",
                         "server.key",
                         "server.key.cipher",
                         "server.key.rand"]
    CERT_BACKUP_FILE = "gsql_cert_backup.tar.gz"
    PATH_CHECK_LIST = ["|", ";", "&", "$", "<", ">", "`", "\\", "'", "\"", "{", "}", "(", ")", "[", "]", "~", "*", "?",
                       " ", "!", "\n"]
    PASSWORD_CHECK_LIST = [";", "'", "$"]
    CONFIG_FILE_TYPE = "\.properties$|\.ini$|\.xml$|\.yaml$|\.yml$|\.json$|\.toml$|\.hocon$|\.conf$|" \
                       "\.config$|\.cnf$|\.cfg$|\.service$"
    CERTIFICATE_FILE_TYPE = "\.rand$|\.cipher$|\.key$|\.crt$|\.pem$"
    RUBY = "Ruby"
    INPLACE_UPGRADE_SQL_GZ = "inplace_upgrade_sql.tar.gz"
    INPLACE_UPGRADE_SQL_SHA256 = "inplace_upgrade_sql.sha256"
    # The xml file path is needed by kerberos in FI_librA
    # FI_KRB_XML is used in mppdb
    FI_KRB_XML = "auth_config/mppdb-site.xml"
    # FI_ELK_KRB_XML is used in elk
    FI_ELK_KRB_XML = "auth_config/elk-krb-site.xml"
    FI_KRB_CONF = "krb5.conf"
    ###########################
    # instance role
    ###########################
    # init value
    INSTANCE_ROLE_UNDEFINED = -1
    # cm_server
    INSTANCE_ROLE_CMSERVER = 0
    # gtm
    INSTANCE_ROLE_GTM = 1
    # etcd
    INSTANCE_ROLE_ETCD = 2
    # cn
    INSTANCE_ROLE_COODINATOR = 3
    # dn
    INSTANCE_ROLE_DATANODE = 4
    # cm_agent
    INSTANCE_ROLE_CMAGENT = 5

    ###########################
    # instance type. only for CN/DN
    ###########################
    # master
    MASTER_INSTANCE = 0
    # standby
    STANDBY_INSTANCE = 1
    # dummy standby
    DUMMY_STANDBY_INSTANCE = 2

    ###########################
    # parallel number
    ###########################
    DEFAULT_PARALLEL_NUM = 12
    DEFAULT_PARALLEL_NUM_UPGRADE = 6

    DEFAULT_BITS_NUM = 3072
    # SQL LOCK TIMEOUT
    OM_CONF = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "/../../etc/conf/om.conf")
    # SQL_EXEC_COMMAND
    SQL_EXEC_COMMAND_WITHOUT_USER = "%s -p %s -d %s "
    SQL_EXEC_COMMAND_WITH_USER = "%s -p %s -d %s -U %s -W %s "
    SQL_EXEC_COMMAND_WITHOUT_USER_FOR_UPGRADE = "%s postgresql://:%s/%s?application_name=%s "
    # Lock Sql Command
    CHECK_LOCK_SQL = "select count(1) from pg_catalog.pg_stat_activity where " \
                     "instr(query, 'pgxc_lock_for_backup()') > 0 or instr(query, 'pg_advisory_lock(65535,65535)') > 0;"

    # cluster type
    CLUSTER_TYPE_SINGLE = "single"
    CLUSTER_TYPE_MASTER_STANDBY = 'master-standby'
    CLUSTER_TYPE_SINGLE_PRIMARY_MULTI_STANDBY = "single-primary-multi-standby"
    CLUSTER_TYPE_SINGLE_INST = "single-inst"
    CLUSTER_TYPE_MASTER_STANDBY_MULTI_AZ = 'master-standby-multi-az'

    # ssh option
    SSH_OPTION = " -o BatchMode=yes -o TCPKeepAlive=yes -o ServerAliveInterval=30 -o ServerAliveCountMax=10 " \
                 "-o ConnectTimeout=30 -o ConnectionAttempts=10 "
    # base64 option
    BASE_ENCODE = "encode"
    BASE_DECODE = "decode"

    # Adapt to 200 and 300
    PRODUCT_VERSION_GAUSS200 = "GaussDB200"
    PRODUCT_VERSION_GAUSS300 = "GaussDB300"
    PRODUCT_VERSION_GAUSS200_APPLIANCE = "GaussDB200_Appliance"
    DEFAULT_PRODUCT_VERSION = PRODUCT_VERSION_GAUSS200
    PRODUCT_LICENSE_DWS = "dws"
    PRODUCT_LICENSE_STREAM = "stream"
    PRODUCT_LICENSE_HYBRID = "hybrid"
    PRODUCT_LICENSE_DWS_ESL = "dws.esl"
    PRODUCT_LICENSE_STREAM_ESL = "stream.esl"
    PRODUCT_LICENSE_HYBRID_ESL = "hybrid.esl"
    LICENSE_LIST = [PRODUCT_VERSION_GAUSS200.lower(),
                    PRODUCT_VERSION_GAUSS300.lower(),
                    PRODUCT_LICENSE_DWS.lower(),
                    PRODUCT_LICENSE_STREAM.lower(),
                    PRODUCT_LICENSE_HYBRID.lower(),
                    PRODUCT_LICENSE_DWS_ESL.lower(),
                    PRODUCT_LICENSE_STREAM_ESL.lower(),
                    PRODUCT_LICENSE_HYBRID_ESL.lower()]
    # Default name of the byte stream file which contain the disabled features.
    DEFAULT_DISABLED_FEATURE_FILE_NAME = "gaussdb.version"
    # Default license control file name.
    DEFAULT_LICENSE_FILE_NAME = "gaussdb.license"
    # Support license control product list.
    LICENSE_SUPPORT_LIST = [PRODUCT_VERSION_GAUSS200]
    # Default product version flag map.
    PRODUCT_VERSION_MAP = {
        2: PRODUCT_VERSION_GAUSS200,
        3: PRODUCT_VERSION_GAUSS300,
    }

    # Default retry times of SQL query attempts after successful operation "gs_ctl start".
    DEFAULT_RETRY_TIMES_GS_CTL = 150

    # Cert type
    GRPC_CA = "grpc"

    # because the number is float, so notice the recision
    DELTA_NUM = 0.000001

    KILL_SESSION = "select pg_terminate_backend(pid) from pg_stat_activity " \
                   "where state in ('active', 'fastpath function call', 'retrying') " \
                   "and query not like '%terminate%' " \
                   "and application_name not in('JobScheduler','WorkloadMonitor'," \
                   "'workload','WLMArbiter','cm_agent', 'CalculateSpaceInfo');"
    QUERY_SESSION = "select pid from pg_stat_activity " \
                    "where state in ('active', 'fastpath function call', 'retrying') " \
                    "and query not like '%terminate%' " \
                    "and application_name not in('JobScheduler','WorkloadMonitor'," \
                    "'workload','WLMArbiter','cm_agent', 'CalculateSpaceInfo');"

    DUMMY_DN_GUC = {"max_connections": "100",
                    "shared_buffers": "32MB",
                    "bulk_write_ring_size": "32MB",
                    "max_prepared_transactions": "10",
                    "cstore_buffers": "16MB",
                    "autovacuum_max_workers": "0",
                    "autovacuum_max_workers_hstore": "0",
                    "max_pool_size": "50",
                    "wal_buffers": "-1",
                    "max_locks_per_transaction": "64",
                    "sysadmin_reserved_connections": "3",
                    "max_wal_senders": "4"
                    }
    DWS_BIGDATA_JVM_METASPACE = 256  # unit M
    DWS_BIGDATA_JVM_CODECACHE = 256  # unit M

    # version of datastorage_threshold_check_interval default value changed
    CM_DATASTORAGE_THRESHOLD_CHECK_INTERVAL_CHANGED_VERSION = 91902
    # datastorage_threshold_check_interval default value before version 91902(not include 91902)
    CM_DATASTORAGE_THRESHOLD_CHECK_INTERVAL_OLD_DEFAULT = 600
    # datastorage_threshold_check_interval default value after 91902(include 91902)
    CM_DATASTORAGE_THRESHOLD_CHECK_INTERVAL_NEW_DEFAULT = 120

    # version of general_task_check_interval default value changed
    CM_GENERAL_TASK_CHECK_INTERVAL_CHANGED_VERSION = 91916
    # general_task_check_interval default value before version 91916(not include 91916)
    CM_GENERAL_TASK_CHECK_INTERVAL_OLD_DEFAULT = 3600
    # general_task_check_interval default value after 91902(include 91902)
    CM_GENERAL_TASK_CHECK_INTERVAL_NEW_DEFAULT = 60

    # version of log compress params default value changed
    CM_LOG_COMPRESS_PARAMS_CHANGED_VERSION = 96103
    # log_threshold_check_interval default value before version 96103(not include 96103)
    CM_LOG_COMPRESS_CHECK_INTERVAL_OLD_DEFAULT = 1800
    # log_threshold_check_interval default value after 96103(include 96103)
    CM_LOG_COMPRESS_CHECK_INTERVAL_NEW_DEFAULT = 300
    # log_max_size default value before version 96103(not include 96103)
    CM_LOG_MAX_SIZE_OLD_DEFAULT = 1024
    # log_max_size default value after 96103(include 96103)
    CM_LOG_MAX_SIZE_NEW_DEFAULT = 10240

    # Online expansion incremental build completion flag file
    INCREMENT_BUILD_FLAG_FILE = "increment_build.flag"
    # Online expansion after incremental build handle metadate completion flag file
    HANDLE_METADATA_FLAG_FILE = "handle_metadata.flag"
    # freeze/unfreeze disk cache for redistribute
    FREEZE_DISK_CACHE = "freeze"
    UNFREEZE_DISK_CACHE = "unfreeze"

    @staticmethod
    def encodeParaline(cmd, keyword):
        """
        """
        if keyword == "encode":
            cmd = base64.b64encode(cmd.encode()).decode()
            return cmd
        if keyword == "decode":
            cmd = base64.b64decode(cmd.encode()).decode()
            return cmd
        return ""

    @staticmethod
    def checkBondMode(bondingConfFile, isCheckOS=True):
        """
        function : Check Bond mode
        input  : String, bool
        output : List
        """
        netNameList = []

        cmd = "grep -w 'Bonding Mode' %s | awk  -F ':' '{print $NF}'" % bondingConfFile
        (status, output) = subprocess.getstatusoutput(cmd)
        if (status != 0 or output.strip() == ""):
            raise Exception(ErrorCode.GAUSS_506["GAUSS_50611"] + " Error: \n%s" % output)

        if (isCheckOS):
            print("BondMode %s" % output.strip())

        cmd = "grep -w 'Slave Interface' %s | awk  -F ':' '{print $NF}'" % bondingConfFile
        (status, output) = subprocess.getstatusoutput(cmd)
        if (status != 0):
            raise Exception(ErrorCode.GAUSS_506["GAUSS_50611"] + " Error: \n%s" % output)
        for networkname in output.split('\n'):
            netNameList.append(networkname.strip())
        return netNameList

    @staticmethod
    def CheckNetWorkBonding(serviceIP, isCheckOS=True):
        """
        function : Check NetWork ConfFile
        input  : String, bool
        output : List
        """
        networkCardNum = DefaultValue.getNICNum(serviceIP)
        vlan_conf_file = "/proc/net/vlan/%s" % networkCardNum
        if os.path.exists(vlan_conf_file):
            # its vlan if the vlan_conf_file exists.
            # get bond card number from vlan config file
            cmd = "grep 'Device' %s | awk -F ':' '{print $2}'" % vlan_conf_file
            (status, output) = subprocess.getstatusoutput(cmd)
            if status == 0 and output.strip() != "":
                networkCardNum = output.strip()
        NetWorkConfFile = DefaultValue.getNetWorkConfFile(networkCardNum)
        bondingConfFile = "/proc/net/bonding/%s" % networkCardNum
        networkCardNumList = []
        networkCardNumList.append(networkCardNum)
        cmd = "grep -i 'BONDING_OPTS\|BONDING_MODULE_OPTS' %s" % NetWorkConfFile
        (status, output) = subprocess.getstatusoutput(cmd)
        if ((status == 0) and (output.strip() != "")):
            if ((output.find("mode") > 0) and os.path.exists(bondingConfFile)):
                networkCardNumList = networkCardNumList + DefaultValue.checkBondMode(bondingConfFile, isCheckOS)
            else:
                raise Exception(ErrorCode.GAUSS_506["GAUSS_50611"])
        elif isCheckOS:
            print("BondMode Null")
        if (len(networkCardNumList) != 1):
            del networkCardNumList[0]
        return networkCardNumList

    @staticmethod
    def checkNetWorkMTU(nodeIp, isCheckOS=True):
        """
        function: gs_check check NetWork card MTU parameters
        input: string, string
        output: int
        """
        try:
            import psutil
            networkCardNum = DefaultValue.CheckNetWorkBonding(nodeIp, isCheckOS)
            mtuValue = psutil.net_if_stats()[networkCardNum[0]].mtu
            if (not mtuValue):
                return "        Abnormal reason: Failed to obtain network card MTU value."
            return mtuValue
        except Exception as e:
            return "        Abnormal reason: Failed to obtain the networkCard parameter [MTU]. " \
                   "Error: \n        %s" % str(e)

    @staticmethod
    def getNetWorkConfFile(networkCardNum):
        """
        function : Get NetWork ConfFile
        input  : int
        output : String
        """
        SuSENetWorkConfPath = "/etc/sysconfig/network"
        RedHatNetWorkConfPath = "/etc/sysconfig/network-scripts"
        gs_platform = Platform()
        distname, _, _ = gs_platform.dist()
        distname = distname.lower()
        if distname == support_platform.SUSE:
            NetWorkConfFile = "%s/ifcfg-%s" % (SuSENetWorkConfPath, networkCardNum)
        else:
            NetWorkConfFile = "%s/ifcfg-%s" % (RedHatNetWorkConfPath, networkCardNum)

        if (not os.path.exists(NetWorkConfFile)):
            if distname == support_platform.SUSE:
                cmd = "find %s -iname 'ifcfg-*-%s' -print" % (SuSENetWorkConfPath, networkCardNum)
            else:
                cmd = "find %s -iname 'ifcfg-*-%s' -print" % (RedHatNetWorkConfPath, networkCardNum)
            (status, output) = subprocess.getstatusoutput(cmd)
            if (status != 0):
                raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd)
            if output.strip() == "" or len(output.split('\n')) != 1:
                NetWorkConfFile = os.path.join(os.path.dirname(NetWorkConfFile), "ifcfg-lo")
            else:
                NetWorkConfFile = output.strip()

        return NetWorkConfFile

    @staticmethod
    def getNICNum(ipAddress):
        """
        function: Obtain network interface card number by psutil module
        input: ipAddress
        output: netWorkNum
        """
        try:
            import psutil
            netWorkNum = ""
            netWorkInfo = psutil.net_if_addrs()
            for num in netWorkInfo.keys():
                for netInfo in netWorkInfo[num]:
                    if netInfo.family in [socket.AF_INET, socket.AF_INET6] and \
                            g_network.isSameIP(netInfo.address, ipAddress):
                        netWorkNum = num
                        break
            if netWorkNum == "":
                raise Exception(ErrorCode.GAUSS_506["GAUSS_50604"] % ipAddress)
            return netWorkNum
        except Exception as e:
            raise Exception(ErrorCode.GAUSS_506["GAUSS_50604"] % ipAddress + " Error: \n%s" % str(e))

    @staticmethod
    def getIpAddressList():
        """
        """
        # Obtain all Ips by psutil module
        try:
            ipAddressList = []
            allNetworkInfo = g_network.getAllNetworkInfo()
            for network in allNetworkInfo:
                ipStr = network.ipAddress
                if (ipStr != ""):
                    ipAddressList.append(ipStr.strip())
            if (len(ipAddressList) == 0):
                raise Exception(ErrorCode.GAUSS_506["GAUSS_50616"])
            return ipAddressList
        except Exception as e:
            raise Exception(ErrorCode.GAUSS_506["GAUSS_50616"] + " Error: \n%s" % str(e))

    @staticmethod
    def getIpByHostName(hostname=""):
        """
        function: get local host ip by the hostname
        input : hostname. If it is an empty string, then the current hostname will be used.
        output: hostIp
        """
        # get hostname
        if hostname is None or len(hostname) == 0:
            hostname = socket.gethostname()

        # get local host in /etc/hosts
        cmd = "grep -E \"^.*%s[ \\t]*#Gauss.* IP Hosts Mapping$\" /etc/hosts" % hostname
        (status, output) = subprocess.getstatusoutput(cmd)
        if (status == 0 and output != ""):
            hostIp = output.strip().split(' ')[0].strip()
            if DefaultValue.isIpValid(hostIp):
                return hostIp

        # get local host by os function
        rs = socket.getaddrinfo(hostname, None)
        # rs[0] means the firstly available protocol tuple
        # rs[0][4] gets the sockaddr(ip, xx,...) of first available protocol tuple.
        return rs[0][4][0]

    @staticmethod
    def GetPythonUCS():
        """
        function: get python unicode value. Using it to chose which Crypto we need.
                  1114111 is Crypto_UCS4
                  65535 is Crypto_UCS2
                  the value 0 is only grammar support.
        input: NA
        output: NA
        """
        if sys.maxunicode == 1114111:
            return 4
        elif sys.maxunicode == 65535:
            return 2
        else:
            return 0

    @staticmethod
    def checkPythonVersion():
        """
        function : Check system comes with Python version
        input : NA
        output: list
        """
        major, minor, patchlevel = platform.python_version_tuple()
        version = "%s.%s.%s" % (str(major), str(minor), str(patchlevel))
        if str(major) == '3':
            return True, version
        else:
            return False, version

    @staticmethod
    def getUserId(user):
        """
        function : get user id
        input : user
        output : user id
        """
        try:
            user_id = pwd.getpwnam(user).pw_uid
            return user_id
        except Exception as e:
            raise Exception(ErrorCode.GAUSS_503["GAUSS_50300"] % user + "Detail msg: %s" % str(e))

    @staticmethod
    def checkUser(user, strict=True):
        """
        function : Check if user exists and if is the right user
        input : String,boolean
        output : NA
        """
        # get group
        try:
            DefaultValue.getUserId(user)
        except Exception as e:
            raise Exception(str(e))

        # if not strict, skip
        if (not strict):
            return

        # get $GAUSS_ENV, and makesure the result is correct.
        mpprcFile = DefaultValue.getEnv(DefaultValue.MPPRC_FILE_ENV)
        if (mpprcFile != "" and mpprcFile is not None):
            gaussEnv = DefaultValue.getEnvironmentParameterValue("GAUSS_ENV", user, mpprcFile)
        else:
            gaussEnv = DefaultValue.getEnvironmentParameterValue("GAUSS_ENV", user, "~/.bashrc")
        if (gaussEnv is None or gaussEnv == "" or str(gaussEnv) != "2"):
            raise Exception(ErrorCode.GAUSS_503["GAUSS_50300"] %
                            ("installation path of designated user %s" % user) +
                            " Maybe the user is not right.")

    @staticmethod
    def getMpprcFile():
        """
        function : get mpprc file
        input : NA
        output : String
        """
        try:
            # get mpp file by env parameter MPPDB_ENV_SEPARATE_PATH
            mpprcFile = DefaultValue.getEnv(DefaultValue.MPPRC_FILE_ENV)
            if (mpprcFile != "" and mpprcFile is not None):
                userProfile = mpprcFile
                if (not os.path.isabs(userProfile)):
                    raise Exception(ErrorCode.GAUSS_512["GAUSS_51206"] % userProfile)
                if (not os.path.exists(userProfile)):
                    raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % userProfile)
            elif (os.getuid() == 0):
                return "/etc/profile"
            else:
                userAbsoluteHomePath = g_Platform.getUserHomePath()
                userProfile = os.path.join(userAbsoluteHomePath, ".bashrc")
            if (not os.path.isfile(userProfile)):
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50210"] % userProfile)
            return userProfile
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def isIpValid(ip):
        """
        function : check if the input ip address is valid
        input : String
        output : NA
        """
        return g_network.isIpValid(ip)

    @staticmethod
    def configPsutil(distFile, sourceFile):
        glo_cmd = "rm -rf '%s' && cp -af '%s' '%s' " % (distFile, sourceFile, distFile)
        psutilFlag = True
        output_mvPsutil = ""
        for _ in range(3):
            (status_mvPsutil, output_mvPsutil) = subprocess.getstatusoutput(glo_cmd)
            if status_mvPsutil != 0:
                psutilFlag = False
                time.sleep(1)
            else:
                psutilFlag = True
                break
        if not psutilFlag:
            print("Failed to execute cmd: %s. Error:\n%s" % (glo_cmd, output_mvPsutil))
            sys.exit(1)

    @staticmethod
    def doCheckForPsutil(distFile, sourceFile):
        cmd = g_file.SHELL_CMD_DICT["compareFile"] % (distFile, sourceFile)
        (status, output) = subprocess.getstatusoutput(cmd)
        if (status != 0) or len(output.splitlines()) != 2:
            raise Exception(output)
        if output.splitlines()[1].split()[0] != output.splitlines()[0].split()[0]:
            DefaultValue.configPsutil(distFile, sourceFile)

    @staticmethod
    def doConfigForPsutil():
        # mv psutil mode .so file by python version
        pythonVer = sys.version[:1]
        localDir = os.path.dirname(os.path.realpath(__file__))
        pathList = []
        psutilLinux = os.path.join(localDir, "./../../../../lib/psutil/_psutil_linux.so")
        psutilPosix = os.path.join(localDir, "./../../../../lib/psutil/_psutil_posix.so")
        psutilPosix1 = os.path.join(localDir, "./../../inspection/lib/psutil/_psutil_posix.so")
        psutilLinux1 = os.path.join(localDir, "./../../inspection/lib/psutil/_psutil_linux.so")
        pathList.append((psutilLinux, "%s_%s" % (psutilLinux, pythonVer)))
        pathList.append((psutilPosix, "%s_%s" % (psutilPosix, pythonVer)))
        pathList.append((psutilLinux1, "%s_%s" % (psutilLinux1, pythonVer)))
        pathList.append((psutilPosix1, "%s_%s" % (psutilPosix1, pythonVer)))
        if os.path.exists(psutilLinux) and os.path.exists(psutilPosix) and \
                os.path.exists(psutilLinux1) and os.path.exists(psutilPosix1):
            for (distFile, sourceFile) in pathList:
                DefaultValue.doCheckForPsutil(distFile, sourceFile)
        else:
            for (distFile, sourceFile) in pathList:
                DefaultValue.configPsutil(distFile, sourceFile)

    @staticmethod
    def doConfigForParamiko():
        """
        -L (used by the FusionInsight or DWS) or --non-interactive deployment mode,
        which does not involve creating mutual trust through Python. The paramiko module is not required.
        """
        result, version = DefaultValue.checkPythonVersion()
        if not result:
            print(ErrorCode.GAUSS_522["GAUSS_52201"] % version + " It must be 3.X")
            sys.exit(1)
        else:
            localDir = os.path.dirname(os.path.realpath(__file__))
            omToolsCffiPath = os.path.join(localDir, "./../../../../lib/_cffi_backend.so")
            inspectToolsCffiPath = os.path.join(localDir,
                                                "./../../../../script/gspylib/inspection/lib/_cffi_backend.so")

            # Never remove _cffi_backend.so_UCS4 folder, as there maybe multi-version pythons on the platform
            # (V1R8C10 is with its own python, but now, we don't package python anymore).
            try:
                flagNum = int(DefaultValue.GetPythonUCS())
                # clean the old path info
                g_file.removeFile(omToolsCffiPath)
                g_file.removeFile(inspectToolsCffiPath)
                # copy the correct version
                newPythonDependCryptoPath = "%s_UCS%d" % (omToolsCffiPath, flagNum)
                g_file.cpFile(newPythonDependCryptoPath, omToolsCffiPath, "shell")
                g_file.cpFile(newPythonDependCryptoPath, inspectToolsCffiPath, "shell")
            except Exception as e:
                print("Failed to config depend file for paramiko 2.7.2. Error:\n%s" % str(e))
                sys.exit(1)
            sys.path.insert(0, os.path.join(localDir, "./../../../lib"))

    @staticmethod
    def getInstallDir(user):
        """
        function : Get the installation directory for user
        input : NA
        output : String
        """
        # get the installation directory for user by $GAUSSHOME
        gaussHome = DefaultValue.getEnvironmentParameterValue("GAUSSHOME", user)
        return gaussHome

    @staticmethod
    def getTmpDir(user, xml_path):
        """
        function : Get the temporary directory for user
        input : NA
        output : String
        """
        return dbClusterInfo.readClusterTmpMppdbPath(user, xml_path)

    @staticmethod
    def getTmpDirFromEnv(user=""):
        """
        function : Get the temporary directory from PGHOST
        precondition: only root user or install user can call this function
        input : String
        output : String
        """
        tmpDir = ""
        if (os.getuid() == 0 and user == ""):
            return tmpDir
        # get the temporary directory from PGHOST
        tmpDir = DefaultValue.getEnvironmentParameterValue("PGHOST", user)
        return tmpDir

    @staticmethod
    def getTmpFileFromEnv(fileName="", user="", desc=""):
        """
        function : Get the temporary directory from PGHOST
        precondition: only root user or install user can call this function
        input : String
        output : String
        """
        tmpFile = ""
        tmpDir = DefaultValue.getTmpDirFromEnv(user)

        if fileName != "":
            # get current time
            currentTime = time.strftime("%Y-%m-%d_%H%M%S")
            # split the log file by '.'
            # rebuild the file name
            # before rebuild:        prefix.suffix
            # after  rebuild:        prefix-currentTime-pid-desc.suffix
            if fileName.find(".") >= 0:
                tmpList = fileName.split(".")
                prefix = tmpList[0]
                suffix = tmpList[1]
                if (desc == ""):
                    tmpFile = os.path.join(tmpDir, "%s-%s-%d.%s" % (prefix, currentTime, os.getpid(), suffix))
                else:
                    tmpFile = os.path.join(tmpDir, "%s-%s-%d-%s.%s" % (prefix, currentTime, os.getpid(), desc, suffix))
            else:
                tmpFile = os.path.join(tmpDir, "%s-%s-%d" % (fileName, currentTime, os.getpid()))
        return tmpFile

    @staticmethod
    def getTmpDirAppendMppdb(user):
        """
        function : Get the user's temporary directory
        input : String
        output : String
        """
        # get the user's temporary directory
        tmpDir = DefaultValue.getTmpDirFromEnv(user)
        # if the env paramter not exist, return ""
        if (tmpDir == ""):
            return tmpDir
        # modify tmp dir
        forbidenTmpDir = "/tmp/%s" % user
        if (tmpDir == forbidenTmpDir):
            tmpDir = "/tmp/%s_mppdb" % user
        return tmpDir

    @staticmethod
    def getEnvironmentParameterValue(environmentParameterName, user, env_file=None):
        """
        function : Get the environment parameter value from user
        input : String,String
        output : String
        """
        try:
            DefaultValue.getUserId(user)
            # User exists, need to check passwd.
            userFlag = True
        except Exception:
            # User does not exist.
            userFlag = False

        if userFlag and os.getuid() == 0:
            # Only user with root permission need check if password must change.
            DefaultValue.checkPasswdForceChange(user)

        if env_file is not None:
            userProfile = env_file
        else:
            userProfile = DefaultValue.getMpprcFile()
        # build the shell command
        executeCmd = "echo $%s" % environmentParameterName
        cmd = g_Platform.getExecuteCmdWithUserProfile(user, userProfile, executeCmd)
        (status, output) = subprocess.getstatusoutput(cmd)
        if status == 0:
            EnvValue = output.split("\n")[0]
            EnvValue = EnvValue.replace("\\", "\\\\").replace('"', '\\"\\"')
            DefaultValue.checkPathVaild(EnvValue)
            return EnvValue
        else:
            return ""

    @staticmethod
    def checkPasswdForceChange(checkUser):
        """
        function: Check if user password is forced to change at next login.
        input : user name
        output: NA
        """
        gs_platform = Platform()
        distname, version, _ = gs_platform.dist()
        distname = distname.lower()
        if distname == support_platform.SUPPORT_WHOLE_PLATFORM_LIST:
            cmd = g_file.SHELL_CMD_DICT["checkPassword"] % (checkUser, "'^Last.*Change'")
        else:
            return

        (timestatus, output) = subprocess.getstatusoutput(cmd)
        if (timestatus != 0):
            raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error:\n%s" % output)
        if (output == ""):
            return
        result = output.split(":")[1].strip()
        # If passwd is forced to change. Throw error code.
        if distname == support_platform.SUSE:
            if version == support_platform.SUSE11:
                if ("password is forced to change at next login" in result):
                    raise Exception(ErrorCode.GAUSS_503["GAUSS_50307"])
            else:
                if ("password must be changed" in result):
                    raise Exception(ErrorCode.GAUSS_503["GAUSS_50307"])
        if distname in support_platform.RHEL_SERIES_VERSION_LIST + support_platform.OTHER_PLATFORM_LIST:
            if ("password must be changed" in result):
                raise Exception(ErrorCode.GAUSS_503["GAUSS_50307"])

    @staticmethod
    def getClusterToolPath():
        """
        function : Get the value of cluster's tool path. The value can't be None or null
        input : NA
        output : String
        """
        mpprcFile = DefaultValue.getEnv(DefaultValue.MPPRC_FILE_ENV)
        echoEnvCmd = "echo $%s" % DefaultValue.TOOL_PATH_ENV
        if (mpprcFile == "" or mpprcFile is None):
            mpprcFile = "/etc/profile"
        cmd = g_Platform.getExecuteCmdWithUserProfile("", mpprcFile, echoEnvCmd)
        (status, output) = subprocess.getstatusoutput(cmd)
        if (status != 0):
            raise Exception(ErrorCode.GAUSS_518["GAUSS_51802"] % DefaultValue.TOOL_PATH_ENV + " Error: \n%s" % output)

        clusterToolPath = output.split("\n")[0]
        if (clusterToolPath is None or clusterToolPath == ""):
            raise Exception(ErrorCode.GAUSS_518["GAUSS_51800"] % DefaultValue.TOOL_PATH_ENV +
                            "Value: %s." % clusterToolPath)

        # Check if the path contains illegal characters
        DefaultValue.checkPathVaild(clusterToolPath)

        return clusterToolPath

    @staticmethod
    def getPreClusterToolPath(user, xml):
        """
        function: get the cluster tool path
        input : NA
        output: NA
        """
        try:
            configedPath = DefaultValue.getOneClusterConfigItem("gaussdbToolPath", user, xml)
            if (configedPath == ""):
                configedPath = DefaultValue.CLUSTER_TOOL_PATH
            DefaultValue.checkPathVaild(configedPath)
            return configedPath
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def getOneClusterConfigItem(item_name, user, xml):
        """
        function: get the OM log path
        input : NA
        output: NA
        """
        try:
            # set env paramter CLUSTERCONFIGFILE
            os.putenv("CLUSTERCONFIGFILE", xml)
            # read one cluster configuration item "cluster"
            (retStatus, retValue) = parse_xml.readOneClusterConfigItem(parse_xml.initParserXMLFile(xml),
                                                                       item_name, "cluster")
            if (retStatus == 0):
                return os.path.normpath(retValue)
            else:
                return ""
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def getUserLogDirWithUser(user):
        """
        function : Get the log directory from user
        input : String
        output : String
        """
        log_path = ""
        try:
            log_path = DefaultValue.getEnvironmentParameterValue("GAUSSLOG", user)
        except Exception:
            log_path = "%s/%s" % (DefaultValue.GAUSSDB_DIR, user)
        return log_path

    @staticmethod
    def getOMLogPath(logName, user="", appPath="", xml="", action=""):
        """
        function : Get the OM log path from xml file
        input : String
        output : String
        """
        try:
            if (user != "" and xml != ""):
                logPath = "%s" % dbClusterInfo.readClusterLogPath(xml)
                path = "%s/%s/om/%s" % (logPath, user, logName)
            elif (action == "virtualip"):
                path = "/tmp/gs_virtualip/%s" % (logName)
            elif (user != ""):
                logPath = DefaultValue.getUserLogDirWithUser(user)
                path = "%s/om/%s" % (logPath, logName)
            elif (appPath != ""):
                user = g_OSlib.getPathOwner(appPath)[0]
                if (user == ""):
                    user = "."
                if (user == "."):
                    logPath = DefaultValue.GAUSSDB_DIR
                else:
                    logPath = DefaultValue.getUserLogDirWithUser(user)
                path = "%s/om/%s" % (logPath, logName)
            else:
                logPath = DefaultValue.GAUSSDB_DIR
                path = "%s/om/%s" % (logPath, logName)
        except Exception:
            logPath = DefaultValue.GAUSSDB_DIR
            path = "%s/om/%s" % (logPath, DefaultValue.LOCAL_LOG_FILE)

        return os.path.realpath(path)

    @staticmethod
    def getBackupDir(subDir=""):
        """
        function : Get the cluster's default backup directory for upgrade
        input : String
        output : String
        """
        bakDir = "%s/backup" % DefaultValue.getClusterToolPath()
        if subDir != "":
            bakDir = os.path.join(bakDir, subDir)

        return bakDir

    @staticmethod
    def getAppBVersion(user, appPath=""):
        """
        function :Get the version of application by $GAUSS_VERSION
        input : String
        output : String
        """
        # build shell command
        userProfile = DefaultValue.getMpprcFile()
        executeCmd = "gaussdb -V"
        cmd = g_Platform.getExecuteCmdWithUserProfile(user, userProfile, executeCmd, False)
        (status, output) = subprocess.getstatusoutput(cmd)
        if status != 0:
            return ""
        return output.replace('gaussdb ', '').strip()

    @staticmethod
    def getOSInitFile():
        """
        function : Get the OS initialization file
        input : NA
        output : String
        """
        systemDir = "/usr/lib/systemd/system/"
        systemFile = "/usr/lib/systemd/system/gs-OS-set.service"
        # system init file
        initSystemFile = "/usr/local/gauss/script/gauss-OS-set.sh"
        initSystemPath = "/usr/local/gauss/script"
        dirName = os.path.dirname(os.path.realpath(__file__))

        if os.path.isdir(systemDir):
            if not os.path.exists(systemFile):
                srcFile = "%s/../../etc/conf/gs-OS-set.service" % dirName
                g_file.cpFile(srcFile, systemFile)
                g_file.changeMode(DefaultValue.KEY_FILE_MODE, systemFile)
                # support RHEL/Centos/Euler/SUSE12/SUSE15
                # SUSE11: only support the 'service' command, and gs-OS-set.service does not work after reboot
                # enable gs-OS-set.service
                (status, output) = g_service.manageOSService("gs-OS-set", "enable")
                if status != 0:
                    g_file.removeFile(systemFile)
                    raise Exception(ErrorCode.GAUSS_508["GAUSS_50802"] % "enable gs-OS-set" +
                                    " Error: \n%s" % output)
            if not os.path.exists(initSystemPath):
                g_file.createDirectory(initSystemPath)
            if not os.path.exists(initSystemFile):
                g_file.createFile(initSystemFile, False)
                g_file.writeFile(initSystemFile, ["#!/bin/bash"], "w")
            g_file.changeMode(DefaultValue.KEY_DIRECTORY_MODE, initSystemFile)
            return initSystemFile

        initFile = g_Platform.get_os_init_file()
        return initFile

    @staticmethod
    def getNetworkConfiguredFile(ip):
        """
        function: get network configuration file
        input: ip
        output: networkFile
        """
        pattern = re.compile("ifcfg-.*:.*")
        networkFile = ""
        fp = None
        try:
            for filename in os.listdir(DefaultValue.REDHAT_NETWORK_PATH):
                result = pattern.match(filename)
                if (result is None):
                    continue
                paramfile = "%s/%s" % (DefaultValue.REDHAT_NETWORK_PATH, filename)
                fp = open(paramfile, "r")
                fileInfo = fp.readlines()
                fp.close()
                # The current opened file is generated while configing virtual IP,
                # there are 3 lines in file, and the second line is IPADDR=IP
                if len(fileInfo) == 3 and (fileInfo[1].find("IPADDR=%s" % ip) >= 0 or
                                           fileInfo[1].find("IPV6ADDR=%s" % ip) >= 0):
                    networkFile += "%s " % paramfile
            return networkFile
        except Exception as e:
            if fp:
                fp.close()
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50219"] % "network configuration file" +
                            " Error: \n%s " % str(e))

    @staticmethod
    def getMatchingResult(matchExpression, fileMatching, remoteHostName=""):
        """
        """
        cmd = "%s -E '%s' %s" % (g_Platform.getGrepCmd(), matchExpression, fileMatching)
        if ("" != remoteHostName and remoteHostName != socket.gethostname()):
            cmd = g_OSlib.getSshCommand(remoteHostName, cmd)
        (status, output) = subprocess.getstatusoutput(cmd)
        return (status, output)

    @staticmethod
    def preConfigFile(filename):
        """
        function: pretreatment configuration file, delete the ' ' or '\t' when they top of line
        input: filename
        output: NA
        """
        try:
            (status, output) = DefaultValue.getMatchingResult("^[ \\t]", filename)
            if (status != 0):
                return
            listLine = output.split('\n')
            for strline in listLine:
                g_file.replaceFileLineContent("^%s$" % strline, strline.strip(), filename)

        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def getConfigFilePara(configFile, section, checkList=None, optionsName=None):
        """
        function: get the configuration file(check_list.conf)
        input: section: the section in check_list.conf will be get
               optionsName: the parameter list will be get, if parameter is NULL, then get all
        output: dist
        """
        if checkList is None:
            checkList = []
        if optionsName is None:
            optionsName = []
        try:
            DefaultValue.preConfigFile(configFile)

            # read the check_list.conf
            data = {}
            fp = configparser.RawConfigParser()
            fp.read(configFile)

            # get the sections then check the section whether or not in check_list.conf
            secs = fp.sections()
            if section not in secs:
                return data

            # get the parameters then check options whether or not in section parameters
            optionList = fp.options(section)
            if (len(optionsName) != 0 and optionsName not in optionList):
                return data
            elif (len(optionsName) != 0):
                optionList = optionsName

            # get th parameter values
            for key in optionList:
                value = fp.get(section, key)
                if (len(value.split()) == 0):
                    raise Exception("The parameter value of %s is Null." % key)
                value = value.split('#')[0]
                if (key in checkList and not value.isdigit()):
                    raise Exception("The value of %s must be a digit." % key)
                if (section == '/etc/security/limits.conf' and not value.isdigit() and value != 'unlimited'):
                    raise Exception("The value of %s is error." % key)
                data[key] = value

            if ("vm.min_free_kbytes" in data.keys()):
                swapTotalSize = g_memory.getMemTotalSize() // 1024
                multiple = data["vm.min_free_kbytes"].split('*')[1].split('%')[0].strip()
                val = int(swapTotalSize) * int(multiple) // 100
                data["vm.min_free_kbytes"] = str(val)

            if "net.nf_conntrack_max" in data.keys() and \
                    not os.path.exists('/proc/sys/net/nf_conntrack_max'):
                data.pop('net.nf_conntrack_max')

            return data
        except Exception as e:
            raise Exception(ErrorCode.GAUSS_512["GAUSS_51234"] % configFile + " Error: \n%s" % str(e))

    @staticmethod
    def checkInList(listsrc, listdest):
        """
        function: check the listsrc element is not in listdest
        input: listsrc, listdest
        output: True or False
        """
        if (listsrc == [] or listdest == []):
            return False

        for key in listsrc:
            if (key in listdest):
                return True
        return False

    @staticmethod
    def checkSSDInstalled():
        """
        function: check SSD
        input: NA
        output: True/False
        """
        cmd = "hio_info"
        (status, _) = subprocess.getstatusoutput(cmd)
        if (status != 0):
            return False
        return True

    @staticmethod
    def Deduplication(listname):
        """
        function: Deduplication the list
        input : NA
        output: NA
        """
        listname.sort()
        for i in range(len(listname) - 2, -1, -1):
            if listname.count(listname[i]) > 1:
                del listname[i]
        return listname

    @staticmethod
    def getEnv(envparam):
        """
        function: get the filter environment variable
        input:envparam
        output:envValue
        """
        try:
            envValue = os.getenv(envparam)

            if (envValue == "" or envValue is None):
                return envValue

            envValue = envValue.replace("\\", "\\\\").replace('"', '\\"\\"')

            DefaultValue.checkPathVaild(envValue)

            return envValue
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def checkPathVaild(envValue):
        """
        function: check path vaild
        input : envValue
        output: NA
        """
        if envValue.strip() == "":
            return
        for rac in DefaultValue.PATH_CHECK_LIST:
            flag = envValue.find(rac)
            if flag >= 0:
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50219"] % envValue +
                                " There are illegal characters in the path.")

    @staticmethod
    def checkPasswordVaild(password, user="", clusterInfo=None):
        """
        function: check password vaild
        input : password
        output: NA
        """
        # rule1: check if the password contains illegal characters
        for rac in DefaultValue.PASSWORD_CHECK_LIST:
            flag = password.find(rac)
            if flag >= 0:
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50219"] % "the password" +
                                " The password contains illegal characters.")

    @staticmethod
    def checkPackageOS():
        """
        function : get and check binary file
        input : NA
        output : boolean
        """
        try:
            (fileSHA256, sha256Value) = g_OSlib.getFileSHA256Info()
            if (fileSHA256 != sha256Value):
                raise Exception(ErrorCode.GAUSS_516["GAUSS_51635"] +
                                "The SHA256 value is different. \nBin file: %s\nSHA256 file: %s." %
                                (fileSHA256, sha256Value))
            return True
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def removeTmpMpp(mpprcFile):
        mppTmp_rm = os.path.dirname(mpprcFile) + "/mpprcfile_tmp"
        if os.path.exists(mppTmp_rm):
            g_file.removeDirectory(mppTmp_rm)

    @staticmethod
    def checkRemoteDir(g_sshTool, remoteDir, hostname, mpprcFile="", localMode=False):
        '''
        function: check the remoteDir is existing on hostname
        input: remoteDir, hostname, mpprcFile
        output:NA
        '''
        try:
            # check package dir
            # package path permission can not change to 750, or it will have permission issue.
            toolpath = remoteDir.split("/")
            toolpath[0] = "/" + toolpath[0]
            path_cmd = ""
            for path in toolpath:
                if path == "":
                    continue
                cmd = g_file.SHELL_CMD_DICT["createDir"] % (path, path, DefaultValue.MAX_DIRECTORY_MODE)
                path_cmd = "%s%s; cd '%s';" % (path_cmd, cmd, path)
            path_cmd = path_cmd[:-1]
            DefaultValue.execCommandWithMode(path_cmd,
                                             "check package directory",
                                             g_sshTool,
                                             localMode,
                                             mpprcFile,
                                             hostname)
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def checkAllNodesMpprcFile(hostList, appPath, mpprcFile):
        """
        function:check All Nodes MpprcFile
        input: hostList, appPath, mpprcFile
        output:NA
        """
        # get mppfile, make sure it exists
        if (mpprcFile == "" or mpprcFile is None or mpprcFile == "/etc/profile" or
                mpprcFile == "~/.bashrc" or not os.path.exists(mpprcFile)):
            return
        if (len(hostList) == 0):
            raise Exception(ErrorCode.GAUSS_512["GAUSS_51203"] % "hostanme")
        mppTmp = os.path.dirname(mpprcFile) + "/mpprcfile_tmp"
        # Clean old tmp dir
        DefaultValue.removeTmpMpp(mpprcFile)
        # Create tmp dir for all mppfile
        g_file.createDirectory(mppTmp)
        # Copy every mppfile, rename them by hostname
        for host in hostList:
            catCmd = "%s %s > /dev/null 2>&1" % (g_Platform.getCatCmd(), mpprcFile)
            cmd = g_OSlib.getSshCommand(host, catCmd)
            (status, _) = subprocess.getstatusoutput(cmd)
            if (status == 0):
                tmpEnv = "%s/%s_env" % (mppTmp, host)
                scpCmd = g_Platform.getRemoteCopyCmd(mpprcFile, tmpEnv, host, False)
                subprocess.getstatusoutput(scpCmd)
                DefaultValue.execCommandLocally(scpCmd)
                DefaultValue.checkMpprcFileChange(appPath, tmpEnv, host, mpprcFile)

        # remove tmp dir
        DefaultValue.removeTmpMpp(mpprcFile)

    @staticmethod
    def check_env_file(env_list, mpprc_file, host):
        """
        function: check env file
        input: env list
        output: NA
        """
        # white elements
        list_white = ["ELK_CONFIG_DIR", "ELK_SYSTEM_TABLESPACE", "MPPDB_ENV_SEPARATE_PATH", "GPHOME", "PATH",
                      "LD_LIBRARY_PATH", "PYTHONPATH", "GAUSS_WARNING_TYPE", "GAUSSHOME", "PATH", "LD_LIBRARY_PATH",
                      "S3_CLIENT_CRT_FILE", "GAUSS_VERSION", "PGHOST", "GS_CLUSTER_NAME", "GAUSSLOG", "GAUSS_ENV"]
        # black elements
        list_black = ["|", ";", "&", "<", ">", "`", "\\", "!", "\n"]

        # check mpprcfile
        flag_white = 0
        for env in env_list:
            env = env.strip()
            if env == "":
                continue
            for white in list_white:
                flag_white = 0
                flag = env.find(white)
                if env.startswith('export') or flag >= 0:
                    flag_white = 1
                    break
            if flag_white == 0:
                DefaultValue.removeTmpMpp(mpprc_file)
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50219"] % env +
                                " There are illegal characters in %s." % host)
            for black in list_black:
                flag = env.find(black)
                if flag >= 0 and env != "":
                    DefaultValue.removeTmpMpp(mpprc_file)
                    raise Exception(ErrorCode.GAUSS_502["GAUSS_50219"] % env +
                                    " There are illegal characters in %s." % host)

    @staticmethod
    def checkMpprcFileChange(appPath, mpprcFile, host="local host", mpprcFile_rm=""):
        """
        function:Check if mppfile has been changed
        input: mppfile
        output:NA
        """
        # get mppfile, make sure it exists
        if (mpprcFile == "" or mpprcFile is None or mpprcFile == "/etc/profile" or
                mpprcFile == "~/.bashrc" or not os.path.exists(mpprcFile)):
            DefaultValue.removeTmpMpp(mpprcFile)
            return

        if host == "" or host is None:
            host = "local host"

        # read the content of mppfile
        with open(mpprcFile, "r") as fp:
            mpp_content = fp.read()
            env_list = mpp_content.split('\n')
        while '' in env_list:
            env_list.remove('')

        # get ec content from xml
        ec_content = "if [ -f '%s/utilslib/env_ec' ] && [ `id -u` -ne 0 ]; then source '%s/utilslib/env_ec'; fi " % \
                     (appPath, appPath)
        ec_content_old = "if [ -f '%s/utilslib/env_ec' ] ; then source '%s/utilslib/env_ec'; fi " % (appPath, appPath)
        ec_content_no_space = "if [ -f '%s/utilslib/env_ec' ] && [ `id -u` -ne 0 ]; " \
                              "then source '%s/utilslib/env_ec'; fi" % (appPath, appPath)

        # get ec content from env
        appPathValue = DefaultValue.getEnv("GAUSSHOME")
        ec_content_env = "if [ -f '%s/utilslib/env_ec' ] && [ `id -u` -ne 0 ]; " \
                         "then source '%s/utilslib/env_ec'; fi " % (appPathValue, appPathValue)
        ec_content_old_env = "if [ -f '%s/utilslib/env_ec' ] ; then source '%s/utilslib/env_ec'; fi " % \
                             (appPathValue, appPathValue)
        ec_content_no_space_env = "if [ -f '%s/utilslib/env_ec' ] && [ `id -u` -ne 0 ]; " \
                                  "then source '%s/utilslib/env_ec'; fi" % (appPathValue, appPathValue)

        # remove ec content from list
        ec_content_list = [ec_content, ec_content_old, ec_content_no_space, ec_content_env, ec_content_old_env,
                           ec_content_no_space_env]
        for tmp_ec in ec_content_list:
            if tmp_ec in env_list:
                env_list.remove(tmp_ec)
        DefaultValue.check_env_file(env_list, mpprcFile_rm, host)

    @staticmethod
    def checkDeletedCN(ClusterInfo, sshTool):
        """
        function:Check deletedCN
        input:NA
        output:list
        """
        cmNames = []
        deletedCNs = []
        envFile = DefaultValue.getMpprcFile()
        for dbNode in ClusterInfo.dbNodes:
            if len(dbNode.cmservers) > 0:
                cmNames.append(dbNode.name)
        cmd = "echo +++ && cm_ctl view -c|grep -B 1 -E '^role[ ]+: .*' && echo +++"
        (status, _) = sshTool.getSshStatusOutput(cmd, cmNames, env_file=envFile)
        outputMap = sshTool.parseSshOutput(cmNames)
        MATCH_KEYWORD = "^instance_id.*:.*\d*\n^role.*:.*"
        pattern = re.compile(MATCH_KEYWORD, re.M)
        for cmName in cmNames:
            if str(outputMap[cmName]).find("Deleted") >= 0:
                cmdoutputlst = str(outputMap[cmName]).split("+++")
                if len(cmdoutputlst) < 2:
                    continue
                cmdoutput = cmdoutputlst[1]
                status = cmdoutput.split("--")
                for state in status:
                    info = state.strip()
                    cnInfoList = info.splitlines()
                    if len(cnInfoList) != 2 or pattern.match(info) is None:
                        continue
                    num = cnInfoList[0].split(":")[1].strip()
                    sts = cnInfoList[1].split(":")[1].strip()
                    if sts.find("Deleted") >= 0 and (num not in deletedCNs):
                        deletedCNs.append(num)
            else:
                continue
        return deletedCNs

    @staticmethod
    def sourceEnvFile(file_env):
        """
        """
        cmd = "%s '%s'" % (g_Platform.getSourceCmd(), file_env)
        (status, output) = subprocess.getstatusoutput(cmd)
        if status != 0 or output.strip() != "":
            return False, output
        return True, ""

    @staticmethod
    def checkEnvFile(mpprcFile="", user=""):
        """
        function: check if the env file contains msg which may cause the program failed.
        input: NA
        output: NA
        """
        (status, output) = DefaultValue.sourceEnvFile("/etc/profile")
        if not status:
            return (False, output)

        if (mpprcFile != "" and os.path.isfile(mpprcFile)):
            (status, output) = DefaultValue.sourceEnvFile(mpprcFile)
            if not status:
                return (False, output)

        if ((user != "") and (os.getuid() == 0)):
            executeCmd = "%s '%s' && %s '%s'" % \
                         (g_Platform.getSourceCmd(), "/etc/profile",
                          g_Platform.getSourceCmd(), "~/.bashrc")
            if (mpprcFile != ""):
                remoteSourceCmd = "if [ -f '%s' ] ; then %s '%s'; fi" % \
                                  (mpprcFile, g_Platform.getSourceCmd(), mpprcFile)
                executeCmd = "%s && %s" % (executeCmd, remoteSourceCmd)
            cmd = g_Platform.getExecuteCmdWithUserProfile(user, "~/.bashrc", executeCmd, False)
            (status, output) = subprocess.getstatusoutput(cmd)
            if (status != 0 or output.strip() != ""):
                return (False, output)
        return (True, "")

    @staticmethod
    def findUnsupportedParameters(parameterList):
        """
        function : find unsupported configuration parameters, just ignore other invalid parameters.
                   if don't find any unsupported configuration parameter, return [].
        input : List
        output : []
        """
        # init unsupported args list
        unsupportedArgs = ["support_extended_features"]
        inputedUnsupportedParameters = []
        for param in parameterList:
            # split it by '='
            keyValue = param.split("=")
            if (len(keyValue) != 2):
                continue
            if (keyValue[0].strip() in unsupportedArgs):
                inputedUnsupportedParameters.append(param)

        return inputedUnsupportedParameters

    @staticmethod
    def judgePathUser(tempPath):
        """
        function: judge the owner of path if exist
        input: tempPath
        output: True/False
        """
        try:
            _ = pwd.getpwuid(os.stat(tempPath).st_uid).pw_name
            return True
        except Exception as e:
            # if the user is not exist
            if (str(e).find("uid not found") >= 0):
                return False
            else:
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50219"] % ("the owner of %s" % tempPath) +
                                " Error: \n%s" % str(e))

    @staticmethod
    def checkPathandChangeOwner(onePath, user, group, permission):
        """
        function: Get the owner of each layer path , if the user does not exist and change owner
        input: onePath---the specified path; user---the user of cluster; group---the group of cluster
        output: the owner of path
        precondiftion: the path exists
        """
        pathlist = []
        try:
            if (not os.path.exists(onePath)):
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % onePath)

            ownerPath = onePath
            while True:
                # obtain the each top path
                (ownerPath, dirName) = os.path.split(ownerPath)
                if (os.path.exists(ownerPath) and dirName != ""):
                    pathlist.append(os.path.join(ownerPath, dirName))
                else:
                    break

            for tempPath in pathlist:
                # the user does not exist
                if (not DefaultValue.judgePathUser(tempPath)):
                    g_file.changeMode(permission, tempPath)
                    g_file.changeOwner(user, tempPath)
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def checkOsVersion():
        """
        function : Check os version
        input : NA
        output : boolean
        """
        # now we support this platform:
        #     RHEL/CentOS     "6.4", "6.5", "6.6", "6.7", "6.8", "6.9", "7.0", "7.1", "7.2", "7.3", "7.4", "7.5"64bit
        #     SuSE11  sp1/2/3/4 64bit
        #     EulerOS '2.0'64bit
        #     SuSE12  sp0/1/2/3 64bit
        try:
            g_Platform.getCurrentPlatForm()
            return True
        except Exception:
            return False

    @staticmethod
    def checkPreInstallFlag(user):
        """
        function : check if have called preinstall.py script
        input : String
        output : boolean
        """
        gaussEnv = DefaultValue.getEnvironmentParameterValue("GAUSS_ENV", user)
        if ("" == gaussEnv):
            return False
        if (str(gaussEnv) != "1" or str(gaussEnv) != "2"):
            return True
        else:
            return False

    @staticmethod
    def cleanTmpFile(path, fp=None):
        """
        function : close and remove temporary file
        input : String,file
        output : NA
        """
        if fp:
            fp.close()
        if os.path.exists(path):
            os.remove(path)

    @staticmethod
    def distributeEncryptFiles(sshTool, appPath, hostList):
        """
        function : distribute encrypted files of server.key.cipher and server.key.rand to remote host
        input : String,[]
        output : NA
        """
        # init encrypt file
        binPath = "%s/bin" % appPath
        encryptFile1 = "%s/server.key.cipher" % binPath
        encryptFile2 = "%s/server.key.rand" % binPath
        if (not os.path.exists(encryptFile1) or not os.path.exists(encryptFile2)):
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % "encrypt files" + " Please check it.")
        # get user and group
        (user, group) = g_OSlib.getPathOwner(appPath)
        if (user == "" or group == ""):
            raise Exception(ErrorCode.GAUSS_503["GAUSS_50308"] + ".")

        # copy encrypt file to host
        if hostList:
            targetPath = "'%s'/" % binPath
            sshTool.scpFiles(encryptFile1, targetPath, hostList)
            sshTool.scpFiles(encryptFile2, targetPath, hostList)

            chownCmd1 = g_Platform.getChownCmd(user, group, encryptFile1)
            chownCmd2 = g_Platform.getChownCmd(user, group, encryptFile2)
            chmodCmd1 = g_Platform.getChmodCmd(str(DefaultValue.KEY_FILE_MODE), encryptFile1)
            chmodCmd2 = g_Platform.getChmodCmd(str(DefaultValue.KEY_FILE_MODE), encryptFile2)
            executeCmd = "%s && %s && %s && %s" % (chownCmd1, chownCmd2, chmodCmd1, chmodCmd2)
            sshTool.executeCommand(executeCmd, "chmod encrypt file permisson", DefaultValue.SUCCESS, hostList)

    @staticmethod
    def distribute_feature_license_file(sshTool, appPath, hostList):
        """
        function : distribute feature license file to remote host, for scenarios: expand,addCn,repalce,resize
        input :  object,string,list
        output : NA
        """
        cluster_bin_path = "%s/bin/" % appPath
        feature_license_file = "%s/feature_license.json" % cluster_bin_path

        # If the file exists. Remote copy datasource cipher file to new nodes.
        if os.path.isfile(feature_license_file):
            sshTool.scpFiles(feature_license_file, cluster_bin_path, hostList)
            cmd = g_Platform.getChmodCmd(str(DefaultValue.KEY_FILE_MODE), feature_license_file)
            sshTool.executeCommand(cmd, "change the feature license file permission", DefaultValue.SUCCESS, hostList)

    @staticmethod
    def distributeDatasourceFiles(sshTool, appPath, hostList):
        """
        function : distribute datasource files of datasource.key.cipher and datasource.key.rand to remote host
        input : String,String
        output : NA
        """
        # init datasource file
        clusterBinPath = "%s/bin/" % appPath
        datasourceCipherFile = "%s/datasource.key.cipher" % clusterBinPath
        datasourceRandFile = "%s/datasource.key.rand" % clusterBinPath
        tde_key_cipher = "%s/gs_tde_keys.cipher" % clusterBinPath

        # If the file exists. Remote copy datasource cipher file to new nodes.
        if (os.path.isfile(datasourceCipherFile)):
            sshTool.scpFiles(datasourceCipherFile, clusterBinPath, hostList)
            cmd = g_Platform.getChmodCmd(str(DefaultValue.KEY_FILE_MODE), datasourceCipherFile)
            sshTool.executeCommand(cmd, "change the datasource cipher file permission", DefaultValue.SUCCESS, hostList)
        # If the file exists. Remote copy datasource rand file to new nodes.
        if (os.path.isfile(datasourceRandFile)):
            sshTool.scpFiles(datasourceRandFile, clusterBinPath, hostList)
            cmd = g_Platform.getChmodCmd(str(DefaultValue.KEY_FILE_MODE), datasourceRandFile)
            sshTool.executeCommand(cmd, "change the datasource rand file permission", DefaultValue.SUCCESS, hostList)
        # If the file exists. Remote copy gs_tde_keys.cipher to new nodes.
        if (os.path.isfile(tde_key_cipher)):
            sshTool.scpFiles(tde_key_cipher, clusterBinPath, hostList)
            cmd = g_Platform.getChmodCmd(str(DefaultValue.KEY_FILE_MODE), tde_key_cipher)
            sshTool.executeCommand(cmd, "change the gs_tde_keys.cipher permission", DefaultValue.SUCCESS, hostList)

    @staticmethod
    def copy_postgis_lib(ssh_tool, app_path, local_hostname, host_list, logger):
        """
        function: copy postgis lib to remote host
        input: ssh_tool, app_path, local_hostname, host_list
        output: NA
        """
        fileLocation = dict()
        fileLocation["'%s'/lib/postgresql/" % app_path] = "postgis-*.*.so|rtpostgis-*.*.so"
        fileLocation["'%s'/lib/" % app_path] = "(libgeos_c.so.*|libproj.so.*|libjson-c.so.*|libgeos-*.*.*so|" \
                                               "libstdc++.*|libgcc_s.so.*|libvim /gdal.so.*|liblwgeom-*.*.so.*|" \
                                               "libgeos.so.*|libsqlite.*.so.*|libprotobuf-c.so.*)"
        fileLocation["'%s'/share/postgresql/extension/" % app_path] = \
            "(postgis--*.*.*.sql|postgis.control|postgis_raster*.*.*.sql|postgis_raster.control|postgis--*.*.*.*.sql)"
        fileLocation["'%s'/bin/" % app_path] = "(pgsql2shp|shp2pgsql|raster2pgsql|logic_cluster_name.txt|" \
                                               "[a-zA-Z0-9_]{1,64}.cluster_static_config)"
        fileLocation["'%s'/etc/" % app_path] = "*.gscgroup_.*.cfg"

        for (gisLibPath, pattarn) in fileLocation.items():
            gisFiles = g_file.getDirectoryList(gisLibPath, pattarn)
            if len(gisFiles) > 0:
                if len(gisFiles) > 1:
                    srcPath = "%s/{'%s'}" % (gisLibPath, "','".join(gisFiles))
                else:
                    srcPath = "%s/%s" % (gisLibPath, gisFiles[0])
                cmd = DefaultValue.get_remote_copy_cmd(srcPath, gisLibPath, local_hostname)
                logger.debug(cmd)
                ssh_tool.executeCommand(cmd, "Copy postgis lib", DefaultValue.SUCCESS, host_list)

    @staticmethod
    def get_remote_copy_cmd(src_path, dest_path, hostname):
        def get_chmod_cmd(src_path, mode):
            return ("find %s -type f -regex '.*\\.py\\|.*\\.sh\\|.*\\.so' "
                    "-print0|xargs -0 -n 800 -r chmod %s ") % (src_path, mode)

        cmd = "%s && %s && %s" % (get_chmod_cmd(src_path, DefaultValue.KEY_FILE_MODE),
                                  g_Platform.getRemoteCopyCmd(src_path, dest_path, hostname, False, "directory"),
                                  get_chmod_cmd(src_path, DefaultValue.SPE_FILE_MODE))

        return cmd

    @staticmethod
    def distributeUtilslibDir(sshTool, logger, appPath, hostList):
        """
        function : distribute utilslib dir to remote host
        input : String,String
        output : NA
        """
        localHostName = socket.gethostname()
        # init utilslib dir
        datasourceLibPath = "%s/utilslib" % appPath
        if os.path.exists(datasourceLibPath):
            srcPath = "'%s'/*" % datasourceLibPath
            destPath = "'%s'/" % datasourceLibPath
            cmd = DefaultValue.get_remote_copy_cmd(srcPath, destPath, localHostName)
            logger.debug(cmd)
            sshTool.executeCommand(cmd, "Copy utils lib for extension connector deployment tool",
                                   DefaultValue.SUCCESS, hostList)

        # init java UDF lib dir
        javaUDFLibPath = "%s/lib/postgresql/java" % appPath
        if os.path.isdir(javaUDFLibPath):
            udfFiles = g_file.getDirectoryList(javaUDFLibPath)
            if len(udfFiles) > 0:
                srcPath = "'%s'/*" % javaUDFLibPath
                destPath = "'%s'/" % javaUDFLibPath
                cmd = DefaultValue.get_remote_copy_cmd(srcPath, destPath, localHostName)
                logger.debug(cmd)
                sshTool.executeCommand(cmd, "Copy java UDF lib", DefaultValue.SUCCESS, hostList)

        # init postgis lib dir
        postgisPath = ["%s/install/gdal" % appPath, "%s/bin/.libs" % appPath]
        for postgisdir in postgisPath:
            if not os.path.isdir(postgisdir):
                continue
            mkdirCmd = g_Platform.getMakeDirCmd(postgisdir, True)
            changModeCmd = g_Platform.getChmodCmd(str(DefaultValue.KEY_DIRECTORY_MODE), postgisdir)
            cmd = "%s && %s" % (mkdirCmd, changModeCmd)
            logger.debug(cmd)
            sshTool.executeCommand(cmd, "Create postgis dir", DefaultValue.SUCCESS, hostList)
            postgisFiles = g_file.getDirectoryList(postgisdir)
            if len(postgisFiles) == 0:
                continue
            srcPath = "'%s'/*" % postgisdir
            if postgisdir == "%s/bin/.libs" % appPath:
                srcPath = "'%s'/raster2pgsql" % postgisdir
            destPath = "'%s'/" % postgisdir
            cmd = DefaultValue.get_remote_copy_cmd(srcPath, destPath, localHostName)
            logger.debug(cmd)
            sshTool.executeCommand(cmd, "Copy postgis files", DefaultValue.SUCCESS, hostList)

        DefaultValue.copy_postgis_lib(sshTool, appPath, localHostName, hostList, logger)
        DefaultValue.distribute_roach_tools(sshTool, logger, hostList)

    @staticmethod
    def distribute_roach_tools(ssh_tool, logger, host_list):
        tool_path = DefaultValue.getEnv(DefaultValue.TOOL_PATH_ENV)
        tool_plugin_path = os.path.join(tool_path, "plugin")
        roach_plugin = os.path.join(tool_plugin_path, "roach")
        if not os.path.exists(roach_plugin):
            logger.debug("roach tools [%s] not exists" % roach_plugin)
            return
        local_hostname = socket.gethostname()
        cmd = DefaultValue.get_remote_copy_cmd(roach_plugin, tool_plugin_path, local_hostname)
        cmd += "; export LD_LIBRARY_PATH=$GAUSSHOME/lib:$LD_LIBRARY_PATH; python3 %s/install.py -L" % roach_plugin
        logger.debug("command for distributeing roach tools: %s" % cmd)
        ssh_tool.executeCommand(cmd, "distribute roach tools", DefaultValue.SUCCESS, host_list)
        logger.debug("Successfully distribute roach tools.")

    @staticmethod
    def distribute_hot_patch(sshTool, appPath, hostList):
        """
        Distribution of hotpatch file to target hosts.

        :param sshTool:     SSH Tool instance.
        :param appPath:     Database application path.
        :param hostList:    The list of host.

        :type sshTool:      gspylib.threads.SshTool.SshTool
        :type appPath:      str
        :type hostList:     list
        """
        patch_file_path = os.path.join(appPath, "hotpatch", "pat")

        if os.path.exists(patch_file_path) and \
                os.listdir(patch_file_path):
            cmd = "mkdir -p '%s' -m %s" % \
                  (patch_file_path, DefaultValue.KEY_DIRECTORY_MODE)
            sshTool.executeCommand(cmd,
                                   "create hot Patch dir",
                                   DefaultValue.SUCCESS,
                                   hostList)

            src_patch_path = "%s/*" % patch_file_path
            dest_patch_path = "'%s'/" % patch_file_path
            sshTool.scpFiles(src_patch_path, dest_patch_path, hostList)

        libhotpatch_ext = os.path.join(appPath, 'lib/libhotpatch_ext.so')
        if os.path.exists(libhotpatch_ext):
            sshTool.scpFiles(libhotpatch_ext, os.path.join(appPath, 'lib'), hostList)

    @staticmethod
    def cleanFile(fileName, hostname=""):
        """
        function : remove file
        input : String,hostname
        output : NA
        """
        fileList = fileName.split(",")

        cmd = ""
        for fileName in fileList:
            deleteCmd = g_file.SHELL_CMD_DICT["deleteFile"] % (fileName, fileName)
            if cmd != "":
                cmd += ';%s' % deleteCmd
            else:
                cmd = deleteCmd

        if ("" != hostname and socket.gethostname() != hostname):
            cmd = g_OSlib.getSshCommand(hostname, cmd)
        DefaultValue.execCommandLocally(cmd)

    @staticmethod
    def cleanUserEnvVariable(userProfile, cleanGAUSS_WARNING_TYPE=False):
        """
        function : Clean the user environment variable
        input : String,boolean
        output : NA
        """
        try:
            # check use profile
            if (os.path.exists(userProfile) and os.path.isfile(userProfile)):
                # clean version
                g_file.deleteLine(userProfile, "^\\s*export\\s*GAUSS_VERSION=.*$")
                # clean bin
                g_file.deleteLine(userProfile, "^\\s*export\\s*PATH=\\$GAUSSHOME\\/bin:\\$PATH$")
                # clean GAUSSHOME
                g_file.deleteLine(userProfile, "^\\s*export\\s*GAUSSHOME=.*$")
                g_file.deleteLine(userProfile, "^\\s*export\\s*PGHOST=.*$")
                # clean MALLOC_CONF
                g_file.deleteLine(userProfile, "^\\s*export\\s*MALLOC_CONF=.*$")
                # clean GAUSSLOG
                g_file.deleteLine(userProfile, "^\\s*export\\s*GAUSSLOG=.*$")
                # clean S3_ACCESS_KEY_ID
                g_file.deleteLine(userProfile, "^\\s*export\\s*S3_ACCESS_KEY_ID=.*$")
                # clean S3_SECRET_ACCESS_KEY
                g_file.deleteLine(userProfile, "^\\s*export\\s*S3_SECRET_ACCESS_KEY=.*$")
                # clean S3_CLIENT_CRT_FILE
                g_file.deleteLine(userProfile, "^\\s*export\\s*S3_CLIENT_CRT_FILE=.*$")
                # clean ETCD_UNSUPPORTED_ARCH
                g_file.deleteLine(userProfile, "^\\s*export\\s*ETCD_UNSUPPORTED_ARCH=.*$")

                if (cleanGAUSS_WARNING_TYPE):
                    # clean extension connector environment variable
                    # because only deleting env_ec in postinstall, put it with GAUSS_WARNING_TYPE
                    g_file.deleteLine(userProfile, "^if \[ -f .*\/env_ec")
                    # clean GAUSS_WARNING_TYPE
                    g_file.deleteLine(userProfile, "^\\s*export\\s*GAUSS_WARNING_TYPE=.*$")

                # clean GS_CLUSTER_NAME
                g_file.deleteLine(userProfile, "^\\s*export\\s*GS_CLUSTER_NAME=.*$")
            if os.path.exists('/var/chroot/') and os.path.exists('/rds/datastore/'):
                g_file.deleteLine(userProfile, "^\\s*export\\s*LD_LIBRARY_PATH=\\$GAUSSHOME\\/lib:\\$LD_LIBRARY_PATH$")
                g_file.deleteLine(userProfile,
                                  "^\\s*export\\s*LD_LIBRARY_PATH=\\$GAUSSHOME"
                                  "\\/lib\\/libsimsearch:\\$LD_LIBRARY_PATH$")
                g_file.deleteLine(userProfile, "^\\s*export\\s*LD_LIBRARY_PATH=\\$LD_LIBRARY_PATH:\\$GAUSSHOME\\/lib$")
                g_file.deleteLine(userProfile,
                                  "^\\s*export\\s*LD_LIBRARY_PATH=\\$LD_LIBRARY_PATH:"
                                  "\\$GAUSSHOME\\/lib\\/libsimsearch$")
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def set_env_variable_depended(userProfile, env):
        """
        Sets the environment variable on which LD_LIBRARY_PATH depends. such as: GPHOME, GAUSSHOME
        :param userProfile:
        :param env:
        :return:
        """
        cmd = "grep -En '^\\s*export\\s*LD_LIBRARY_PATH=.*' %s" % userProfile
        (status, output) = subprocess.getstatusoutput(cmd)
        if status == 0:
            line_num = output.strip().split(":")[0]
            set_cmd = "sed -i '%si %s' %s" % (line_num, env, userProfile)
            (status, output) = subprocess.getstatusoutput(set_cmd)
            if status != 0:
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50205"] % userProfile + " Error: \n%s" % output)
        else:
            g_file.writeFile(userProfile, [env])

    @staticmethod
    def setComponentEnvVariable(userProfile, envList):
        """
        function: Set component environment variable
        input: userProfile- env file, envList - environment variable list
        output: NA
        """
        # at aarch64 platform, set ETCD_UNSUPPORTED_ARCH=arm64
        # else, set export ETCD_UNSUPPORTED_ARCH=386
        arch = "arm64" if platform.machine() == "aarch64" else "386"
        try:
            flags = os.O_WRONLY | os.O_CREAT | os.O_APPEND
            modes = stat.S_IWUSR | stat.S_IRUSR
            with os.fdopen(os.open(userProfile, flags, modes), "a") as fp:
                for inst_env in envList:
                    fp.write(inst_env)
                    fp.write(os.linesep)
                fp.write("export ETCD_UNSUPPORTED_ARCH=%s" % arch)
                fp.write(os.linesep)
        except Exception as e:
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50205"] % userProfile + " Error: \n%s" % str(e))

    @staticmethod
    def setUserEnvVariable(userProfile, installPath, tmpPath, clusterName, logPath):
        """
        function : Set the user environment variable
        input : String,String,String,,String,String
        output : NA
        """
        env_info = "export GAUSSHOME=%s" % installPath
        DefaultValue.set_env_variable_depended(userProfile, env_info)
        envList = ["export PATH=$GAUSSHOME/bin:$PATH",
                   "export S3_CLIENT_CRT_FILE=$GAUSSHOME/lib/client.crt",
                   "export GAUSS_VERSION=%s" % VersionInfo.getPackageVersion(),
                   "export PGHOST=%s" % tmpPath,
                   "export GS_CLUSTER_NAME=%s" % clusterName,
                   "export GAUSSLOG=%s" % logPath]
        if os.path.exists('/var/chroot/') and os.path.exists('/rds/datastore/') and \
                not DefaultValue.is_os_with_conflicting_so_libraries():
            envList.append("export LD_LIBRARY_PATH=$GAUSSHOME/lib:$LD_LIBRARY_PATH")
            envList.append("export LD_LIBRARY_PATH=$GAUSSHOME/lib/libsimsearch:$LD_LIBRARY_PATH")
        DefaultValue.setComponentEnvVariable(userProfile, envList)

    @staticmethod
    def updateUserEnvVariable(userProfile, variable, value):
        """
        function : Update the user environment variable
        input : String,String,String
        output : NA
        """
        try:
            # delete old env information
            deleteContent = "^\\s*export\\s*%s=.*$" % variable
            g_file.deleteLine(userProfile, deleteContent)
            # write the new env information into userProfile
            writeContent = ['export %s=%s' % (variable, value)]
            g_file.writeFile(userProfile, writeContent)
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def create_tmp_ca_file_dir(ssh_tool, ca_path, host_list, ca_type=""):
        """
        function : create the tmp dir of ca file
        input : config file path and ca dir path
        output : NA
        """
        openssl_file = os.path.join(os.path.dirname(ca_path), "grpc/openssl.cnf")
        if not os.path.isfile(openssl_file):
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % openssl_file)

        if ca_type == "scheduler":
            demo_path = os.path.join(ca_path, "demoCA")
            cmd = "rm -rf %s && mkdir %s -m 700" % (ca_path, ca_path)
        else:
            tmp_file = os.path.join(os.path.abspath(os.path.join(ca_path, "../..")), "openssl.cnf")
            # not rename file, just move it out and clean the dir, then move back
            cmd = g_file.SHELL_CMD_DICT["renameFile"] % (openssl_file, openssl_file, tmp_file)
            cmd += " && " + g_file.SHELL_CMD_DICT["cleanDir"] % (ca_path, ca_path, ca_path)
            cmd += " && " + g_file.SHELL_CMD_DICT["renameFile"] % (tmp_file, tmp_file, openssl_file)
        ssh_tool.executeCommand(cmd, "move file and clean dir", DefaultValue.SUCCESS, host_list)

        # create ./demoCA/newcerts ./demoCA/private
        demo_path = os.path.join(ca_path, "demoCA")
        new_certs_path = os.path.join(demo_path, "newcerts")
        g_file.createDirectory(new_certs_path)
        private_path = os.path.join(demo_path, "private")
        g_file.createDirectory(private_path)
        # touch files: ./demoCA/serial ./demoCA/index.txt
        ser_file = os.path.join(demo_path, "serial")
        g_file.createFile(ser_file)
        g_file.writeFile(ser_file, ["01"])
        index_file = os.path.join(demo_path, "index.txt")
        g_file.createFile(index_file)
        # copy openssl.cnf
        new_openssl_file = os.path.join(demo_path, "openssl.cnf")
        cmd = "cp -f %s %s" % (openssl_file, new_openssl_file)
        DefaultValue.execCommandLocally(cmd)

    @staticmethod
    def change_openssl_file(conf_file, host_list):
        """
        function : change the openssl.cnf file
        input : confFile, hostList
        output : NA
        """
        # Clean the old content.
        line_list = g_file.readFile(conf_file)
        for i in range(len(line_list)):
            if "[" in line_list[i] and "alt_names" in line_list[i] and "]" in line_list[i]:
                row = i + 1
                g_file.deleteLineByRowNum(conf_file, row)
            if "DNS." in line_list[i] and "=" in line_list[i]:
                g_file.deleteLineByRowNum(conf_file, row)
        # Add new one.
        dns_list = ["\n", "[ alt_names ]", "DNS.1 = localhost"]
        cont = 2
        for host in host_list:
            dns = f"DNS.{str(cont)} = {host}"
            dns_list.append(dns)
            cont = cont + 1
        g_file.writeFile(conf_file, dns_list)

    @staticmethod
    def judge_num(num):
        """
        function : judge num contains upper lower and digits
        input : num
        output : NA
        """
        pattern = re.compile('[A-Z]+')
        match = pattern.findall(num)
        if match:
            pattern = re.compile('[a-z]+')
            match = pattern.findall(num)
            if match:
                pattern = re.compile('[0-9]+')
                match = pattern.findall(num)
                if match:
                    return True
                return False
            return False
        else:
            return False

    @staticmethod
    def generate_random_num(num):
        """
        function : generate random password
        input : random num
        output : NA
        """
        try:
            while True:
                secrets_generator = secrets.SystemRandom()
                random_num = ''.join([secrets_generator.choice(string.ascii_letters + string.digits)
                                      for _ in range(num)])
                if DefaultValue.judge_num(random_num):
                    break
        except Exception as ex:
            raise Exception(str(ex))
        return random_num

    @staticmethod
    def create_ca2(ca_path, random_num, logger):
        """
        function: create ca file
        input: ca dir
        output: NA
        """
        cmd = g_Platform.getCdCmd(ca_path)
        cmd += " && export LD_LIBRARY_PATH=$GAUSSHOME/lib:$LD_LIBRARY_PATH"
        cmd += " && openssl ca -config demoCA/openssl.cnf -batch -in demoCA/server.req -out demoCA/server.crt "
        logger.debug(cmd)
        DefaultValue.execCommandLocally(cmd)

        cmd = g_Platform.getCdCmd(ca_path)
        cmd += " && export LD_LIBRARY_PATH=$GAUSSHOME/lib:$LD_LIBRARY_PATH"
        cmd += " && openssl genrsa -aes256 -passout pass:\"%s\" -out demoCA/client.key %s" % (
            random_num, DefaultValue.DEFAULT_BITS_NUM)
        cmd += " && openssl req -passin pass:\"%s\" -config demoCA/openssl.cnf -batch -new " \
               "-key demoCA/client.key -out demoCA/client.req " % random_num
        cmd += " && openssl ca -config demoCA/openssl.cnf -batch -in demoCA/client.req -out demoCA/client.crt"
        cmd_log = cmd.replace(random_num, "******")
        logger.debug(cmd_log)
        DefaultValue.execCommandLocally(cmd)

        # gs_guc set grpc sever key and client key
        userProfile = DefaultValue.getMpprcFile()
        demo_path = os.path.join(ca_path, "demoCA")
        cmd = g_Platform.getCdCmd(demo_path)
        cmd += " && %s %s;gs_guc encrypt -M server -K \"%s\" -D ." % \
               (g_Platform.getSourceCmd(), userProfile, random_num)
        cmd += ";gs_guc encrypt -M client -K \"%s\" -D ." % random_num
        cmd_log = cmd.replace(random_num, "******")
        logger.debug(cmd_log)
        DefaultValue.execCommandLocally(cmd)

    @staticmethod
    def create_ca_file(ca_path, logger):
        """
        function : create ca file
        input : ca file type and ca dir path
        output : NA
        """
        random_num = DefaultValue.generate_random_num(14)
        cmd = g_Platform.getCdCmd(ca_path)
        cmd += " && export LD_LIBRARY_PATH=$GAUSSHOME/lib:$LD_LIBRARY_PATH"
        cmd += " && openssl genrsa -out demoCA/private/cakey.pem %s" % DefaultValue.DEFAULT_BITS_NUM
        cmd += " && openssl req -config demoCA/openssl.cnf " \
               "-batch -new -key demoCA/private/cakey.pem -out demoCA/careq.pem "
        cmd += " && openssl ca -config demoCA/openssl.cnf " \
               "-batch -out demoCA/cacert.pem -keyfile demoCA/private/cakey.pem -selfsign -infiles demoCA/careq.pem"
        logger.debug(cmd)
        DefaultValue.execCommandLocally(cmd)

        cmd = g_Platform.getCdCmd(ca_path)
        cmd += " && export LD_LIBRARY_PATH=$GAUSSHOME/lib:$LD_LIBRARY_PATH"
        cmd += " && openssl genrsa -aes256 -passout pass:\"%s\" -out demoCA/server.key %s" % (
            random_num, DefaultValue.DEFAULT_BITS_NUM)
        cmd += " && openssl req -passin pass:\"%s\" -config demoCA/openssl.cnf -batch -new " \
               "-key demoCA/server.key -out demoCA/server.req " % random_num
        cmd_log = cmd.replace(random_num, "******")
        logger.debug(cmd_log)
        DefaultValue.execCommandLocally(cmd)

        index_attr_file = os.path.join(ca_path, "demoCA/index.txt.attr")
        if os.path.isfile(index_attr_file):
            g_file.replaceFileLineContent("unique_subject = yes", "unique_subject = no", index_attr_file)
        else:
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % index_attr_file)
        DefaultValue.create_ca2(ca_path, random_num, logger)

    @staticmethod
    def modifyFileOwner(user, currentfile):
        """
        function : Modify the file's owner
        input : String,String
        output : String
        """
        # only root user can run this function
        if (os.getuid() == 0):
            try:
                g_OSlib.getGroupByUser(user)
            except Exception as e:
                raise Exception(str(e))
            if os.path.exists(currentfile):
                g_file.changeOwner(user, currentfile)

    @staticmethod
    def modifyFileOwnerFromGPHOME(currentfile):
        """
        function : Modify the file's owner to the GPHOME's user
        input : String,String
        output : String
        """
        GPHOME = DefaultValue.getEnv(DefaultValue.TOOL_PATH_ENV)
        if (GPHOME is None or GPHOME == ""):
            raise Exception(ErrorCode.GAUSS_518["GAUSS_51802"] % "GPHOME")
        (user, group) = g_OSlib.getPathOwner(GPHOME)
        if (user == "" or group == ""):
            raise Exception(ErrorCode.GAUSS_503["GAUSS_50308"])
        DefaultValue.modifyFileOwner(user, currentfile)

    @staticmethod
    def checkOutputFile(outputFile):
        """
        function : check the output file
        input : String
        output : NA
        """
        if (os.path.isdir(outputFile)):
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50210"] % "output file")
        # get parent directory of output file
        parent_dir = os.path.dirname(outputFile)
        if (os.path.isfile(parent_dir)):
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50211"] % "base directory of output file")

    @staticmethod
    def getAllIP(g_dbNodes):
        """
        function : Get all node IP. node and every instances haips and listenips
        input : list
        output : list
        """
        allIP = []
        for dbNode in g_dbNodes:
            allIP += dbNode.backIps
            allIP += dbNode.sshIps
            for dbInstance in dbNode.cmservers:
                allIP += dbInstance.haIps
                allIP += dbInstance.listenIps
            for dbInstance in dbNode.coordinators:
                allIP += dbInstance.haIps
                allIP += dbInstance.listenIps
            for dbInstance in dbNode.datanodes:
                allIP += dbInstance.haIps
                allIP += dbInstance.listenIps
            for dbInstance in dbNode.gtms:
                allIP += dbInstance.haIps
                allIP += dbInstance.listenIps
            for etcdInst in dbNode.etcds:
                allIP += etcdInst.haIps
                allIP += etcdInst.listenIps

        return allIP

    @staticmethod
    def KillAllProcess(userName, procName):
        """
        function : Kill all processes by userName and procName.
        input : userName, procName
        output : boolean
        """
        return g_OSlib.killallProcess(userName, procName, "9")

    @staticmethod
    def sendNetworkCmd(ip):
        """
        function : Send the network command of ping.
        input : String
        output : NA
        """
        cmd = "%s |%s ttl |%s -l" % \
              (g_Platform.getPingCmd(ip, "5", "1"), g_Platform.getGrepCmd(), g_Platform.getWcCmd())
        (status, output) = subprocess.getstatusoutput(cmd)
        if (str(output) == '0' or status != 0):
            g_lock.acquire()
            noPassIPs.append(ip)
            g_lock.release()

    @staticmethod
    def checkIsPing(ips):
        """
        function : Check the connection status of network.
        input : []
        output : []
        """
        global noPassIPs
        noPassIPs = []
        parallelTool.parallelExecute(DefaultValue.sendNetworkCmd, ips)
        return noPassIPs

    @staticmethod
    def retryGetstatusoutput(cmd, retryTime=3, sleepTime=1):
        """
        function : retry getStatusoutput
        @param cmd: command  going to be execute
        @param retryTime: default retry 3 times after execution failure
        @param sleepTime: default sleep 1 second then start retry
        """
        retryTime += 1
        status = 0
        output = ""
        for _ in range(retryTime):
            (status, output) = subprocess.getstatusoutput(cmd)
            if status != 0:
                time.sleep(sleepTime)
            else:
                break
        return status, output

    @staticmethod
    def retryRedisCmd(cmd, retryTime=3, sleepTime=5):
        """
        function : retry redis cmd considering the return value
        @param cmd: redis command going to be execute
        @param retryTime: default retry 3 times after execution failure
        @param sleepTime: default sleep 1 second then start retry
        """
        # gs_redis can return value:
        # 0: REDIS_SUCCEED, redistribute success. (of course not need retry)
        # 1: REDIS_TIMEOUT_RETRY, redistribute timeout and need retry
        # 2: REDIS_FAIL_RETRY, redistribute failed and need retry
        # 3: REDIS_FAIL_NORETRY, redistribute failed and not need retry
        status = 0
        output = ""
        for _ in range(retryTime):
            (status, output) = subprocess.getstatusoutput(cmd)
            if status == 0 or status == 3:
                break
            else:
                time.sleep(sleepTime)
        return status, output

    @staticmethod
    def killInstProcessCmd(instName, isRemote=False, signal=9, isExactMatch=True,
                           instType="", procAbsPath="", instDir="", appPath=""):
        """
        instName: process name
        isRemote: do it under remote machine. default is false
        signal  : kill signle. default is 9
        isExactMatch: the match rule. default is exact match
        instType: instance type. default is "", now only support for get coordinator instance
        procAbsPath: process abs path. default is ""
        instDir: instance data directory. default is ""
        """
        # only cm_server need kill all child process, when do kill -9
        search_key = os.path.join(appPath, 'bin', instName) if appPath else instName
        if instName in ["cm_server", "gs_checkperf"] and signal == 9:
            if isRemote:
                cmd = "pidList=\`ps ux | grep -w '%s' | grep -v 'grep' | awk '{print \$2}' | xargs \`; " \
                      "for pid in \$pidList; do pstree -alnp \$pid | awk -F ',' '{print \$2}' | awk '{print \$1}' | " \
                      "xargs -r -n 100 kill -9; echo 'SUCCESS'; done" % instName
                # only try to kill -9 process of cmserver
                cmd += "; ps ux | grep -w '%s' | grep -v grep | awk '{print \$2}' | " \
                       "xargs -r kill -9; echo 'SUCCESS'" % instName
            else:
                cmd = "pidList=`ps ux | grep -w '%s' | grep -v 'grep' | awk '{print $2}' | " \
                      "xargs `; for pid in $pidList; do pstree -alnp $pid | awk -F ',' '{print $2}' | " \
                      "awk '{print $1}' | xargs -r -n 100 kill -9; echo 'SUCCESS'; done" % instName
                cmd += "; ps ux | grep -w '%s' | grep -v grep | awk '{print $2}' | " \
                       "xargs -r kill -9; echo 'SUCCESS'" % instName
            return cmd

        if "" != instType and "" != procAbsPath and "" != instDir:
            if isRemote:
                cmd = "ps ux | grep '\<%s\>' | grep '%s' | grep '%s' | grep -v grep | " \
                      "awk '{print \$2}' | xargs -r kill -%d " % \
                      (instType, procAbsPath, instDir, signal)
            else:
                cmd = "ps ux | grep '\<%s\>' | grep '%s' | grep '%s' | grep -v grep | " \
                      "awk '{print $2}' | xargs -r kill -%d " % \
                      (instType, procAbsPath, instDir, signal)
        else:
            if isExactMatch:
                if isRemote:
                    cmd = "ps ux | grep '\<%s\>' | grep -v grep | awk '{print \$2}' | xargs -r kill -%d " % \
                          (search_key, signal)
                else:
                    cmd = "ps ux | grep '\<%s\>' | grep -v grep | awk '{print $2}' | xargs -r kill -%d " % \
                          (search_key, signal)
            else:
                if isRemote:
                    cmd = "ps ux | grep '%s' | grep -v grep | awk '{print \$2}' | xargs -r kill -%d " % \
                          (search_key, signal)
                else:
                    cmd = "ps ux | grep '%s' | grep -v grep | awk '{print $2}' | xargs -r kill -%d " % \
                          (search_key, signal)
        return cmd

    @staticmethod
    def getRuningInstNum(procAbsPath, instDir=""):
        """
        """
        if (instDir):
            cmd = "ps ux | grep '%s' | grep '%s' | grep -v grep | wc -l" % (procAbsPath, instDir)
        else:
            cmd = "ps ux | grep '%s' | grep -v grep | wc -l" % (procAbsPath)
        return cmd

    @staticmethod
    def execRemoteCmd(sshTool, cmd, nodeNames):
        """
        """
        # Retry 10 times for running the command.
        retryCounts = 10
        output = ""
        while retryCounts > 0:
            (status, output) = sshTool.getSshStatusOutput(cmd, nodeNames)
            failedNodes = []
            for node in nodeNames:
                if status[node] != DefaultValue.SUCCESS:
                    failedNodes.append(node)
            nodeNames = failedNodes
            if len(nodeNames) == 0:
                break
            time.sleep(1)
            retryCounts -= 1
        if retryCounts == 0:
            raise Exception(output)

    @staticmethod
    def killCmserverProcess(sshTool, cmsInsts, appPath=""):
        # Restart the instance CMSERVERS
        if (len(cmsInsts) == 1 and cmsInsts[0].hostname == socket.gethostname()):
            cmd = DefaultValue.killInstProcessCmd("cm_server", False, 1, appPath=appPath)
            (status, output) = DefaultValue.retryGetstatusoutput(cmd)
            if (status != 0):
                raise Exception(output)
        else:
            cmd = DefaultValue.killInstProcessCmd("cm_server", True, 1, appPath=appPath)
            DefaultValue.execRemoteCmd(sshTool, cmd, [cmsInst.hostname for cmsInst in cmsInsts])
        time.sleep(3)

    @staticmethod
    def setCmInstanceParameter(logger, clusterInfo, user, sshTool, mode="close", hostList=None, abNormalCms=None,
                               abNormalGtms=None, gucSet=False, operationName=""):
        """
        function: close or restore cmserver instance parameter
        [coordinator_heartbeat_timeout,enable_transaction_read_only]
        @param clusterInfo: the cluster information
        @param user: the cluster user
        @param mode: set mode, close:  close the parameter
                               restore: restore the parameter
        @param sshTool: the sshtool to distribute or remove backupfile
        @param hostList: which hostlist sshTool use
        @param abNormalCms:  the damaged cm which we won't connect
        """
        logger.debug("Starting to %s cm instance parameters." % mode)

        if hostList is None:
            hostList = []
        # Localhost may not in the hostlist so add it(for gs_replace)
        loacalHostName = socket.gethostname()
        if loacalHostName not in hostList:
            hostList.append(loacalHostName)

        # Parameters to be set during the execution of the operation
        cmsParameter = {"coordinator_heartbeat_timeout": "0",
                        "enable_transaction_read_only": "on",
                        "datastorage_threshold_value_check": "95"}
        gtmParameter = {"enable_connect_control": "off"}
        # In the expansion scence, The default parameter[instance_heartbeat_timeout]
        # value of 15s will misjudge cn exception,
        # cmagent executes pg_pool_validate(true, 'cn_xx'), and cancel lock process,
        # so set the parameter[instance_heartbeat_timeout] timeout time to 60.
        if len(clusterInfo.newNodes) > 0:
            cmsParameter['instance_heartbeat_timeout'] = 60
        tmpDir = DefaultValue.getTmpDirFromEnv(user)
        flag = "cm_server"
        if operationName != "":
            flag = "%s_cm_server" % operationName
        tmpFileBefore = os.path.join(tmpDir, "%s_before.json" % flag)
        tmpFile = os.path.join(tmpDir, "%s.json" % flag)

        # Get the cm list and remove the damaged cm
        cmInsts = []
        gtmInsts = []
        gtmHostnames = []
        for node in clusterInfo.dbNodes:
            for inst in node.cmagents:
                if hostList and node.name not in hostList:
                    continue
                if abNormalCms is not None:
                    if not abNormalCms.__contains__(inst.hostname):
                        cmInsts.append(inst)
                else:
                    cmInsts.append(inst)
            for inst in node.gtms:
                if abNormalGtms is not None:
                    if not abNormalGtms.__contains__(inst.hostname):
                        gtmHostnames.append(inst.hostname)
                        gtmInsts.append(inst)
                else:
                    gtmHostnames.append(inst.hostname)
                    gtmInsts.append(inst)

        logger.debug("cmInsts:%s,gtmInsts:%s,gtmHostnames:%s." % (cmInsts, gtmInsts, gtmHostnames))

        # get current parameter of [coordinator_heartbeat_timeout] and [datastorage_threshold_value_check]
        if mode == "close":
            DefaultValue.closeCmInstanceParameter(tmpFileBefore,
                                                  tmpFile,
                                                  cmsParameter,
                                                  cmInsts,
                                                  gtmParameter,
                                                  gtmInsts,
                                                  clusterInfo,
                                                  sshTool,
                                                  hostList,
                                                  gucSet,
                                                  gtmHostnames,
                                                  logger)
        # Restoring previously set parameters by copying the backup file
        elif mode == "restore":
            DefaultValue.restoreCmInstanceParameter(tmpFile,
                                                    cmInsts,
                                                    loacalHostName,
                                                    sshTool,
                                                    hostList,
                                                    gtmParameter,
                                                    gucSet,
                                                    gtmHostnames,
                                                    clusterInfo,
                                                    logger)

        logger.debug("Successfully %s cm instance parameters." % mode)

    @staticmethod
    def closeCmInstanceParameter(tmpFileBefore, tmpFile, cmsParameter, cmInsts, gtmParameter, gtmInsts, clusterInfo,
                                 sshTool, hostList, gucSet, gtmHostnames, logger):
        """
        function: close cmserver instance parameter [coordinator_heartbeat_timeout,enable_transaction_read_only]
        input : string,string,dict,[]
        output : na
        """
        oldGUCparas = {}
        # get cm guc parameter
        if os.path.isfile(tmpFileBefore):
            oldGUCparas = g_file.parseJsonFile(tmpFileBefore)
        else:
            oldCMGUCparas = DefaultValue.getParaValueFromConfigFile(list(cmsParameter.keys()), cmInsts)
            oldGTMGUCparas = DefaultValue.getParaValueFromConfigFile(list(gtmParameter.keys()), gtmInsts,
                                                                     instType="gtm")
            oldGUCparas.update(oldCMGUCparas)
            if (oldGTMGUCparas.__contains__('enable_connect_control') and
                    oldGTMGUCparas['enable_connect_control'] != "off"):
                oldGUCparas.update(oldGTMGUCparas)
            # Save the parameters to a file
            g_file.generateJsonFile(tmpFileBefore, oldGUCparas)

        if not clusterInfo.isSingleCluster():
            sshTool.scpFiles(tmpFileBefore, os.path.dirname(tmpFileBefore) + "/", hostList)

        logger.debug("oldGUCparas:%s." % oldGUCparas)

        # close the parameter command and execute command
        cm_guc_list = []
        for (key, value) in cmsParameter.items():
            cm_guc_list.append("-c '%s=%s'" % (key, value))

        if cm_guc_list:
            cmd = "gs_guc %s -Z cm -D cm_instance_data_path %s" % \
                  ("set" if gucSet else "reload", " ".join(cm_guc_list))
            logger.debug("Command to set cm guc:%s." % cmd)
            sshTool.executeCommand(cmd, "set guc parameter for CM ", DefaultValue.SUCCESS,
                                   [cmInst.hostname for cmInst in cmInsts])

        # set gtm para
        gtm_guc_list = []
        for key in gtmParameter.keys():
            if oldGUCparas.__contains__(key):
                gtm_guc_list.append("-c '%s=%s'" % (key, gtmParameter[key]))

        if gtm_guc_list:
            cmd = "gs_guc %s -Z gtm -I all %s" % \
                  ("set" if gucSet else "reload", " ".join(gtm_guc_list))
            logger.debug("Command to set gtm guc:%s." % cmd)
            sshTool.executeCommand(cmd, "set guc parameter for GTM ",
                                   DefaultValue.SUCCESS, gtmHostnames)

        # change file name
        cmd = g_file.SHELL_CMD_DICT["renameFile"] % (tmpFileBefore, tmpFileBefore, tmpFile)
        sshTool.executeCommand(cmd, "rename CMServer parameters file", hostList=hostList)
        # kill cmserver process
        DefaultValue.killCmserverProcess(sshTool, cmInsts, clusterInfo.appPath)

    @staticmethod
    def restoreCmInstanceParameter(tmpFile, cmInsts, loacalHostName, sshTool, hostList, gtmParameter, gucSet,
                                   gtmHostnames, clusterInfo, logger):
        """
        function: restore cmserver instance parameter [coordinator_heartbeat_timeout,enable_transaction_read_only]
        input : string,string,dict,[]
        output : na
        """
        if not os.path.isfile(tmpFile):
            for cmInst in cmInsts:
                cmd = "if [ -f '%s' ];then export LD_LIBRARY_PATH=/lib64:$LD_LIBRARY_PATH; scp '%s' %s:'%s';fi" % \
                      (tmpFile, tmpFile, g_network.makeSCPHost(loacalHostName), tmpFile)
                _, _ = sshTool.getSshStatusOutput(cmd, [cmInst.hostname])

        if not os.path.isfile(tmpFile):
            logger.debug("%s does not exists." % tmpFile)
            return

        oldGUCparas = g_file.parseJsonFile(tmpFile)
        if len(oldGUCparas.keys()) == 0:
            cmd = g_file.SHELL_CMD_DICT["deleteFile"] % (tmpFile, tmpFile)
            sshTool.executeCommand(cmd, "remove CMServer parameters file", hostList=hostList)
            logger.debug("%s is empty." % tmpFile)
            return

        # restore cmserver para
        cm_inst_hostnames = [cmInst.hostname for cmInst in cmInsts]
        for (key, value) in oldGUCparas.items():
            if key in gtmParameter.keys():
                continue
            # Determine whether the file exists for gs_replace:
            # If cm and another instance of a node damaged at the same time,cm configuration file does not exist,
            # Then start another node will be an error.This change does not affect other functions.
            if gucSet:
                cmd = "gs_guc set -Z cm -D cm_instance_data_path -c '%s=%s'" % (key, value)
            else:
                cmd = "gs_guc reload -Z cm -D cm_instance_data_path -c '%s=%s'" % (key, value)
            logger.debug("Command to set cm guc:%s." % cmd)
            sshTool.executeCommand(cmd, "set guc parameter for cm ", DefaultValue.SUCCESS, cm_inst_hostnames)

        # kill cmserver process
        DefaultValue.killCmserverProcess(sshTool, cmInsts, clusterInfo.appPath)

        # restore gtm para
        for key in gtmParameter.keys():
            if oldGUCparas.__contains__(key):
                if gucSet:
                    cmd = "gs_guc set -Z gtm -I all -c '%s=%s'" % (key, oldGUCparas[key])
                else:
                    cmd = "gs_guc reload -Z gtm -I all -c '%s=%s'" % (key, oldGUCparas[key])
                logger.debug("Command to set cm guc:%s." % cmd)
                sshTool.executeCommand(cmd, "set guc parameter for GTM ", DefaultValue.SUCCESS, gtmHostnames)

        cmd = g_file.SHELL_CMD_DICT["deleteFile"] % (tmpFile, tmpFile)
        if hostList:
            sshTool.executeCommand(cmd, "remove CMServer parameters file", hostList=hostList)
        else:
            sshTool.executeCommand(cmd, "remove CMServer parameters file")

    @staticmethod
    def getParaValueFromConfigFile(paraList, instList, instType="cm_server"):
        """
        function : Get guc parameter from config file for cm_server or gtm.
        input : paraList, instList, instType
        output : paraMap
        """
        paraMap = {}
        for para in paraList:
            for inst in instList:
                if instType == "cm_server":
                    configPath = DefaultValue.getCmConfigFile(inst.datadir)
                else:
                    configPath = os.path.join(inst.datadir, "%s.conf" % instType)
                (status, output) = DefaultValue.getMatchingResult("\<'%s'\>" % para,
                                                                  configPath, inst.hostname)
                if status != 0 and status != 1:
                    if instType == "gtm":
                        output = ""
                    else:
                        raise Exception(ErrorCode.GAUSS_502["GAUSS_50219"] % configPath + " Error:%s." % output)
                for line in output.split('\n'):
                    confInfo = line.strip()
                    if confInfo.startswith('#') or confInfo == "":
                        continue
                    elif confInfo.startswith(para):
                        configValue = confInfo.split('#')[0].split('=')[1].strip()
                        if paraMap.__contains__(para) and paraMap[para] != configValue:
                            raise Exception(ErrorCode.GAUSS_530["GAUSS_53011"] %
                                            "Parameter '%s', it is different in same level instance." % para)
                        paraMap[para] = configValue
                        break
        return paraMap

    @staticmethod
    def retry_gs_guc(cmd):
        """
        function : Retry 3 times when HINT error
        input : cmd
        output : NA
        """
        retryTimes = 0
        while True:
            (status, output) = subprocess.getstatusoutput(cmd)
            if (status == 0):
                break
            if (retryTimes > 1):
                raise Exception(ErrorCode.GAUSS_500["GAUSS_50008"] + " Error: \n%s" % str(output))
            retryTimes = retryTimes + 1
            time.sleep(3)

    @staticmethod
    def distributePackagesToRemote(g_sshTool, srcPackageDir, destPackageDir,
                                   hostname, mpprcFile, logger):
        '''
        function: distribute the package to remote nodes
        input: g_sshTool, hostname, srcPackageDir, destPackageDir, mpprcFile, clusterType
        output:NA
        '''
        try:
            # check the destPackageDir is existing on hostname
            DefaultValue.checkRemoteDir(g_sshTool, destPackageDir, hostname, mpprcFile)

            # Send compressed package to every host
            g_sshTool.scpFiles("%s/%s" % (srcPackageDir, DefaultValue.PACKAGE_BACK_NAME),
                               destPackageDir, hostname, mpprcFile)
            logger.debug("Sending %s/%s to %s." %
                         (srcPackageDir, DefaultValue.PACKAGE_BACK_NAME, destPackageDir))
            # Decompress package on every host
            srcPackage = "'%s'/'%s'" % (destPackageDir, DefaultValue.PACKAGE_BACK_NAME)
            cmd = g_Platform.getDecompressFilesCmd(srcPackage, destPackageDir)
            logger.debug("Decompress cmd %s." % cmd)
            g_sshTool.executeCommand(cmd,
                                     "extract %s server package" % VersionInfo.PRODUCT_NAME,
                                     DefaultValue.SUCCESS,
                                     hostname,
                                     mpprcFile)
            # change owner and mode of packages
            destPath = "'%s'/*" % destPackageDir
            cmd = g_Platform.getChmodCmd(str(DefaultValue.MAX_DIRECTORY_MODE), destPath, True)
            logger.debug("Change mode cmd:%s." % cmd)

            # Note that:if chmod/chown -R failed by root user,this loop will retry 3 times,and just show exception message;
            for i in range(3):
                try:
                    logger.debug("Begin to change mode ,cmd is :%s." % cmd)
                    g_sshTool.executeCommand(cmd, "change permission", DefaultValue.SUCCESS, hostname, mpprcFile)
                except Exception as e:
                    # loop 3 times, if still wrong, just show exception message.
                    if i == 2:
                        logger.debug(str(e))
                    # If error, continue loop.
                    logger.debug("change mode failed,cmd is :%s. retry." % cmd)
                    continue
                # If chmod/chown success , exit loop.
                logger.debug("Successfully change mode. cmd is: %s " % cmd)
                break

        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def scp_files_to_remote(app_path, file_name, ssh_tool, host_list, retry_time=3):
        """
        """
        bin_path = "%s/bin/" % app_path
        for i in range(retry_time):
            try:
                ssh_tool.scpFiles(file_name, bin_path, host_list)
                break
            except Exception as e:
                if i < retry_time - 1:
                    continue
                else:
                    raise Exception(str(e))

    @staticmethod
    def distribute_file_to_remote(app_path, file_name, ssh_tool, host_list):
        """
        """
        if os.path.isfile(file_name):
            # skip local host
            remote_list = copy.deepcopy(host_list)
            local_name = socket.gethostname()
            if local_name in remote_list:
                remote_list.remove(local_name)
            if len(remote_list) > 0:
                # modify local file from 400 to 700
                cmd = g_Platform.getChmodCmd(str(DefaultValue.KEY_DIRECTORY_MODE), file_name)
                DefaultValue.execCommandLocally(cmd)
                # delete the remote file
                cmd = g_file.SHELL_CMD_DICT["deleteFile"] % (file_name, file_name)
                ssh_tool.executeCommand(cmd, "clean remote file", DefaultValue.SUCCESS, remote_list)
                # scp local file to remote
                DefaultValue.scp_files_to_remote(app_path, file_name, ssh_tool, remote_list)
                # modify remote file from 700 to 400
                cmd = g_Platform.getChmodCmd(str(DefaultValue.MIN_FILE_MODE), file_name)
                ssh_tool.executeCommand(cmd, "change permission", DefaultValue.SUCCESS, remote_list)
                # modify local file from 700 to 400
                DefaultValue.execCommandLocally(cmd)

    @staticmethod
    def distributeObsserverkeyFile(appPath, sshTool, hostList):
        '''
        function: Distribute obs server key file to the node of hostList
        input : appPath, sshTool, hostList
        output: NA
        '''
        installBinPath = "%s/bin" % appPath
        obsserverKeyCipher = os.path.join(installBinPath, "obsserver.key.cipher")
        obsserverKeyRand = os.path.join(installBinPath, "obsserver.key.rand")
        if not os.path.exists(obsserverKeyCipher) or not os.path.exists(obsserverKeyRand):
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % "obs server key files" + " Please check it.")
        try:
            for file_name in [obsserverKeyCipher, obsserverKeyRand]:
                DefaultValue.distribute_file_to_remote(appPath, file_name, sshTool, hostList)
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def distributeTransEncryptFile(appPath, sshTool, hostList):
        '''
        function: Distribute trans encrypt file to the node of hostList
        input : appPath, sshTool, hostList
        output: NA
        '''
        try:
            installBinPath = "%s/bin" % appPath
            transEncryptKeyCipher = os.path.join(installBinPath, "trans_encrypt.key.cipher")
            transEncryptKeyRand = os.path.join(installBinPath, "trans_encrypt.key.rand")
            transEncryptKeyAkSk = os.path.join(installBinPath, "trans_encrypt_ak_sk.key")
            for file_name in [transEncryptKeyCipher, transEncryptKeyRand, transEncryptKeyAkSk]:
                DefaultValue.distribute_file_to_remote(appPath, file_name, sshTool, hostList)
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def distributeXmlConfFile(g_sshTool, confFile, hostname=None, mpprcFile="", localMode=False):
        '''
        function: distribute the confFile to remote nodes
        input: g_sshTool, hostname, confFile, mpprcFile
        output:NA
        '''
        if hostname is None:
            hostname = []
        try:
            # distribute xml file
            # check and create xml file path
            xmlDir = os.path.dirname(confFile)
            xmlDir = os.path.normpath(xmlDir)
            DefaultValue.checkRemoteDir(g_sshTool, xmlDir, hostname, mpprcFile, localMode)

            if (not localMode):
                # Send xml file to every host
                g_sshTool.scpFiles(confFile, xmlDir + "/", hostname, mpprcFile)
            # change owner and mode of xml file
            cmd = g_Platform.getChmodCmd(str(DefaultValue.FILE_MODE), confFile)
            DefaultValue.execCommandWithMode(cmd,
                                             "change permission",
                                             g_sshTool,
                                             localMode,
                                             mpprcFile,
                                             hostname)
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def cleanFileDir(dirName, g_sshTool=None, hostname=None):
        '''
        function: clean directory or file
        input: dirName, g_sshTool, hostname
        output:NA
        '''
        if hostname is None:
            hostname = []
        try:
            cmd = g_file.SHELL_CMD_DICT["deleteDir"] % (dirName, dirName)
            # If clean file or directory  on local node
            if (g_sshTool is None):
                (status, output) = subprocess.getstatusoutput(cmd)
                if (status != 0):
                    raise Exception(output)
            else:
                # Assign some remote node to clean directory or file.
                if hostname == []:
                    g_sshTool.executeCommand(cmd, "clean directory or file ")
                else:
                    g_sshTool.executeCommand(cmd, "clean directory or file ", DefaultValue.SUCCESS, hostname)
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def backupClusterParameterFile(backupDir, logFile="", config="", logAction="", logUuid="", logStep=0):
        '''
        function: backup cluster parameter file
        input: dirName, g_sshTool, hostname
        output:NA
        '''
        try:
            if logAction == "" or logUuid == "":
                raise Exception("Must set para of logAction and logUuid.")
            current_Path = os.path.dirname(os.path.realpath(__file__))
            DefaultValue.getEnvironmentParameterValue("GPHOME", "")
            scriptName = "python3 %s" % (os.path.normpath(current_Path + "/../../../gs_backup"))
            # do backup by gs_backup
            cmd = "%s -t backup --backup-dir=%s --parameter --uuid=%s --logAction=%s --logStep=%s" % (
                scriptName,
                backupDir,
                logUuid,
                logAction,
                logStep
            )
            if (logFile != ""):
                cmd += " -l %s" % logFile
            if config:
                cmd += " -X %s" % config

            (status, output) = subprocess.getstatusoutput(cmd)
            if (status != 0):
                raise Exception(output)
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def execCommandLocally(cmd):
        """
        function: exec only on local node
        input: cmd
        output: NA
        """
        # exec the cmd
        (status, output) = subprocess.getstatusoutput(cmd)
        # if cmd failed, then raise
        if (status != 0 and "[GAUSS-5" in str(output)):
            raise Exception(str(output))
        elif (status != 0):
            raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % str(cmd) + " Error: \n%s" % str(output))

    @staticmethod
    def execCommandWithMode(cmd, decript, g_sshTool, localMode=False, mpprcFile='', hostList=None):
        """
        function: check the mode, if local mode, exec only on local node, else exec on all nodes
        input: cmd, decript, g_sshTool, localMode, mpprcFile
        output: NA
        """
        if hostList is None:
            hostList = []
        # check the localMode
        if localMode:
            # localMode
            DefaultValue.execCommandLocally(cmd)
        else:
            # Non-native mode
            g_sshTool.executeCommand(cmd, decript, DefaultValue.SUCCESS, hostList, mpprcFile)

    @staticmethod
    def getDevices():
        """
        function: get device
        input: NA
        output: NA
        """
        cmd = "fdisk -l 2>/dev/null | grep \"Disk /dev/\" | grep -Ev \"/dev/mapper/|loop\" | " \
              "awk '{ print $2 }' | awk -F'/' '{ print $NF }' | sed s/:$//g"
        (status, output) = subprocess.getstatusoutput(cmd)
        if (status != 0):
            raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error: \n%s" % output)
        devList = output.split('\n')
        return devList

    @staticmethod
    def copyCAfile(sshTool, hostList):
        """
        function: copy CA file
        input: NA
        output: NA
        """
        try:
            user = pwd.getpwuid(os.getuid()).pw_name
            gaussHome = DefaultValue.getInstallDir(user)
            sslpath = "%s/share/sslcert/etcd/" % gaussHome
            caKeyFile = "%s/ca.key" % sslpath
            caCrtFile = "%s/etcdca.crt" % sslpath
            clientKeyFile = "%s/client.key" % sslpath
            clientCrtFile = "%s/client.crt" % sslpath
            if (os.path.exists(caKeyFile)):
                mkdirCmd = g_Platform.getMakeDirCmd(sslpath, True)
                changModeCmd = g_Platform.getChmodCmd(str(DefaultValue.KEY_DIRECTORY_MODE), sslpath)
                cmd = "%s && %s" % (mkdirCmd, changModeCmd)
                sshTool.executeCommand(cmd, "create CA path", DefaultValue.SUCCESS, hostList)
                sshTool.scpFiles(caKeyFile, sslpath, hostList)
                sshTool.scpFiles(caCrtFile, sslpath, hostList)
                sshTool.scpFiles(clientKeyFile, sslpath, hostList)
                sshTool.scpFiles(clientCrtFile, sslpath, hostList)
                cmd = g_Platform.getChmodCmd(str(DefaultValue.KEY_FILE_MODE), "%s %s" % (caKeyFile, caCrtFile))
                sshTool.executeCommand(cmd, "change permission", DefaultValue.SUCCESS, hostList)
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def copyLicenseFile(sshTool, hostList):
        """
        Copy license file to other host.

        :param sshTool:     The ssh tool instance.
        :param hostList:    The host list.

        :type sshTool:      SshTool
        :type hostList:     list

        :rtype: None
        """
        user = pwd.getpwuid(os.getuid()).pw_name
        gaussHome = DefaultValue.getInstallDir(user)
        binaryPath = os.path.join(gaussHome, "bin")
        licenseFilePath = os.path.join(binaryPath, DefaultValue.DEFAULT_LICENSE_FILE_NAME)
        if os.path.exists(licenseFilePath):
            sshTool.scpFiles(licenseFilePath, binaryPath + "/", hostList)

    @staticmethod
    def genCert(nodeip, etcddir, remoteip=""):
        """
        function: generate a certificate file for ETCD
        input : nodeip:backip, etcddir: the dir of etcd, remoteip:sship
        output: NA
        """
        user = pwd.getpwuid(os.getuid()).pw_name
        gaussHome = DefaultValue.getInstallDir(user)
        sslpath = "%s/share/sslcert/etcd" % gaussHome
        sslcfg = "%s/openssl.cnf" % sslpath
        tmp_Dir = "%s/demoCA" % sslpath
        try:
            # 1.clean file
            DefaultValue.cleanFileDir(tmp_Dir)

            # 2.generate server certificate and sign it
            # 3. create directory and copy files
            # 4.generate server certificate and sign it
            cmd = "%s" % g_Platform.getCdCmd(sslpath)
            # Create paths and files
            cmd += " && %s" % g_Platform.getMakeDirCmd("demoCA/newcerts", True)
            cmd += " && %s" % g_Platform.getMakeDirCmd("demoCA/private", True)
            cmd += " && %s" % g_Platform.getChmodCmd(str(DefaultValue.KEY_DIRECTORY_MODE), "demoCA/newcerts")
            cmd += " && %s" % g_Platform.getChmodCmd(str(DefaultValue.KEY_DIRECTORY_MODE), "demoCA/private")
            cmd += " && %s" % g_Platform.getTouchCmd("demoCA/index.txt")
            cmd += " && echo '01' > demoCA/serial"
            cmd += " && export SAN=\"IP:%s\"" % nodeip
            cmd += " && %s " % g_Platform.getCopyCmd("ca.key", "demoCA/private/")
            cmd += " && %s " % g_Platform.getCopyCmd("etcdca.crt", "demoCA/")

            cmd += " && export LD_LIBRARY_PATH=$GAUSSHOME/lib:$LD_LIBRARY_PATH"
            cmd += " && openssl req -config '%s' -new -nodes -keyout '%s/etcd.key' -out '%s/etcd.csr' -subj '/CN=cn'" \
                   % (sslcfg, sslpath, sslpath)
            cmd += " && %s" % g_Platform.getCdCmd("demoCA")
            cmd += " && openssl ca -startdate 170101000000Z -config '%s' -extensions etcd_server " \
                   "-batch -keyfile '%s/demoCA/private/ca.key' -cert '%s/demoCA/etcdca.crt' " \
                   "-out '%s/etcd.crt' -infiles '%s/etcd.csr'" % \
                   (sslcfg, sslpath, sslpath, sslpath, sslpath)
            cmd += " && cd ../ && find . -type f | xargs chmod %s" % DefaultValue.KEY_FILE_MODE
            DefaultValue.execCommandLocally(cmd)

            # 5.copy etcd.srt to the ETCD directory
            etcdKeyFile = "%s/etcd.key" % sslpath
            etcdCrtFile = "%s/etcd.crt" % sslpath
            # copy the file to the ETCD directory
            etcddir = "%s/" % etcddir
            if (remoteip):
                g_OSlib.scpFile(remoteip, etcdKeyFile, etcddir)
                g_OSlib.scpFile(remoteip, etcdCrtFile, etcddir)
            else:
                g_file.cpFile(etcdKeyFile, etcddir)
                g_file.cpFile(etcdCrtFile, etcddir)
            cmd = "unset SAN"
            DefaultValue.execCommandLocally(cmd)
            DefaultValue.cleanFileDir(tmp_Dir)
        except Exception as e:
            DefaultValue.cleanFileDir(tmp_Dir)
            raise Exception(str(e))

    @staticmethod
    def replaceCertFilesToRemoteNode(cnNodeName, instanceList, cnInstDir):
        """
        function: This method is for replace SSL cert files
        input : cnNodeName, instanceList, cnInstDir
        output: NA
        """
        fileList = DefaultValue.CERT_ROLLBACK_LIST[:]
        for num in range(len(fileList)):
            fileList[num] = os.path.join(cnInstDir, fileList[num])

        # copy encrypt file to host
        for instInfo in instanceList:
            for certfile in fileList:
                # scp certfile from cnNodeName to instInfo.hostname
                sshCmd = g_Platform.getSshCmd(cnNodeName)
                scpCmd = g_Platform.getRemoteCopyCmd(certfile, "%s/" % instInfo.datadir, instInfo.hostname)
                cmd = "%s \"if [ -f '%s' ]; then %s; fi\"" % (sshCmd, certfile, scpCmd)
                DefaultValue.execCommandLocally(cmd)
                # change the certfile under instInfo.hostname
                sshCmd = g_Platform.getSshCmd(instInfo.hostname)
                chmodCmd = g_Platform.getChmodCmd(str(DefaultValue.KEY_FILE_MODE), certfile)
                cmd = "%s \"if [ -f '%s' ]; then %s; fi\"" % (sshCmd, certfile, chmodCmd)
                DefaultValue.execCommandLocally(cmd)

    @staticmethod
    def getSecurityMode(agentDir):
        """
        function:to set security mode,if security_mode is not in config file,return off.
        input:String
        output:String
        """
        securityModeValue = "off"
        configFile = DefaultValue.getCmConfigFile(agentDir)
        security_mode = "security_mode"
        (status, output) = DefaultValue.getMatchingResult("\<'%s'\>" % security_mode, configFile)
        if (status != 0 and output != ""):
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50204"] % configFile + " Error:\n%s" % str(output))
        else:
            if (output != ""):
                for out in output.split("\n"):
                    if (out.strip()[0] != "#"):
                        securityModeValue = out.split('#')[0].split('=')[1].strip()
        return securityModeValue

    @staticmethod
    def syncDependLibsAndEtcFiles(sshTool, nodeName):
        """
        function: Distribute etc file and libsimsearch libs to new node
        input : NA
        output: NA
        """
        try:
            # distribute etc file to new node
            gaussHome = DefaultValue.getEnv("GAUSSHOME")
            DefaultValue.checkPathVaild(gaussHome)

            searchConfigFile = "%s/etc/searchletConfig.yaml" % gaussHome
            searchIniFile = "%s/etc/searchServer.ini" % gaussHome
            if (os.path.exists(searchConfigFile)):
                sshTool.scpFiles(searchConfigFile, searchConfigFile, nodeName)
            if (os.path.exists(searchIniFile)):
                sshTool.scpFiles(searchIniFile, searchIniFile, nodeName)

            # distribute libsimsearch libs to new node
            libPath = "%s/lib" % gaussHome
            libsimsearchPath = "%s/libsimsearch" % libPath
            if (not os.path.isdir(libsimsearchPath)):
                return

            if nodeName:
                libPath = "'%s/'" % libPath
                cmd = DefaultValue.get_remote_copy_cmd(libsimsearchPath, libPath, socket.gethostname())
                sshTool.executeCommand(cmd, "scp libsimsearch libs to newnode", DefaultValue.SUCCESS, nodeName)

        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def makeCompressedToolPackage(packageDir, logger):
        """
        function : check the output file
        input : String
        output : NA
        """
        logger.debug("Starting to make compressed tool package.")
        # init bin file name, integrity file name and tar list names
        packageDir = os.path.normpath(packageDir)
        binFileName = g_OSlib.getBinFilePath()
        integrityFileName = g_OSlib.getSHA256FilePath()
        tarLists = "--exclude=script/*.log --exclude=*.log script sudo version.cfg libcgroup lib lvs " \
                   "unixodbc inplace_upgrade_sql.sha256 inplace_upgrade_sql.tar.gz"
        if os.path.isdir(os.path.join(packageDir, 'hotpatch')):
            tarLists += " hotpatch"
        try:
            # make compressed tool package
            cmd = "%s && " % g_Platform.getCdCmd(packageDir)
            # do not tar *.log files
            cmd += g_Platform.getCompressFilesCmd(DefaultValue.PACKAGE_BACK_NAME, tarLists)
            cmd += " %s %s " % (os.path.basename(binFileName), os.path.basename(integrityFileName))
            cmd += "&& %s " % g_Platform.getChmodCmd(str(DefaultValue.KEY_FILE_MODE), DefaultValue.PACKAGE_BACK_NAME)
            cmd += "&& %s " % g_Platform.getCdCmd("-")
            logger.debug("Command:%s." % cmd)
            (status, output) = DefaultValue.retryGetstatusoutput(cmd)
            if status != 0:
                raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error: \n%s" % output)
        except Exception as e:
            raise Exception(str(e))

        logger.debug("Successfully made compressed tool package.")

    @staticmethod
    def getCpuSet():
        """
        function: get cpu set of current board
                  cat /proc/cpuinfo |grep processor
        input: NA
        output: cpuSet
        """
        # do this function to get the parallel number
        cpuSet = multiprocessing.cpu_count()
        if cpuSet > 1:
            return cpuSet
        else:
            return DefaultValue.DEFAULT_PARALLEL_NUM

    @staticmethod
    def getTopPathNotExist(topDirPath):
        """
        function : Get the top path if exist
        input : String
        output : String
        """
        tmpDir = topDirPath
        while True:
            # find the top path to be created
            (tmpDir, topDirName) = os.path.split(tmpDir)
            if (os.path.exists(tmpDir) or topDirName == ""):
                tmpDir = os.path.join(tmpDir, topDirName)
                break
        return tmpDir

    @staticmethod
    def checkDirSize(path, needSize, g_logger):
        """
        function: Check the size of directory
        input : path,needSize
        output: NA
        """
        # The file system of directory
        diskSizeInfo = {}
        dfCmd = "%s | head -2 |tail -1 | %s -F\" \" '{print $1}'" % \
                (g_Platform.getDiskFreeCmd(path), g_Platform.getAwkCmd())
        (status, output) = subprocess.getstatusoutput(dfCmd)
        if (status != 0):
            g_logger.logExit(ErrorCode.GAUSS_502["GAUSS_50219"] % "the system file directory")

        fileSysName = str(output)
        diskSize = diskSizeInfo.get(fileSysName)
        if (diskSize is None):
            vfs = os.statvfs(path)
            diskSize = vfs.f_bavail * vfs.f_bsize // (1024 * 1024)
            diskSizeInfo[fileSysName] = diskSize

        # 200M for a instance needSize is 200M
        if (diskSize < needSize):
            g_logger.logExit(ErrorCode.GAUSS_504["GAUSS_50400"] % (fileSysName, needSize))

        diskSizeInfo[fileSysName] -= needSize
        return diskSizeInfo

    @staticmethod
    def get_min_cpu():
        """
        function: get cpu number
        """
        try:
            cmd = g_file.SHELL_CMD_DICT.get("cpuInfo")
            (status, output) = subprocess.getstatusoutput(cmd)
            if status != 0:
                raise Exception("Failed to get number of CPUs, Error:%s" % output)
            return int(output.strip())
        except Exception as ex:
            raise Exception(str(ex))

    @staticmethod
    def get_physical_memory(cluster_info, ssh_tool):
        """
        """
        try:
            node_names = cluster_info.getClusterNodeNames()
            cmd = g_file.SHELL_CMD_DICT.get("physicMemory")
            physic_memo = []
            (status, output) = ssh_tool.getSshStatusOutput(cmd, node_names)
            for ret in status.values():
                if ret != DefaultValue.SUCCESS:
                    raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + "Error:\n%s" % str(output))
            mem_total_list = output.split("\n")
            for content in mem_total_list:
                if "MemTotal" in content:
                    memoList = content.split(":")
                    memo = int(memoList[1].replace("kB", "").strip()) // 1024 // 1024
                    physic_memo.append(memo)
            min_physic_memo = min(physic_memo)
            return min_physic_memo
        except Exception as ex:
            raise Exception from ex

    @staticmethod
    def get_physical_memory_single():
        """
        """
        try:
            cmd = g_file.SHELL_CMD_DICT.get("physicMemory")
            (status, output) = DefaultValue.retryGetstatusoutput(cmd)
            if status != 0:
                raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd +
                                "Error:\n%s" % str(output))

            physical_memory = None
            for content in output.split("\n"):
                if "MemTotal" in content:
                    memoList = content.split(":")
                    physical_memory = int(memoList[1].replace("kB", "").strip()) // 1024 // 1024

            if physical_memory is None:
                raise Exception("Failed to get MemTotal.Output:%s." % output)

            return physical_memory
        except Exception as ex:
            raise Exception from ex

    @staticmethod
    def get_min_value_dict(cluster_info, ssh_tool):
        """
        get cluster min_cpu_info, min_physical_memory
        """
        min_value_dict = {}
        min_cpu_info = DefaultValue.get_min_cpu()
        min_physical_memory = DefaultValue.get_physical_memory_single()
        min_value_dict["min_cpu_info"] = min_cpu_info
        min_value_dict["min_physical_memory"] = min_physical_memory
        return min_value_dict

    @staticmethod
    def getPrivateGucParamList():
        """
        function : Get the private guc parameter list.
        input : NA
        output
        """
        # only used by dummy standby instance
        # add the parameter content to the dictionary list
        return DefaultValue.DUMMY_DN_GUC

    @staticmethod
    def checkKerberos(mpprcFile):
        """
        function : check kerberos authentication
        input : mpprcfile absolute path
        output : True/False
        """
        krb5Conf = os.path.join(os.path.dirname(mpprcFile), DefaultValue.FI_KRB_CONF)
        tablespace = DefaultValue.getEnv("ELK_SYSTEM_TABLESPACE")
        if (tablespace is not None and tablespace != ""):
            xmlfile = os.path.join(os.path.dirname(mpprcFile), DefaultValue.FI_ELK_KRB_XML)
        else:
            xmlfile = os.path.join(os.path.dirname(mpprcFile), DefaultValue.FI_KRB_XML)
        if (os.path.exists(xmlfile) and os.path.exists(krb5Conf) and DefaultValue.getEnv("PGKRBSRVNAME")):
            return True
        return False

    @staticmethod
    def get_max_wal_senders_value(max_connections):
        """
        function : Get guc max_wal_senders value by max_connections.
        input : NA
        output
        """
        value = int(max_connections) - 1
        if (value >= DefaultValue.MAX_WAL_SENDERS):
            return DefaultValue.MAX_WAL_SENDERS
        else:
            return value

    @staticmethod
    def unencryptedFeatureInfo(featureFile):
        """
        Read the byte stream data from specified file and convert it to the disabled feature list of Gauss DB.

        All exceptions of this method are exposed to its caller.

        :param featureFile: Files used to save byte stream.
        :type featureFile:  str

        :return:    Return the GaussDB version and the disabled feature list.
        :rtype:     str, list
        """
        # Read the byte stream data from the specified file.
        with open(featureFile, "rb") as fp:
            # Read the header. Three int parameters.
            header_data = fp.read(4 * 3)
            fp.seek(4 * 3)
            # The format of "header" field.
            header_format = "III"
            # Unpack the byte stream data.
            crc32_code, base64_data_len, data_len = struct.unpack(header_format, header_data)

            # Read data.
            base64_data = fp.read(base64_data_len)
            if binascii.crc32(base64_data) & 0xFFFFFFFF != crc32_code:
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50222"], featureFile)

            # Base64 decode.
            data = base64.b64decode(base64_data)
            if len(data) != data_len:
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50222"], featureFile)

            # Combine format of "data" field converted to streaming data according to the length of the disabled feature
            #  list.
            data_format = "BI"
            data_format = data_format.ljust(len(data_format) + (len(data) - 4 - 1 * 4) // 2, "H")

            # Unpack the data.
            temp = list(struct.unpack(data_format, data))
            productFlag = temp[0]
            disabledFeature_len = temp[1]
            disabledFeature_list = temp[2:]
            if len(disabledFeature_list) != disabledFeature_len:
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50222"], featureFile)

            # Setting Gauss DB version according to product flag.
            if productFlag == 2:
                return DefaultValue.PRODUCT_VERSION_GAUSS200, disabledFeature_list
            elif productFlag == 3:
                return DefaultValue.PRODUCT_VERSION_GAUSS300, disabledFeature_list
            else:
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50222"], featureFile)

    @staticmethod
    def changeObsLogSetting(appPath, logPath):
        """
        function: change the obs log setting file  distribute package
        input : appPath  $GAUSSHOME
                logPath  $GAUSSLOG
        output: NA
        """
        obspathNum = appPath.count("/")
        # obs path is the relative path between log path and app path.
        # if app path is /test/app and log path is /test/log
        # then the relative path from app to log is '..'+'/..'*(num-1)+logpath
        # the relative path from obs to log is '../../..'+'/..'*(num-1)+logpath
        username = DefaultValue.getEnv("LOGNAME")
        DefaultValue.checkPathVaild(username)
        obspath = "LogPath=../.." + "/.." * obspathNum + "%s/" % logPath + "%s" % username + "/bin/gs_obs"
        cmd = "mkdir -p '%s/%s/bin/gs_obs' -m %s" % (logPath, username, DefaultValue.KEY_DIRECTORY_MODE)
        (status, output) = subprocess.getstatusoutput(cmd)
        if (status != 0):
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50208"] % "obs log" + " Error: \n%s " % output)
        obsinifile = "%s/lib/OBS.ini" % appPath

        if (not os.path.exists(obsinifile)):
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % obsinifile)
        try:
            with open(obsinifile, 'r') as fp:
                lines = fp.readlines()
                flen = len(lines) - 1
                for i in range(flen):
                    if "sdkname=eSDK-OBS-API-Linux-C" in lines[i]:
                        lines[i] = lines[i].replace("sdkname=eSDK-OBS-API-Linux-C", "sdkname=gs_obs")
                    if "LogPath=../logs" in lines[i]:
                        lines[i] = lines[i].replace("LogPath=../logs", obspath)
            g_file.write_file_with_default_permission(obsinifile, lines)
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def get_alarm_component_value(config_file):
        """
        function: get the value of alarm_component.
                  The default value is '/opt/huawei/snas/bin/snas_cm_cmd'
        input: config_file
        output:String
        """
        alarm_component_value = DefaultValue.ALARM_COMPONENT_PATH
        (status, output) = DefaultValue.getMatchingResult("\<'%s'\>" %
                                                          "alarm_component", config_file)
        if status != 0:
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50204"] %
                            config_file + " Error:\n%s" % str(output))

        for line in output.split('\n'):
            line = line.strip()
            if line[0] != '#' and line.find('=') > 0:
                alarm_component_value = line.split('#')[0].split('=')[1].strip()
        return alarm_component_value

    @staticmethod
    def get_cn_instance_info(db_node):
        """
        function: get cn instance info
        input: db node
        output: cn dict
        """
        cn_inst_dict = dict()
        for dbInstance in db_node.coordinators:
            cn_inst_dict['C|cn_%s' % dbInstance.instanceId] = "%s|%s|%s|%s|%s|%s|0|0" % (dbInstance.listenIps[0],
                                                                                         dbInstance.listenIps[0],
                                                                                         dbInstance.port,
                                                                                         dbInstance.port,
                                                                                         dbInstance.sctpPort,
                                                                                         dbInstance.controlPort)
        return cn_inst_dict

    @staticmethod
    def get_dn_instance_info(db_node, cluster_info):
        """
        function: get dn instance info
        input: db node
        output: dn dict
        """
        dn_inst_dict = dict()
        for dbInstance in db_node.datanodes:
            if cluster_info.isSinglePrimaryMultiStandbyCluster():
                if dbInstance.instanceType == DefaultValue.MASTER_INSTANCE:
                    instanceIdList = list()
                    instanceIdList.append(dbInstance.instanceId)
                    peerInsts = cluster_info.getPeerInstance(dbInstance)
                    for i in range(len(peerInsts)):
                        if peerInsts[i].instanceType == DefaultValue.STANDBY_INSTANCE:
                            instanceIdList.append(peerInsts[i].instanceId)
                    instanceIdList = sorted(instanceIdList)
                    if len(instanceIdList) < 2:
                        raise Exception(ErrorCode.GAUSS_516["GAUSS_51620"] % "standby")
                    instance_name = "dn_%s" % ('_'.join([str(instId) for instId in instanceIdList]))
                    dn_inst_dict['D|%s' % instance_name] = "%s|%s|%s|%s|%s|%s|0|0" % (
                        dbInstance.listenIps[0], dbInstance.listenIps[0],
                        dbInstance.port, dbInstance.port,
                        dbInstance.sctpPort, dbInstance.controlPort)
                    index = 1
                    for inst in peerInsts:
                        dn_inst_dict['S%d|%s' % (index, instance_name)] = "%s|%s|%s|%s|%s|%s|0|0" % (
                            inst.listenIps[0], inst.listenIps[0],
                            inst.port, inst.port,
                            inst.sctpPort, inst.controlPort)
                        index += 1
            elif cluster_info.isMasterStandbyCluster() or cluster_info.isMasterStandbyMultiAZCluster():
                if dbInstance.instanceType == DefaultValue.MASTER_INSTANCE:
                    standbyInstance = None
                    peerInsts = cluster_info.getPeerInstance(dbInstance)
                    for i in range(len(peerInsts)):
                        if peerInsts[i].instanceType == DefaultValue.STANDBY_INSTANCE:
                            standbyInstance = peerInsts[i]
                    if standbyInstance is None:
                        raise Exception(ErrorCode.GAUSS_516["GAUSS_51620"] % "standby")
                    dn_inst_dict['D|dn_%s_%s' % (
                        dbInstance.instanceId, standbyInstance.instanceId)] = "%s|%s|%s|%s|%s|%s|%s|%s" % (
                        dbInstance.listenIps[0], standbyInstance.listenIps[0],
                        dbInstance.port, standbyInstance.port,
                        dbInstance.sctpPort, dbInstance.controlPort,
                        standbyInstance.sctpPort, standbyInstance.controlPort)
            else:
                dn_inst_dict['D|dn_%s' % dbInstance.instanceId] = "%s|%s|%s|%s|%s|%s|0|0" % (
                    dbInstance.listenIps[0], dbInstance.listenIps[0],
                    dbInstance.port, dbInstance.port,
                    dbInstance.sctpPort, dbInstance.controlPort)
        return dn_inst_dict

    @staticmethod
    def getInstanceInfoDict(clusterInfo, nameList=None):
        """
        """
        # get instance Dict
        # key   : type, instance_name. split by '|'
        # value : node_host, node_host1, node_port, node_port1, sctp_port, control_port, sctp_port1, control_port1
        # nameList: If a value is available, the node list information is obtained.
        instDict = {}
        for dbNode in clusterInfo.dbNodes:
            if nameList is not None and dbNode.name not in nameList:
                continue
            # get info for CNs
            cn_inst_dict = DefaultValue.get_cn_instance_info(dbNode)
            # get info for DNs
            dn_inst_dict = DefaultValue.get_dn_instance_info(dbNode, clusterInfo)
            instDict.update(cn_inst_dict)
            instDict.update(dn_inst_dict)
        return instDict

    @staticmethod
    def get_local_cn_state(cluster_info, cluster_status):
        """
        function: get local cn node status
        input : user, clusterInfo
        output  : True/False
        """
        local_node_info = cluster_info.getDbNodeByName(socket.gethostname())
        if local_node_info.coordinators:
            instance_status = cluster_status.getInstanceStatusById(local_node_info.coordinators[0].instanceId)
            if instance_status is not None and instance_status.isInstanceHealthy() \
                    and not instance_status.isCNDeleted():
                return True
            else:
                return False
        else:
            return False

    @staticmethod
    def getInstMapping(oldClusterInfo, newClusterInfo):
        """
        function: Obtain the mapping for all DNs in the old and new clusters in sequence.
                  don't care about the CNs
        input : dbclusterInfo,dbclusterInfo
        output  : list
        """
        mapList = []
        oldDnInsts = oldClusterInfo.getAllDNInsts()
        newDnInsts = newClusterInfo.getAllDNInsts()
        if len(oldDnInsts) != len(newDnInsts):
            raise Exception(ErrorCode.GAUSS_512["GAUSS_51227"] % "datanodes")

        for (newInst, oldInst) in zip(newDnInsts, oldDnInsts):
            if newInst.instanceId != oldInst.instanceId:
                mapList.append((oldInst, newInst))
        return mapList

    @staticmethod
    def modifyClusterOMStatus(OMStatus="off", nodeIdList=None, offline=False):
        """
        function : modify cluster O&M Management switch
        """
        userProfile = DefaultValue.getMpprcFile()
        cmd = "%s %s ; cm_ctl set --maintenance=%s " % (g_Platform.getSourceCmd(), userProfile, OMStatus)
        if OMStatus != "off":
            # check node id
            if nodeIdList is not None and len(nodeIdList) > 0:
                for nodeId in nodeIdList:
                    cmd = "%s -n %s" % (cmd, nodeId)
        if offline is True:
            cmd += " -f"
        (status, output) = DefaultValue.retryGetstatusoutput(cmd)
        if status != 0:
            raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error: \n%s" % output)

    @staticmethod
    def modifySchedulerStatus(schedulerStatus):
        """
        function : modify scheduler status
        input : True means run scheduler, False means stop scheduler
        """
        maintenance = "off" if schedulerStatus else "on"
        userProfile = DefaultValue.getMpprcFile()
        cmd = "%s %s ; gs_scheduler -t manage --maintenance=%s " % (g_Platform.getSourceCmd(), userProfile, maintenance)
        (status, output) = DefaultValue.retryGetstatusoutput(cmd, retryTime=10, sleepTime=3)
        if (status != 0):
            raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error: \n%s" % output)

    @staticmethod
    def getCmConfigFile(dataPath):
        """
        """
        if dataPath != "" and dataPath.endswith('/'):
            dataPath = dataPath[:-1]
        configFile = os.path.join(os.path.dirname(dataPath), "cm_agent/cm.conf")
        return configFile

    @staticmethod
    def getDbAdminPwd():
        """
        """
        tmptoken = DefaultValue.TMP_TOKEN_FILE
        dbAdminPwd = ""
        if os.path.isfile(tmptoken):
            with open(tmptoken, "r") as fp:
                lines = fp.readlines()
                if len(lines) == 1:
                    dbAdminPwd = base64.b64decode(lines[0]).decode()
        elif os.path.isdir(tmptoken):
            dbAdminPwd = AesCbcUtil.aes_cbc_decrypt_with_multi(tmptoken)
        return dbAdminPwd

    @staticmethod
    def getBuildCmd(datadir, nodeId=0, isCmCtl=True, instType="datanode", buildMode="full",
                    timeout=TIMEOUT_INSTANCE_BUILD, options=""):
        """
        """
        # Clearing Residual Processes
        processName = 'gs_ctl *build .* -D *%s' % datadir
        killCmd = DefaultValue.killInstProcessCmd(processName)
        # Deleting Residual Files
        buildPidFile = "%s/gs_build.pid" % datadir
        delCmd = g_file.SHELL_CMD_DICT["deleteFile"] % (buildPidFile, buildPidFile)
        # Generate the build command.
        userProfile = DefaultValue.getMpprcFile()
        sourceCmd = "source %s " % userProfile
        if isCmCtl:
            buildCmd = "cm_ctl build -b %s -n %s -D %s -t %d -f " % (buildMode, nodeId, datadir, timeout)
        else:
            buildCmd = "gs_ctl build -b %s -Z %s -D %s -w -r %d %s" % (buildMode, instType, datadir, timeout, options)
        exeCmd = "%s; %s; %s; %s" % (killCmd, delCmd, sourceCmd, buildCmd)
        return exeCmd

    @staticmethod
    def set_cloexec(fd, cloexec=True):
        """
        """
        flags = fcntl.fcntl(fd, fcntl.F_GETFD)
        if cloexec:
            flags |= fcntl.FD_CLOEXEC
        else:
            flags &= ~fcntl.FD_CLOEXEC
        fcntl.fcntl(fd, fcntl.F_SETFD, flags)

    @staticmethod
    def get_config_parameter_value(action, key, throwException=True):
        """
        """
        try:
            paraList = DefaultValue.getConfigFilePara(DefaultValue.OM_CONF, action)
            if len(paraList) > 0 and key in paraList.keys():
                return paraList[key]
            else:
                return None
        except Exception as e:
            if throwException:
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50204"] % DefaultValue.OM_CONF + " Error:\n") from e
            else:
                return None

    @staticmethod
    def get_instance_message(app_path, inst_name):
        """
        """
        cmd = "ps ux | grep -w '%s/bin/%s' | grep -v grep" % (app_path, inst_name)
        _, output = DefaultValue.retryGetstatusoutput(cmd)
        return output

    @staticmethod
    def is_instance_alive(app_path, inst_name):
        """
        """
        cmd = "ps ux | grep -w '%s/bin/%s' | grep -v grep | wc -l" % (app_path, inst_name)
        status, output = DefaultValue.retryGetstatusoutput(cmd)
        if status == 0 and output.isdigit() and int(output) >= 1:
            return True
        else:
            return False

    @staticmethod
    def start_om_monitor(logger, user, app_path):
        """
        """
        log_path = DefaultValue.getOMLogPath(DefaultValue.OM_MONITOR_DIR_FILE, user, app_path, "")
        sep_env_file = DefaultValue.getEnv(DefaultValue.MPPRC_FILE_ENV)
        if sep_env_file != "" and sep_env_file is not None:
            cmd = "source /etc/profile;(if [ -f ~/.profile ]; " \
                  "then source ~/.profile;fi);source ~/.bashrc;source %s;" % sep_env_file
        else:
            cmd = "source /etc/profile;(if [ -f ~/.profile ];" \
                  "then source ~/.profile;fi);source ~/.bashrc;"
        cmd += "nohup %s/bin/om_monitor -L %s >>/dev/null 2>&1 &" % (app_path, log_path)
        logger.debug("Command for start om_monitor:%s" % cmd)
        status = 0
        max_retry_times = 5
        for _ in range(max_retry_times):
            status, _ = DefaultValue.retryGetstatusoutput(cmd)
            if status != 0:
                continue
            time.sleep(1)
            if DefaultValue.is_instance_alive(app_path, "om_monitor"):
                break
        if status != 0 or not DefaultValue.is_instance_alive(app_path, "om_monitor"):
            raise Exception(ErrorCode.GAUSS_516["GAUSS_51607"] % "om_monitor")

    @staticmethod
    def restart_om_monitor(logger, user, app_path):
        """
        """
        output = DefaultValue.get_instance_message(app_path, "om_monitor")
        logger.debug("Before restart, the om_monitor process:\n%s." % output)

        logger.debug("Start to kill om_monitor.")
        DefaultValue.KillAllProcess(user, "om_monitor")
        logger.debug("Successfully killed om_monitor.")

        logger.debug("Start to start om_monitor.")
        DefaultValue.start_om_monitor(logger, user, app_path)
        logger.debug("Successfully started om_monitor.")

        output = DefaultValue.get_instance_message(app_path, "om_monitor")
        logger.debug("After restart, the om_monitor process:\n%s." % output)

    @staticmethod
    def get_dws_bigdata_directory(logger, node_info):
        """
        """
        if len(node_info.datanodes) == 0:
            logger.debug("There is no dn instances on %s." % node_info.name)
            return ""

        dn_data_path_list = []
        for dn_insts in node_info.datanodes:
            if dn_insts.instanceType == DefaultValue.MASTER_INSTANCE:
                dn_data_path_list.append(dn_insts.datadir)
        for dn_insts in node_info.datanodes:
            if dn_insts.instanceType == DefaultValue.STANDBY_INSTANCE:
                dn_data_path_list.append(dn_insts.datadir)
        if len(dn_data_path_list) == 0:
            logger.debug("There is no dn master/standby instances on %s." % node_info.name)
            return ""

        data_path = dn_data_path_list[0]
        cmd = "df '%s' | grep -v 'Filesystem' | awk -F ' ' '{print $NF}'" % data_path
        logger.debug("Command for getting instance mount path: %s" % cmd)
        status, output = DefaultValue.retryGetstatusoutput(cmd)
        if status != 0 or output == "" or len(output.split('\n')) > 1:
            raise Exception(ErrorCode.GAUSS_516["GAUSS_51615"] +
                            " Command:%s. Error:\n%s" % (cmd, output))
        mount_path = output.strip()
        if not os.path.ismount(mount_path):
            logger.debug("The mount path on %s is incorrect." % mount_path)
            return ""

        if mount_path == '/':
            mount_path = os.path.join(os.path.dirname(node_info.cmagents[0].datadir), "dws_bigdata")
        else:
            if os.access(mount_path, os.W_OK):
                mount_path = os.path.join(mount_path, "dws_bigdata")
            else:
                mount_path = os.path.join(os.path.dirname(node_info.cmagents[0].datadir), "dws_bigdata")
        logger.debug("The dws_bigdata_directory is: %s" % mount_path)
        return mount_path

    @staticmethod
    def check_suse_version_id(version_id):
        """
        """
        if os.path.isfile("/etc/os-release"):
            cmd = "grep -i 'VERSION_ID' /etc/os-release | awk -F '=' '{print $2}'"
            status, output = subprocess.getstatusoutput(cmd)
            output = output.replace("'", "").replace('"', '')
            if status == 0 and output != "":
                if output.strip() == str(version_id):
                    return True
            else:
                raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error: \n%s " % output)
        return False

    @staticmethod
    def check_kylin_version_id(version_id):
        """
        """
        info_file = "/etc/.productinfo"
        if os.path.isfile(info_file):
            cmd = "tail -n 1 %s | awk -F ' ' '{print $3}'" % (info_file)
            status, output = subprocess.getstatusoutput(cmd)
            output = output.replace("(", "").replace(")", "")
            if status == 0 and output != "":
                if output.strip() == str(version_id):
                    return True
            else:
                raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error: \n%s " % output)
        return False

    @staticmethod
    def check_openssl_version():
        try:
            cmd = "/usr/bin/openssl version"
            status, output = subprocess.getstatusoutput(cmd)
            if status == 0 and output != "":
                openssl_version = output.strip().split(" ")[1]
                if openssl_version == "1.1.1f" or openssl_version == "1.1.1d":
                    return True
        except Exception:
            return False
        return False

    @staticmethod
    def is_os_with_conflicting_so_libraries():
        """
        """
        gs_platform = Platform()
        dist_name, version, _ = gs_platform.dist()
        dist_name = dist_name.lower()
        if dist_name == support_platform.SUSE and version in support_platform.CONFLICTING_SUSE_LARGE_VERSION_LIST:
            version_id_list = support_platform.CONFLICTING_SUSE_MINOR_VERSION_LIST
            for version_id in version_id_list:
                if DefaultValue.check_suse_version_id(version_id) and DefaultValue.check_openssl_version():
                    return True
        elif dist_name == support_platform.KYLIN and version in support_platform.CONFLICTING_KYLIN_LARGE_VERSION_LIST:
            version_id_list = support_platform.CONFLICTING_KYLIN_MINOR_VERSION_LIST
            for version_id in version_id_list:
                if DefaultValue.check_kylin_version_id(version_id) and DefaultValue.check_openssl_version():
                    return True
        return False

    @staticmethod
    def get_dws_bigdata_vmoptions():
        """
        dws-bigdata total memory: physical memory divide 8, min 4G
        JVM MetaSpace: 256M
        JVM CodeCache: 256M
        JVM DirectMemorySize: 1 + max data node num per node
        JVM Heap:others
        :return:
        """
        physical_memory = DefaultValue.get_physical_memory_single()
        # dws_bigdata_total_memory is setup to physical_memory divide 8 for all flavors.
        dws_bigdata_total_memory = round(physical_memory / 8)  # unit:GB

        cluster_info = dbClusterInfo()
        cluster_info.initFromStaticConfig(pwd.getpwuid(os.getuid()).pw_name)
        one_node_dn_num = cluster_info.get_dn_num_in_one_node()

        dws_bigdata_jvm_directmemorysize = one_node_dn_num + 1  # unit:GB
        dws_bigdata_jvm_heap = round(dws_bigdata_total_memory * 1024 -
                                     DefaultValue.DWS_BIGDATA_JVM_METASPACE -
                                     DefaultValue.DWS_BIGDATA_JVM_CODECACHE -
                                     dws_bigdata_jvm_directmemorysize * 1024)  # unit:MB

        # if dws_bigdata_jvm_heap is less than 0, means its non-standard configuration.
        # so we keep jvm_heap and jvm_directmemorysize is half of the remain memory.
        if dws_bigdata_jvm_heap <= 0:
            half_of_remain_mem = round(dws_bigdata_total_memory * 1024 -
                                       DefaultValue.DWS_BIGDATA_JVM_METASPACE -
                                       DefaultValue.DWS_BIGDATA_JVM_CODECACHE) // 2
            dws_bigdata_jvm_directmemorysize = str(half_of_remain_mem) + 'M'
            dws_bigdata_jvm_heap_str = str(half_of_remain_mem) + 'M'
        else:
            dws_bigdata_jvm_directmemorysize = str(dws_bigdata_jvm_directmemorysize) + 'G'
            dws_bigdata_jvm_heap_str = str(dws_bigdata_jvm_heap) + 'M'

        # jvm gc options
        other_jvm_options = ("-XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps "
                             "-XX:+PrintGCDateStamps -Xloggc:${GAUSSLOG}/dws-bigdata/gc-%t.log "
                             "-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=20M "
                             "-XX:+ExitOnOutOfMemoryError")

        return "-Xms%s -Xmx%s " \
               "-XX:MaxMetaspaceSize=%sM " \
               "-XX:ReservedCodeCacheSize=%sM " \
               "-XX:MaxDirectMemorySize=%s " \
               "%s" % \
               (dws_bigdata_jvm_heap_str, dws_bigdata_jvm_heap_str,
                DefaultValue.DWS_BIGDATA_JVM_METASPACE,
                DefaultValue.DWS_BIGDATA_JVM_CODECACHE,
                dws_bigdata_jvm_directmemorysize,
                other_jvm_options), dws_bigdata_jvm_heap

    @staticmethod
    def support_tsc():
        cmd = "cat /sys/devices/system/clocksource/clocksource0/available_clocksource|grep -w tsc"
        (status, output) = subprocess.getstatusoutput(cmd)
        if output.find('tsc') >= 0:
            return True
        else:
            return False

    @staticmethod
    def get_standby_data_path(cluster_info, local_inst):
        """
        """
        node_info = cluster_info.getDbNodeByName(local_inst.hostname)
        if node_info is None:
            raise Exception(ErrorCode.GAUSS_512["GAUSS_51209"] % ("NODE", local_inst.name))
        master_path_list = []
        standby_path_list = []
        for inst in node_info.datanodes:
            if inst.instanceType == DefaultValue.MASTER_INSTANCE:
                master_path_list.append(inst.datadir)
            if inst.instanceType == DefaultValue.STANDBY_INSTANCE:
                standby_path_list.append(inst.datadir)
        master_path_list.sort()
        standby_path_list.sort()
        data_path = ""
        for tmp_dict in zip(master_path_list, standby_path_list):
            if tmp_dict[0] == local_inst.datadir:
                data_path = tmp_dict[1]
                break
        return data_path

    @staticmethod
    def get_disk_cache_max_size(primary_base_path, standby_base_path):
        """
        """
        primary_mount_path = g_disk.getMountPathByDataDir(primary_base_path)
        primary_path_size = g_disk.getMountPathTotalSize(primary_base_path, "GB")
        if standby_base_path == "":
            return (primary_path_size // 2)
        standby_mount_path = g_disk.getMountPathByDataDir(standby_base_path)
        standby_path_size = g_disk.getMountPathTotalSize(standby_base_path, "GB")
        if primary_mount_path == standby_mount_path:
            return (primary_path_size // 2)
        else:
            return ((primary_path_size + standby_path_size) // 2)

    @staticmethod
    def modify_disk_cache_base_paths_for_inst(cluster_info, local_inst, logger, setup_scene):
        """
        :param cluster_info:
        :param local_inst:
        :param logger:
        :param setup_scene:resize, install, expand, replace, upgrade
        :return:
        """
        if (cluster_info.isMasterStandbyCluster() or
                cluster_info.isMasterStandbyMultiAZCluster() or
                cluster_info.isSinglePrimaryMultiStandbyCluster()):
            if local_inst.instanceType == DefaultValue.MASTER_INSTANCE:
                disk_cache_base_paths = []
                primary_path = os.path.join(local_inst.datadir, "disk_cache")
                disk_cache_base_paths.append(primary_path)
                standby_base_path = DefaultValue.get_standby_data_path(cluster_info, local_inst)
                if standby_base_path != "":
                    # standby_path are not supposed to be set under standby_data_path
                    # set standby_path: standby_base_path../xxx_disk_cache
                    standby_path = os.path.join(os.path.dirname(standby_base_path),
                                                os.path.basename(local_inst.datadir) + "_disk_cache")

                    if standby_path != primary_path:
                        disk_cache_base_paths.append(standby_path)

                guc_str = "-c \"disk_cache_base_paths='%s'\"" % " ".join(list(disk_cache_base_paths))
                if setup_scene in ["resize", "install", "upgrade"]:
                    disk_cache_max_size = DefaultValue.get_disk_cache_max_size(local_inst.datadir,
                                                                               standby_base_path)
                    guc_str += " -c \"disk_cache_max_size='%dGB'\"" % disk_cache_max_size
                elif setup_scene in ["replace"]:
                    cmd = "grep -w disk_cache_max_size %s|grep =" % \
                          os.path.join(local_inst.datadir, "postgresql.conf")
                    (status, output) = subprocess.getstatusoutput(cmd)
                    if status == 0 and output != "":
                        disk_cache_max_size = (output.split('#')[0].split('=')[1].
                                               replace('"', '').replace("'", '').strip())
                        if disk_cache_max_size == "1GB":
                            # disk_cache_max_size is 1GB, means it is not set by user
                            disk_cache_max_size = DefaultValue.get_disk_cache_max_size(local_inst.datadir,
                                                                                       standby_base_path)
                            guc_str += " -c \"disk_cache_max_size='%dGB'\"" % disk_cache_max_size

                guc_str += " -c \"install_as_standby=false\""
            else:
                guc_str = "-c \"disk_cache_base_paths=''\""
                guc_str += " -c \"disk_cache_max_size='1GB'\""
                guc_str += " -c \"install_as_standby=true\""

            user_profile = DefaultValue.getMpprcFile()
            cmd = "source %s;" % user_profile
            cmd += "gs_guc set -Z datanode -D %s %s " % (local_inst.datadir, guc_str)
            logger.debug("Command for setting parameter: %s" % cmd)
            status, output = DefaultValue.retryGetstatusoutput(cmd)
            if status != 0:
                logger.logExit(ErrorCode.GAUSS_500["GAUSS_50007"] % cmd + " Error:\n%s" % output)

    @staticmethod
    def get_numa_bind_node_value(node_info, inst_info, cpu_list_info):
        """
        :param node_info:
        :param inst_info:
        :param cpu_list_info:
        :return:
        """
        numa_bind_node_value = "'none'"
        if inst_info.instanceType != DefaultValue.MASTER_INSTANCE:
            return numa_bind_node_value

        master_inst = [inst for inst in node_info.datanodes
                       if inst.instanceType == DefaultValue.MASTER_INSTANCE]
        if len(cpu_list_info) == 2:
            if len(master_inst) >= 2 and len(master_inst) % 2 == 0:
                for idx, inst in enumerate(master_inst):
                    if inst.instanceId == inst_info.instanceId:
                        numa_bind_node_value = "'numa%s,%s'" % (idx % 2, cpu_list_info[idx % 2])

        elif len(cpu_list_info) == 4:
            if len(master_inst) >= 4 and len(master_inst) % 4 == 0:
                for idx, inst in enumerate(master_inst):
                    if inst.instanceId == inst_info.instanceId:
                        numa_bind_node_value = "'numa%s,%s'" % (idx % 4, cpu_list_info[idx % 4])

        return numa_bind_node_value
