# -*- coding:utf-8 -*- ############################################################################# # Copyright (c) 2020 Huawei Technologies Co.,Ltd. # # openGauss is licensed under Mulan PSL v2. # You can use this software according to the terms # and conditions of the Mulan PSL v2. # You may obtain a copy of Mulan PSL v2 at: # # http://license.coscl.org.cn/MulanPSL2 # # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, # WITHOUT WARRANTIES OF ANY KIND, # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. # See the Mulan PSL v2 for more details. # ---------------------------------------------------------------------------- # Description : Common is a utility with a lot of common functions ############################################################################# import ctypes import sys import subprocess import os import platform import socket import types import re import time import multiprocessing import _thread as thread import pwd import json import base64 import secrets import string import stat import csv import copy from subprocess import PIPE from subprocess import Popen from base_utils.os.password_util import PasswordUtil # The installation starts, but the package is not decompressed completely. # The lib64/libz.so.1 file is incomplete, and the hashlib depends on the # libz.so.1 file. num = 0 while num < 10: try: import hashlib break except ImportError: num += 1 time.sleep(1) import shutil from ctypes import * from datetime import datetime localDirPath = os.path.dirname(os.path.realpath(__file__)) sys.path.insert(0, localDirPath + "/../../../lib") try: import psutil except ImportError as e: if not bool(os.listdir(localDirPath + "/../../../lib")): raise # mv psutil mode .so file by python version pythonVer = str(sys.version_info[0]) + '.' + str(sys.version_info[1]) psutilLinux = os.path.join(localDirPath, "./../../../lib/psutil/_psutil_linux.so") psutilPosix = os.path.join(localDirPath, "./../../../lib/psutil/_psutil_posix.so") psutilLinuxBak = "%s_%s" % (psutilLinux, pythonVer) psutilPosixBak = "%s_%s" % (psutilPosix, pythonVer) glo_cmd = "rm -rf '%s' && cp -r '%s' '%s' " % (psutilLinux, psutilLinuxBak, psutilLinux) glo_cmd += " && rm -rf '%s' && cp -r '%s' '%s' " % (psutilPosix, psutilPosixBak, psutilPosix) psutilFlag = True for psutilnum 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) # del error import and reload psutil del sys.modules['psutil._common'] del sys.modules['psutil._psposix'] import psutil sys.path.append(localDirPath + "/../../") from gspylib.common.ErrorCode import ErrorCode from os_platform.UserPlatform import g_Platform from gspylib.os.gsfile import g_file from os_platform.gsservice import g_service from gspylib.threads.parallelTool import parallelTool from base_utils.executor.cmd_executor import CmdExecutor from base_utils.executor.local_remote_cmd import LocalRemoteCmd from domain_utils.cluster_file.cluster_config_file import ClusterConfigFile from base_utils.os.cmd_util import CmdUtil from base_utils.os.env_util import EnvUtil from base_utils.os.file_util import FileUtil from domain_utils.cluster_file.version_info import VersionInfo from domain_utils.cluster_file.cluster_dir import ClusterDir from domain_utils.security.random_value import RandomValue from base_utils.os.process_util import ProcessUtil from domain_utils.sql_handler.sql_executor import SqlExecutor from domain_utils.sql_handler.sql_file import SqlFile from base_utils.os.net_util import NetUtil from base_utils.common.constantsbase import ConstantsBase from base_utils.security.sensitive_mask import SensitiveMask from os_platform.linux_distro import LinuxDistro from base_diff.sql_commands import SqlCommands from gspylib.common.DbClusterInfo import dbClusterInfo from base_utils.common.fast_popen import FastPopen from gspylib.common.Constants import Constants from domain_utils.cluster_file.profile_file import ProfileFile from domain_utils.domain_common.cluster_constants import ClusterConstants from gspylib.common.aes_cbc_util import AesCbcUtil noPassIPs = [] g_lock = thread.allocate_lock() def check_content_key(content, key): if not (type(content) == bytes): raise Exception(ErrorCode.GAUSS_530["GAUSS_53025"]) elif not (type(key) in (bytes, str)): raise Exception(ErrorCode.GAUSS_530["GAUSS_53026"]) iv_len = 16 if not (len(content) >= (iv_len + 16)): raise Exception(ErrorCode.GAUSS_530["GAUSS_53027"]) class DefaultValue(): """ Default value of some variables """ def __init__(self): pass TASK_QUERY_STATUS = "status" TASK_START = "startup" TASK_STOP = "shutdown" ########################### # DWS path info ########################### DWS_IMAGE_PATH = "/opt/dws/image" DWS_PACKAGE_PATH = "/opt/dws/package" DWS_APP_PAHT = "/opt/dws/app" ########################### # init action timeout value ########################### # start timeout value TIMEOUT_CLUSTER_START = 300 # stop timeout value TIMEOUT_CLUSTER_STOP = 300 ## TIMEOUT_PSSH_COMMON = 80 ########################### ########################### # 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 and rollback timeout value TIMEOUT_PSSH_BINARY_UPGRADE = 14400 # check timeout value TIMEOUT_PSSH_CHECK = 1800 # backup timeout value TIMEOUT_PSSH_BACKUP = 1800 # collector timeout value TIMEOUT_PSSH_COLLECTOR = 1800 # exponsion switchover timeout value TIMEOUT_EXPANSION_SWITCH = 30 ########################### # init authority parameter ########################### # directory mode DIRECTORY_MODE = 750 # directory permission DIRECTORY_PERMISSION = 0o750 # file node FILE_MODE = 640 FILE_MODE_PERMISSION = 0o640 KEY_FILE_MODE = 600 BIN_FILE_MODE = 700 KEY_FILE_MODE_IN_OS = 0o600 MIN_FILE_MODE = 400 SPE_FILE_MODE = 500 KEY_DIRECTORY_MODE = 700 MAX_DIRECTORY_MODE = 755 SQL_FILE_MODE = 644 # the host file permission. Do not changed it. HOSTS_FILE = 644 KEY_HOSTS_FILE = 0o644 # The available size of install app directory APP_DISK_SIZE = 100 # in grey upgrade, need to install new bin instead of replacing # old bin in inplace upgrade # so need 10G to guarantee enough space GREY_DISK_SIZE = 10 # The remaining space of device INSTANCE_DISK_SIZE = 200 DSS_DISK_MODE = 660 ########################### # upgrade parameter ########################### GREY_UPGRADE_STEP_UPGRADE_PROCESS = 3 CAP_WIO = "CAP_SYS_RAWIO" CAP_ADM = "CAP_SYS_ADMIN" # env parameter MPPRC_FILE_ENV = "MPPDB_ENV_SEPARATE_PATH" SUCCESS = "Success" FAILURE = "Failure" # tablespace version directory name # it is from gaussdb kernel code TABLESPACE_VERSION_DIRECTORY = "PG_9.2_201611171" # default database name DEFAULT_DB_NAME = "postgres" # database size file DB_SIZE_FILE = "total_database_size" # om_monitor log directory OM_MONITOR_DIR_FILE = "../cm/om_monitor" # action flag file name ACTION_FLAG_FILE = ".action_flag_file" # action log file name EXPANSION_LOG_FILE = "gs_expansion.log" DROPNODE_LOG_FILE = "gs_dropnode.log" # dump file for cn instance SCHEMA_COORDINATOR = "schema_coordinator.sql" # dump file for job data COORDINATOR_JOB_DATA = "schema_coordinator_job_data.sql" # dump file for statistics data COORDINATOR_STAT_DATA = "schema_coordinator_statistics_data.sql" # dump global info file for DB instance SCHEMA_DATANODE = "schema_datanode.sql" # record default group table info DUMP_TABLES_DATANODE = "dump_tables_datanode.dat" # dump default group table info file for DB instance DUMP_Output_DATANODE = "dump_output_datanode.sql" # default alarm tools ALARM_COMPONENT_PATH = "/opt/huawei/snas/bin/snas_cm_cmd" # root scripts path ROOT_SCRIPTS_PATH = "/root/gauss_om" # 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] 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 = ["clientnew.crt", "clientnew.key", "cacertnew.pem", "servernew.crt", "servernew.key", "openssl.cnf", "client.key.cipher", "client.key.rand", "server.key.cipher", "server.key.rand"] SERVER_CERT_LIST = ["client.crt", "client.key", "cacert.pem", "server.crt", "server.key", "openssl.cnf", "client.key.cipher", "client.key.rand", "server.key.cipher", "server.key.rand", "client.key.pk8"] BIN_CERT_LIST = ["server.key.cipher", "server.key.rand"] CERT_BACKUP_FILE = "gsql_cert_backup.tar.gz" PATH_CHECK_LIST = ["|", ";", "&", "$", "<", ">", "`", "\\", "'", "\"", "{", "}", "(", ")", "[", "]", "~", "*", "?", " ", "!", "\n"] PASSWORD_CHECK_LIST = [";", "'", "$"] # 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" # cluster status CLUSTER_STATUS_NORMAL = "Normal" CLUSTER_STATUS_DEGRADED = "Degraded" CLUSTER_STATUS_UNAVAILABLE = "Unavailable" ########################### # 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 # cascade standby CASCADE_STANDBY = 3 ########################### # parallel number ########################### DEFAULT_PARALLEL_NUM = 12 # SQL_EXEC_COMMAND SQL_EXEC_COMMAND_WITHOUT_HOST_WITHOUT_USER = "%s -p %s -d %s " # cluster type CLUSTER_TYPE_SINGLE = "single" CLUSTER_TYPE_SINGLE_PRIMARY_MULTI_STANDBY = "single-primary-multi-standby" CLUSTER_TYPE_SINGLE_INST = "single-inst" # 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" # 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" COLLECT_CONF_JSON_KEY_LIST = [ "Content", "TypeName", "Interval", "Count" ] COLLECT_CONF_CONTENT_MAP = { # System check config # cat /proc/cpuinfo; "HardWareInfo": "cpuInfo,memInfo,disk", # cat /proc/meminfo df -h # top; ps ux; iostat "RunTimeInfo": "ps,ioStat,netFlow,spaceUsage", # -xm 2 3; netstat; free -m du -sh # Log & Conf_Gstack check config "Coordinator": "CN", "DataNode": "DN", "Gtm": "GTM", # Log check config "ClusterManager": "cm,om,bin", # Core Dump check "gaussdb": "gaussdb", "gs_gtm": "gs_gtm", "gs_rewind": "gs_rewind", "cm_server": "cm_server", "cm_agent": "cm_agent", "gs_ctl": "gs_ctl", "gaussdb_stack": "gaussdb_stack", "gs_gtm_stack": "gs_gtm_stack", "gs_rewind_stack": "gs_rewind_stack", "cm_server_stack": "cm_server_stack", "cm_agent_stack": "cm_agent_stack", "gs_ctl_stack": "gs_ctl_stack", "AioWorker": "AioWorker", "AlarmChecker": "AlarmChecker", "Archiver": "Archiver", "Auditor": "Auditor", "AutoVacLauncher": "AutoVacLauncher", "AutoVacWorker": "AutoVacWorker", "AuxMain": "AuxMain", "BackendMode": "BackendMode", "BgWriter": "BgWriter", "BootStrap": "BootStrap", "Catchup": "Catchup", "CBMWriter": "CBMWriter", "Checkpointer": "Checkpointer", "CommAuxStream": "CommAuxStream", "CommPoolCleaner": "CommPoolCleaner", "CommRcvStream": "CommRcvStream", "CommRcvWorker": "CommRcvWorker", "CommSendStream": "CommSendStream", "CpMonitor": "CpMonitor", "DataRcvWriter": "DataRcvWriter", "DataReceiver": "DataReceiver", "DataSender": "DataSender", "ExtremeRTO": "ExtremeRTO", "FencedUDFMaster": "FencedUDFMaster", "GaussMaster": "GaussMaster", "Heartbeater": "Heartbeater", "JobExecutor": "JobExecutor", "LWLockMonitor": "LWLockMonitor", "PageWriter": "PageWriter", "ParallelRecov": "ParallelRecov", "PercentileJob": "PercentileJob", "Reaper": "Reaper", "RemoteSrv": "RemoteSrv", "StartupProcess": "StartupProcess", "StatCollector": "StatCollector", "Stream": "Stream", "SysLogger": "SysLogger", "ThdPoolListener": "ThdPoolListener", "TwoPhaseCleaner": "TwoPhaseCleaner", "WalRcvWriter": "WalRcvWriter", "WalReceiver": "WalReceiver", "WalSender": "WalSender", "WalWriter": "WalWriter", "WDRSnapshot": "WDRSnapshot", "WlmArbiter": "WlmArbiter", "WlmCollector": "WlmCollector", "WlmMonitor": "WlmMonitor" } COLLECT_CONF_MAP = { "System": "HardWareInfo,RunTimeInfo", "Database": "*", "Log": "Coordinator,DataNode,Gtm,ClusterManager,FFDC,AWRReport", "XLog": "Coordinator,DataNode", "Config": "Coordinator,DataNode,Gtm", "Gstack": "Coordinator,DataNode,Gtm", "CoreDump": "gaussdb,gs_gtm,gs_rewind,cm_server,cm_agent,gs_ctl," "gaussdb_stack,gs_gtm_stack,gs_rewind_stack," "cm_server_stack,cm_agent_stack,cm_server_stack," "gs_ctl_stack,AioWorker,AlarmChecker,Archiver,Auditor," "AutoVacLauncher,AutoVacWorker,AuxMain,BackendMode," "BgWriter,BootStrap,Catchup,CBMWriter,Checkpointer," "CommAuxStream,CommPoolCleaner,CommRcvStream,CommRcvWorker," "CommSendStream,CpMonitor,DataRcvWriter,DataReceiver," "DataSender,ExtremeRTO,FencedUDFMaster,GaussMaster," "Heartbeater,JobExecutor,JobScheduler,LWLockMonitor," "PageWriter,ParallelRecov,PercentileJob,Reaper,RemoteSrv," "StartupProcess,StatCollector,Stream,SysLogger," "ThdPoolListener,TwoPhaseCleaner,WalRcvWriter,WalReceiver," "WalSender,WalWriter,WDRSnapshot,WlmArbiter,WlmCollector," "WlmMonitor", "Trace": "Dump", "Plan": "*" } DATABASE_CHECK_WHITE_LIST = ["dbe_perf", "pg_catalog"] # Default retry times of SQL query attempts after successful # operation "gs_ctl start". DEFAULT_RETRY_TIMES_GS_CTL = 20 CORE_PATH_DISK_THRESHOLD = 50 # Cert type GRPC_CA = "grpc" SERVER_CA = "server" # rsa file name SSH_PRIVATE_KEY = os.path.expanduser("~/.ssh/id_om") SSH_PUBLIC_KEY = os.path.expanduser("~/.ssh/id_om.pub") SSH_AUTHORIZED_KEYS = os.path.expanduser("~/.ssh/authorized_keys") SSH_KNOWN_HOSTS = os.path.expanduser("~/.ssh/known_hosts") @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 @staticmethod def CheckNetWorkBonding(serviceIP, isCheckOS=True): """ function : Check NetWork ConfFile input : String, bool output : List """ networkCardNum = NetUtil.getNICNum(serviceIP) NetWorkConfFile = DefaultValue.getNetWorkConfFile(networkCardNum) bondingConfFile = "/proc/net/bonding/%s" % networkCardNum networkCardNumList = [] networkCardNumList.append(networkCardNum) if os.path.exists(NetWorkConfFile): 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 + \ NetUtil.checkBondMode( bondingConfFile, isCheckOS) else: raise Exception(ErrorCode.GAUSS_506["GAUSS_50611"] + " Command:%s. Error:\n%s" % (cmd, output)) elif isCheckOS: print("BondMode Null") else: (flag, netcardList) = NetUtil.getNetWorkBondFlag( networkCardNum) if flag: if os.path.exists(bondingConfFile): networkCardNumList = networkCardNumList + \ NetUtil.checkBondMode( bondingConfFile, isCheckOS) else: sys.exit(ErrorCode.GAUSS_506["GAUSS_50611"] + "Without NetWorkConfFile mode.") else: 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: 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" UbuntuNetWorkConfPath = "/etc/network" NetWorkConfFile = "" distname, version, idnum = LinuxDistro.linux_distribution() distname = distname.lower() if (distname in ("redhat", "centos", "euleros", "openeuler", "fusionos")): NetWorkConfFile = "%s/ifcfg-%s" % (RedHatNetWorkConfPath, networkCardNum) else: NetWorkConfFile = "%s/ifcfg-%s" % (SuSENetWorkConfPath, networkCardNum) if (not os.path.exists(NetWorkConfFile)): if (distname in ( "redhat", "centos", "euleros", "openeuler", "fusionos")): cmd = "find %s -iname 'ifcfg-*-%s' -print" % ( RedHatNetWorkConfPath, networkCardNum) elif (distname == "debian" and version == "buster/sid"): cmd = "find %s -iname 'ifcfg-*-%s' -print" % ( UbuntuNetWorkConfPath, networkCardNum) else: cmd = "find %s -iname 'ifcfg-*-%s' -print" % ( SuSENetWorkConfPath, networkCardNum) (status, output) = subprocess.getstatusoutput(cmd) if (status != 0 and DefaultValue.checkDockerEnv()): return output.strip() if (status != 0): raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd) if (len(output.split('\n')) != 1): raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % NetWorkConfFile) NetWorkConfFile = output.strip() return NetWorkConfFile @staticmethod def get_remote_ips(host, mpp_file): """ Get ips from remote host """ cmd = "source %s && pssh -s -t 30 -H %s \"hostname -I\"" % (mpp_file, host) status, output = subprocess.getstatusoutput(cmd) if status == 0 and output != "": ips = output.strip().split() return ips else: raise Exception(ErrorCode.GAUSS_516['GAUSS_51632'] % "check remote ips for node:%s, Error:%s." % (host, output)) @staticmethod def obtain_file_content(dest_file, deduplicate=True, is_list=True): """ function:obtains the content of each line in the file. input: file dir :return: file context lines list """ result = [] if is_list else None if not os.path.isfile(dest_file): return result with open(dest_file, "r") as fp_read: if is_list: for line in fp_read: result.append(line.strip('\n')) else: result = fp_read.read().strip() if deduplicate and is_list: result = list(set(result)) return result @staticmethod def get_all_dn_num_for_dr(file_path, dn_inst, cluster_info, logger): """get_all_dn_num_for_dr_cluster""" # DN inst supports a maximum of replicaNum=8 in postgresql.conf. default_num = 8 content = DefaultValue.obtain_file_content(file_path, is_list=False) if content: default_num = 0 shards = json.loads(content)['remoteClusterConf']["shards"] logger.debug("Stream cluster json shards:%s" % shards) if cluster_info.isSingleInstCluster(): for shard in shards: default_num += len(shard) else: default_num += len(shards[0]) peer_insts = cluster_info.getPeerInstance(dn_inst) default_num += len(peer_insts) logger.debug("Get config replconninfo dn num:%s" % default_num) return default_num @staticmethod def getIpByHostName(): ''' function: get local host ip by the hostname input : NA output: hostIp ''' # get hostname hostname = socket.gethostname() # get local host in /etc/hosts cmd = "grep -E \"^[1-9 \\t].*%s[ \\t]*#Gauss.* IP Hosts Mapping$\" " \ "/etc/hosts | grep -E \" %s \"" % (hostname, hostname) (status, output) = subprocess.getstatusoutput(cmd) if (status == 0 and output != ""): hostIp = output.strip().split(' ')[0].strip() return hostIp # get local host by os function hostIp = socket.gethostbyname(hostname) # due to two loopback address in ubuntu, 127.0.1.1 are choosed by hostname. # there is need to choose 127.0.0.1 version = LinuxDistro.linux_distribution()[1].split('/')[0] if version == "buster" and hostIp == "127.0.1.1": hostIp = "127.0.0.1" return hostIp @staticmethod def GetPythonUCS(): """ function: get python3 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 getUserId(user): """ function : get user id input : user output : user id """ try: pwd.getpwnam(user).pw_uid except Exception as e: raise Exception(ErrorCode.GAUSS_503["GAUSS_50300"] % user + "Detail msg: %s" % str(e)) @staticmethod def doConfigForParamiko(): """ function: Config depend file for pramiko 2.4.2. wen only support 2.7.x input : NA output: NA """ localDir = os.path.dirname(os.path.realpath(__file__)) sys.path.insert(0, os.path.join(localDir, "./../../lib")) @staticmethod def getTmpDir(user, xml_path): """ function : Get the temporary directory for user input : NA output : String """ return ClusterConfigFile.readClusterTmpMppdbPath(user, xml_path) @staticmethod def getTmpDirAppendMppdb(user): """ function : Get the user's temporary directory input : String output : String """ # get the user's temporary directory tmpDir = EnvUtil.getTmpDirFromEnv(user) # if the env paramter not exist, return "" if (tmpDir == ""): return tmpDir # modify tmp dir forbidenTmpDir = "/tmp/%s" % user if (tmpDir == forbidenTmpDir): tmpDir = os.path.join(EnvUtil.getEnv("GPHOME"), "%s_mppdb" % user) return tmpDir @staticmethod def checkPasswdForceChange(checkUser): """ function: Check if user password is forced to change at next login. input : user name output: NA """ distname, version, _ = LinuxDistro.linux_distribution() if (distname.lower() in ("suse", "redhat", "centos", "euleros", "openeuler", "fusionos")): 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.lower() == "suse"): if (version == '11'): if ("password is forced to change at next login" in result): raise Exception(ErrorCode.GAUSS_503["GAUSS_50307"]) elif (version == '12'): if ("password must be changed" in result): raise Exception(ErrorCode.GAUSS_503["GAUSS_50307"]) if (distname.lower() in ("redhat", "centos", "euleros", "openeuler", "fusionos")): if ("password must be changed" in result): raise Exception(ErrorCode.GAUSS_503["GAUSS_50307"]) @staticmethod def getUserHome(user=""): """ function :Get the user Home input : String output : String """ cmd = "su - %s -c \"echo ~\" 2>/dev/null" % user (status, output) = subprocess.getstatusoutput(cmd) if status != 0 or output.strip() == "": raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error:\n%s" % output) return output.strip() @staticmethod def getOSInitFile(): """ function : Get the OS initialization file input : NA output : String """ distname, version, _ = LinuxDistro.linux_distribution() systemDir = "/usr/lib/systemd/system/" systemFile = "/usr/lib/systemd/system/gs-OS-set.service" # OS init file # now we only support SuSE, RHEL/CentOS and Ubuntu initFileSuse = "/etc/init.d/boot.local" initFileRedhat = "/etc/rc.d/rc.local" initFileUbuntu = "/lib/systemd/system/rc.local.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__)) # Get the startup file of suse or redhat os if (os.path.isdir(systemDir)): # Judge if cgroup para 'Delegate=yes' is written in systemFile cgroup_gate = False cgroup_gate_para = "Delegate=yes" if os.path.exists(systemFile): with open(systemFile, 'r') as fp: retValue = fp.readlines() for line in retValue: if line.strip() == cgroup_gate_para: cgroup_gate = True break if (not os.path.exists(systemFile) or not cgroup_gate): srcFile = "%s/../etc/conf/gs-OS-set.service" % dirName FileUtil.cpFile(srcFile, systemFile) FileUtil.changeMode(DefaultValue.KEY_FILE_MODE, systemFile) # only support RHEL/Centos/Euler if (distname != "SuSE"): # enable gs-OS-set.service (status, output) = g_service.manageOSService("gs-OS-set", "enable") if (status != 0): raise Exception(ErrorCode.GAUSS_508["GAUSS_50802"] % "enable gs-OS-set" + " Error: \n%s" % output) if (not os.path.exists(initSystemPath)): FileUtil.createDirectory(initSystemPath) if (not os.path.exists(initSystemFile)): FileUtil.createFile(initSystemFile, False) FileUtil.writeFile(initSystemFile, ["#!/bin/bash"], "w") FileUtil.changeMode(DefaultValue.KEY_DIRECTORY_MODE, initSystemFile) return initSystemFile if (distname == "SuSE" and os.path.isfile(initFileSuse)): initFile = initFileSuse elif (distname in ("redhat", "centos", "euleros", "openEuler", "FusionOS") and os.path.isfile(initFileRedhat)): initFile = initFileRedhat elif (distname == "debian" and version == "buster/sid" and os.path.isfile(initFileUbuntu)): initFile = initFileUbuntu else: initFile = "" return initFile @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, output) = 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 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 getPathFileOfENV(envName): """ function : Get the env. input : envName output """ value = EnvUtil.getEnv(envName) if (value and not g_file.checkClusterPath(value)): raise Exception(ErrorCode.GAUSS_518["GAUSS_51805"] % envName + "It may have been modified after the cluster " "installation is complete.") return value @staticmethod def obtainInstStr(objectList): """ function : Obtain the message from the objectList input : List output : String """ info = "" if (isinstance(objectList, types.ListType)): for obj in objectList: info += "%s\n" % str(obj) return info @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 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 as e: return False @staticmethod def distributeRackFile(sshTool, hostList): """ function: Distributing the rack Information File input : NA output: NA """ rack_conf_file = os.path.realpath(os.path.join( EnvUtil.getEnv("GPHOME"), "script/gspylib/etc/conf/rack_info.conf")) rack_info_temp = os.path.realpath(os.path.join( EnvUtil.getEnv("GPHOME"), "script/gspylib/etc/conf/rack_temp.conf")) if os.path.isfile(rack_info_temp): shutil.move(rack_info_temp, rack_conf_file) if os.path.isfile(rack_conf_file): sshTool.scpFiles(rack_conf_file, rack_conf_file, hostList) @staticmethod def cleanUserEnvVariable(userProfile, cleanGAUSS_WARNING_TYPE=False, cleanGS_CLUSTER_NAME=True, cleanLD_LIBRARY=True): """ function : Clean the user environment variable input : String,boolean output : NA """ try: # check use profile if os.path.isfile(userProfile): # clean version FileUtil.deleteLine(userProfile, "^\\s*export\\" "s*GAUSS_VERSION=.*$") FileUtil.deleteLine(userProfile, "^\\s*export\\s*LD_LIBRARY_PATH=\\" "$GAUSSHOME\\/lib:\\$LD_LIBRARY_PATH$") if (cleanLD_LIBRARY): # clean lib FileUtil.deleteLine(userProfile, "^\\s*export\\s*LD_LIBRARY_PATH=\\" "$GAUSSHOME\\/lib\\/libsimsearch:\\" "$LD_LIBRARY_PATH$") FileUtil.deleteLine(userProfile, "^\\s*export\\s*LD_LIBRARY_PATH=\\$GPHOME\\" "/script\\/gspylib\\/clib:\\" "$LD_LIBRARY_PATH$") # clean bin FileUtil.deleteLine(userProfile, "^\\s*export\\s*PATH=\\$GAUSSHOME\\" "/bin:\\$PATH$") # clean GAUSSHOME FileUtil.deleteLine(userProfile, "^\\s*export\\s*GAUSSHOME=.*$") FileUtil.deleteLine(userProfile, "^\\s*export\\s*PGHOST=.*$") # clean GAUSSLOG FileUtil.deleteLine(userProfile, "^\\s*export\\s*GAUSSLOG=.*$") # clean S3_ACCESS_KEY_ID FileUtil.deleteLine(userProfile, "^\\s*export\\s*S3_ACCESS_KEY_ID=.*$") # clean S3_SECRET_ACCESS_KEY FileUtil.deleteLine(userProfile, "^\\s*export\\s*S3_SECRET_ACCESS_KEY=.*$") # clean S3_CLIENT_CRT_FILE FileUtil.deleteLine(userProfile, "^\\s*export\\s*S3_CLIENT_CRT_FILE=.*$") # clean ETCD_UNSUPPORTED_ARCH FileUtil.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 FileUtil.deleteLine(userProfile, "^if \[ -f .*\/env_ec") # clean GAUSS_WARNING_TYPE FileUtil.deleteLine(userProfile, "^\\s*export\\" "s*GAUSS_WARNING_TYPE=.*$") if (cleanGS_CLUSTER_NAME): # clean GS_CLUSTER_NAME FileUtil.deleteLine(userProfile, "^\\s*export\\" "s*GS_CLUSTER_NAME=.*$") # clean AGENTPATH FileUtil.deleteLine(userProfile, "^\\s*export\\s*AGENTPATH=.*$") # clean AGENTLOGPATH FileUtil.deleteLine(userProfile, "^\\s*export\\s*AGENTLOGPATH=" ".*$") # clean umask FileUtil.deleteLine(userProfile, "^\\s*umask\\s*.*$") except Exception as e: raise Exception(str(e)) @staticmethod def setComponentEnvVariable(userProfile, envList): """ funciton: Set component environment variable input: userProfile- env file, envList - environment variable list output: NA """ try: FileUtil.createFileInSafeMode(userProfile) with open(userProfile, "a") as fp: for inst_env in envList: fp.write(inst_env) fp.write(os.linesep) fp.flush() except Exception as e: raise Exception(ErrorCode.GAUSS_502["GAUSS_50205"] % userProfile + " Error: \n%s" % str(e)) @staticmethod def setUserEnvVariable(userProfile, installPath, tmpPath, logPath, agentPath, agentLogPath): """ function : Set the user environment variable input : String,String,String,String,String,String output : NA """ envList = ["export GAUSSHOME=%s" % installPath, \ "export PATH=$GAUSSHOME/bin:$PATH", \ "export LD_LIBRARY_PATH=$GAUSSHOME/lib:$LD_LIBRARY_PATH", \ "export S3_CLIENT_CRT_FILE=$GAUSSHOME/lib/client.crt", \ "export GAUSS_VERSION=%s" % VersionInfo.getPackageVersion(), \ "export PGHOST=%s" % tmpPath, \ "export GAUSSLOG=%s" % logPath, "umask 077"] if agentPath != '': envList.append("export AGENTPATH=%s" % agentPath) if agentLogPath != '': envList.append("export AGENTLOGPATH=%s" % agentLogPath) DefaultValue.setComponentEnvVariable(userProfile, envList) @staticmethod def createCADir(sshTool, caDir, hostList): """ function : create the dir of ca file input : config file path and ca dir path output : NA """ opensslFile = os.path.join(caDir, "openssl.cnf") tmpFile = os.path.join(os.path.realpath( os.path.join(caDir, "..")), "openssl.cnf") if (not os.path.isfile(opensslFile)): raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % opensslFile) # not rename file, just move it out and clean the dir, then move back cmd = g_file.SHELL_CMD_DICT["renameFile"] % (opensslFile, opensslFile, tmpFile) cmd += " && " + g_file.SHELL_CMD_DICT["cleanDir"] % (caDir, caDir, caDir) cmd += " && " + g_file.SHELL_CMD_DICT["renameFile"] % (tmpFile, tmpFile, opensslFile) sshTool.executeCommand(cmd, DefaultValue.SUCCESS, hostList) # create ./demoCA/newcerts ./demoCA/private newcertsPath = os.path.join(caDir, "demoCA/newcerts") FileUtil.createDirectory(newcertsPath) privatePath = os.path.join(caDir, "demoCA/private") FileUtil.createDirectory(privatePath) # touch files: ./demoCA/serial ./demoCA/index.txt serFile = os.path.join(caDir, "demoCA/serial") FileUtil.createFile(serFile, mode=DefaultValue.KEY_FILE_MODE) FileUtil.writeFile(serFile, ["01"]) indexFile = os.path.join(caDir, "demoCA/index.txt") FileUtil.createFile(indexFile, mode=DefaultValue.KEY_FILE_MODE) @staticmethod def createServerCA(caType, caDir, logger): """ function : create ca file input : ca file type and ca dir path output : NA """ if (caType == DefaultValue.SERVER_CA): logger.log("The sslcert will be generated in %s" % caDir) randpass = RandomValue.getRandStr() confFile = caDir + "/openssl.cnf" if not os.path.isfile(confFile): raise Exception(ErrorCode.GAUSS_502 ["GAUSS_50201"] % confFile) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl genrsa -aes256 -passout stdin -out " % \ (randpass) cmd += "demoCA/private/cakey.pem 2048" proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if (status != 0): raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % output) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl req -config openssl.cnf -new " % (randpass) cmd += "-key demoCA/private/cakey.pem -passin stdin " \ "-out " cmd += "demoCA/careq.pem -subj " cmd += "'/C=CN/ST=Beijing/L=Beijing/" cmd += "O=huawei/OU=gauss/CN=root'" proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) FileUtil.replaceFileLineContent("CA:FALSE", "CA:TRUE", confFile) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl ca -config openssl.cnf " % (randpass) cmd += "-batch -passin stdin -out demoCA/cacert.pem " \ "-keyfile " cmd += "demoCA/private/cakey.pem " cmd += "-selfsign -infiles demoCA/careq.pem " proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl genrsa -aes256 -passout stdin -out " \ "server.key 2048" % (randpass) proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl req -config openssl.cnf -new " % (randpass) cmd += "-key server.key -passin stdin -out server.req " \ "-subj " cmd += "'/C=CN/ST=Beijing/L=Beijing/" cmd += "O=huawei/OU=gauss/CN=server'" proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if (status != 0): raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) FileUtil.replaceFileLineContent("CA:TRUE", "CA:FALSE", confFile) indexAttrFile = caDir + "/demoCA/index.txt.attr" if os.path.isfile(indexAttrFile): FileUtil.replaceFileLineContent("unique_subject = yes", "unique_subject = no", indexAttrFile) else: raise Exception(ErrorCode.GAUSS_502 ["GAUSS_50201"] % indexAttrFile) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl ca -config openssl.cnf -batch -in " % (randpass) cmd += "server.req -passin stdin -out server.crt " \ "-days 3650 -md sha256 -subj " cmd += "'/C=CN/ST=Beijing/L=Beijing/" cmd += "O=huawei/OU=gauss/CN=server'" proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) cmd = CmdUtil.getCdCmd(caDir) cmd += " && gs_guc encrypt -M server -K '%s' -D ./ " % randpass proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) # client key randpassClient = RandomValue.getRandStr() cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl genrsa -aes256 -passout stdin -out " \ "client.key 2048" % (randpassClient) proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl req -config openssl.cnf " % (randpassClient) cmd += "-new -key client.key -passin stdin " \ "-out client.req -subj " cmd += "'/C=CN/ST=Beijing/L=Beijing/" cmd += "O=huawei/OU=gauss/CN=client'" proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl ca -config openssl.cnf " % (randpass) cmd += "-batch -in client.req -passin stdin -out " cmd += "client.crt -days 3650 -md sha256" proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) cmd = CmdUtil.getCdCmd(caDir) cmd += " && gs_guc encrypt -M client -K '%s' -D ./ " % randpassClient proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl pkcs8 -topk8 -outform DER" % randpassClient cmd += " -passin stdin " cmd += " -in client.key -out client.key.pk8 -nocrypt" proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) del randpass, randpassClient @staticmethod def changeOpenSslConf(confFile, hostList): """ function : change the openssl.cnf file input : confFile, hostList output : NA """ # Clean the old content. lineList = FileUtil.readFile(confFile) for i in range(len(lineList)): if ("[" in lineList[i] and "alt_names" in lineList[i] and "]" in lineList[i]): row = i + 1 FileUtil.deleteLineByRowNum(confFile, row) if ("DNS." in lineList[i] and "=" in lineList[i]): FileUtil.deleteLineByRowNum(confFile, row) # Add new one. dnsList = [] dnsList.append("\n") dnsList.append("[ alt_names ]") dnsList.append("DNS.1 = localhost") cont = 2 for host in hostList: dns = "DNS." + str(cont) + " = " + host dnsList.append(dns) cont = cont + 1 FileUtil.writeFile(confFile, dnsList) @staticmethod def is_create_grpc(logger, gauss_home_path): """ function : Check whether the grpc.conf file exists. input : logger object, gauss_home_path output : True or False """ logger.debug("Start check grpc.conf file.") conf_file = os.path.realpath(os.path.join(gauss_home_path, "share", "sslcert", "grpc", "openssl.cnf")) if os.path.isfile(conf_file): logger.debug("Exist openssl.cnf file [%s]." % conf_file) return True else: logger.debug("Does not exist openssl.cnf file [%s]." % conf_file) return False @staticmethod def createCA(caType, caDir): """ function : create ca file input : ca file type and ca dir path output : NA """ if caType == DefaultValue.GRPC_CA: randpass = RandomValue.getRandStr() confFile = caDir + "/openssl.cnf" if (os.path.isfile(confFile)): FileUtil.replaceFileLineContent("cakey.pem", "cakeynew.pem", confFile) FileUtil.replaceFileLineContent("careq.pem", "careqnew.pem", confFile) FileUtil.replaceFileLineContent("cacert.pem", "cacertnew.pem", confFile) FileUtil.replaceFileLineContent("server.key", "servernew.key", confFile) FileUtil.replaceFileLineContent("server.req", "servernew.req", confFile) FileUtil.replaceFileLineContent("server.crt", "servernew.crt", confFile) FileUtil.replaceFileLineContent("client.key", "clientnew.key", confFile) FileUtil.replaceFileLineContent("client.req", "clientnew.req", confFile) FileUtil.replaceFileLineContent("client.crt", "clientnew.crt", confFile) else: raise Exception(ErrorCode.GAUSS_502 ["GAUSS_50201"] % confFile) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl genrsa -aes256 -passout stdin -out " % \ (randpass) cmd += "demoCA/private/cakeynew.pem 2048" proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl req -config openssl.cnf -new " % (randpass) cmd += "-key demoCA/private/cakeynew.pem -passin stdin " \ "-out " cmd += "demoCA/careqnew.pem -subj " cmd += "'/C=CN/ST=Beijing/L=Beijing/" cmd += "O=huawei/OU=gauss/CN=root'" proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl ca -config openssl.cnf -days 7300 " % (randpass) cmd += "-batch -passin stdin -out demoCA/cacertnew.pem " \ "-md sha512 -keyfile " cmd += "demoCA/private/cakeynew.pem " cmd += "-selfsign -infiles demoCA/careqnew.pem " proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl genrsa -aes256 -passout stdin -out " \ "servernew.key 2048" % (randpass) proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl req -config openssl.cnf -new " % (randpass) cmd += "-key servernew.key -passin stdin -out servernew.req " \ "-subj " cmd += "'/C=CN/ST=Beijing/L=Beijing/" cmd += "O=huawei/OU=gauss/CN=root'" proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) indexAttrFile = caDir + "/demoCA/index.txt.attr" if (os.path.isfile(indexAttrFile)): FileUtil.replaceFileLineContent("unique_subject = yes", "unique_subject = no", indexAttrFile) else: raise Exception(ErrorCode.GAUSS_502 ["GAUSS_50201"] % indexAttrFile) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl ca -config openssl.cnf -batch -in " % (randpass) cmd += "servernew.req -passin stdin -out servernew.crt " \ "-days 7300 -md sha512" proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl genrsa -aes256 -passout stdin -out " \ "clientnew.key 2048" % (randpass) proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl req -config openssl.cnf " % (randpass) cmd += "-new -key clientnew.key -passin stdin " \ "-out clientnew.req -subj " cmd += "'/C=CN/ST=Beijing/L=Beijing/" cmd += "O=huawei/OU=gauss/CN=root'" proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) cmd = CmdUtil.getCdCmd(caDir) cmd += " && echo '%s' | openssl ca -config openssl.cnf " % (randpass) cmd += "-batch -in clientnew.req -passin stdin -out " cmd += "clientnew.crt -days 7300 -md sha512" proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) cmd = CmdUtil.getCdCmd(caDir) cmd += " && gs_guc encrypt -M server -K '%s' -D ./ " % randpass proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % output) cmd = CmdUtil.getCdCmd(caDir) cmd += " && gs_guc encrypt -M client -K '%s' -D ./ " % randpass (status, output) = subprocess.getstatusoutput(cmd) if status != 0: raise Exception(ErrorCode.GAUSS_514 ["GAUSS_51402"] + "Error:\n%s" % SensitiveMask.mask_pwd(output)) del randpass @staticmethod def cleanServerCaDir(caDir): """ function : clean the dir of ca file and change mode of ca files input : ca dir path output : NA """ certFile = caDir + "/demoCA/cacert.pem" if os.path.exists(certFile): FileUtil.moveFile(certFile, caDir) clientReq = caDir + "/server.req" FileUtil.removeFile(clientReq) clientReq = caDir + "/client.req" FileUtil.removeFile(clientReq) demoCA = caDir + "/demoCA" FileUtil.removeDirectory(demoCA) allCerts = caDir + "/*" FileUtil.changeMode(DefaultValue.KEY_FILE_MODE, allCerts) @staticmethod def cleanCaDir(caDir): """ function : clean the dir of ca file and change mode of ca files input : ca dir path output : NA """ certFile = caDir + "/demoCA/cacertnew.pem" if os.path.exists(certFile): FileUtil.moveFile(certFile, caDir) clientReq = caDir + "/clientnew.req" FileUtil.removeFile(clientReq) clientReq = caDir + "/servernew.req" FileUtil.removeFile(clientReq) demoCA = caDir + "/demoCA" FileUtil.removeDirectory(demoCA) allCerts = caDir + "/*" FileUtil.changeMode(DefaultValue.KEY_FILE_MODE, allCerts) @staticmethod def obtainSSDDevice(): """ function : Obtain the SSD device input : NA output : [] """ devList = [] cmd = "ls -ll /dev/hio? | awk '{print $10}'" (status, output) = subprocess.getstatusoutput(cmd) if (status == 0 and output.find("No such file or directory") < 0): devList = output.split("\n") else: raise Exception(ErrorCode.GAUSS_530["GAUSS_53005"] + " Command:%s. Error:\n%s" % (cmd, output)) return devList @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 KillAllProcess(userName, procName): """ function : Kill all processes by userName and procName. input : userName, procName output : boolean """ return ProcessUtil.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" % (CmdUtil.getPingCmd(ip, "5", "1"), CmdUtil.getGrepCmd(), CmdUtil.getWcCmd()) (status, output) = subprocess.getstatusoutput(cmd) if (str(output) == '0' or status != 0): g_lock.acquire() noPassIPs.append(ip) g_lock.release() @staticmethod def fast_ping(node_ip): """ ping node with short timeout """ cmd = "ping %s -c 1 -w 4" % node_ip proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) proc.communicate() status = proc.returncode result = (node_ip, True) if status == 0 else (node_ip, False) return result @staticmethod def fast_ping_on_node(on_node, from_ip, to_ip, logger): """ Ping on remote node with -I """ cmd = "ping %s -c 1 -w 4" % on_node proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) proc.communicate() status = proc.returncode if status != 0: logger.debug("Node:%s ping failed, can not execute remote check." % on_node) return on_node, False if on_node == NetUtil.GetHostIpOrName(): cmd_remote = "ping %s -I %s -c 1 -w 4" % (to_ip, from_ip) else: cmd_remote = "source %s && pssh -s -H %s 'ping %s -I %s -c 1 -w 4'" \ % (EnvUtil.getMpprcFile(), on_node, to_ip, from_ip) proc = FastPopen(cmd_remote, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) proc.communicate() status = proc.returncode result = (to_ip, True) if status == 0 else (to_ip, False) logger.debug("Remote ping result on node:%s, from ip:%s, to ip:%s, result:%s." % (on_node, from_ip, to_ip, result)) return result @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 killInstProcessCmd(instName, isRemote=False, signal=9, isExactMatch=True, instType="", procAbsPath="", instDir=""): """ 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 "" """ pstree = "python3 %s -sc" % os.path.realpath(os.path.dirname( os.path.realpath(__file__)) + "/../../py_pstree.py") # only cm_server need kill all child process, when do kill -9 if instName == "cm_server" and signal == 9: if isRemote: cmd = "pidList=\`ps ux | grep '\' | grep -v " \ "'grep' " \ "| awk '{print \$2}' | xargs \`; for pid in \$pidList;" \ " do %s \$pid | xargs -r -n 100 kill -9; echo " \ "'SUCCESS'; " \ "done" % pstree # only try to kill -9 process of cmserver cmd += "; ps ux | grep '\' | grep -v grep | awk " \ "'{print \$2}' | xargs -r kill -9; echo 'SUCCESS'" else: cmd = "pidList=`ps ux | grep '\' | grep -v " \ "'grep' |" \ " awk '{print $2}' | xargs `; for pid in $pidList; " \ "do %s $pid | xargs -r -n 100 kill -9; echo 'SUCCESS';" \ " done" % pstree cmd += "; ps ux | grep '\' | grep -v grep | " \ "awk '{print $2}' | xargs -r kill -9; echo 'SUCCESS'" 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 " % (instName, signal) else: cmd = "ps ux | grep '\<%s\>' | grep -v grep | awk " \ "'{print $2}' | xargs -r kill -%d " % (instName, signal) else: if (isRemote): cmd = "ps ux | grep '%s' | grep -v grep | awk " \ "'{print \$2}' | xargs -r kill -%d " % (instName, signal) else: cmd = "ps ux | grep '%s' | grep -v grep | " \ "awk '{print $2}' | xargs -r kill -%d " % (instName, signal) return cmd @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"] + " Command:%s. Error:\n%s" % (cmd, output)) retryTimes = retryTimes + 1 time.sleep(3) @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) LocalRemoteCmd.checkRemoteDir(g_sshTool, xmlDir, hostname, mpprcFile, localMode) local_node = NetUtil.GetHostIpOrName() # Skip local file overwriting if not hostname: hostname = g_sshTool.hostNames[:] if local_node in hostname: hostname.remove(local_node) if (not localMode): # Send xml file to every host g_sshTool.scpFiles(confFile, xmlDir, hostname, mpprcFile) # change owner and mode of xml file cmd = CmdUtil.getChmodCmd(str(DefaultValue.FILE_MODE), confFile) CmdExecutor.execCommandWithMode(cmd, g_sshTool, localMode, mpprcFile, hostname) except Exception as e: raise Exception(str(e)) @staticmethod def getSecurityMode(): """ function:to set security mode,if security_mode is not in config file,return off. input:String output:String """ securityModeValue = "off" try: cmd = "ps -ux | grep \"\\-\\-securitymode\" | grep -v \"grep\"" (status, output) = subprocess.getstatusoutput(cmd) if status != 0 and output != "": raise Exception( (ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + "Error: \n %s" % output)) if output != "": securityModeValue = "on" return securityModeValue except Exception as ex: raise Exception(str(ex)) @staticmethod def checkTransactionReadonly(user, DbclusterInfo, normalCNList=None): """ function : check the CN's parameter default_transaction_read_only is on if eques on, return 1 and error info input : user, DbclusterInfo, normalCNList output : 0/1 """ cnList = [] if normalCNList is None: normalCNList = [] localhost = NetUtil.GetHostIpOrName() sql = "show default_transaction_read_only;" try: if (len(normalCNList)): cnList = normalCNList else: # Find CN instance in cluster for dbNode in DbclusterInfo.dbNodes: if (len(dbNode.coordinators) != 0): cnList.append(dbNode.coordinators[0]) security_mode_value = DefaultValue.getSecurityMode() # Execute sql on every CN instance if (security_mode_value == "on"): for cooInst in cnList: if (localhost == cooInst.hostname): (status, result, error_output) = \ SqlExecutor.excuteSqlOnLocalhost(cooInst.port, sql) if (status != 2): return 1, "[%s]: Error: %s result: %s status: " \ "%s" % \ (cooInst.hostname, error_output, result, status) if (result[0][0].strip().lower() == "on"): return 1, "The database is in read only mode." else: currentTime = time.strftime("%Y-%m-%d_%H:%M:%S") pid = os.getpid() outputfile = "metadata_%s_%s_%s.json" % ( cooInst.hostname, pid, currentTime) tmpDir = EnvUtil.getTmpDirFromEnv() filepath = os.path.join(tmpDir, outputfile) ClusterCommand.executeSQLOnRemoteHost(cooInst.hostname, cooInst.port, sql, filepath) (status, result, error_output) = \ SqlExecutor.getSQLResult(cooInst.hostname, outputfile) if (status != 2): return 1, "[%s]: Error: %s result: %s status: " \ "%s" % \ (cooInst.hostname, error_output, result, status) if (result[0][0].strip().lower() == "on"): return 1, "The database is in read only mode." else: for cooInst in cnList: (status, output) = ClusterCommand.remoteSQLCommand( sql, user, cooInst.hostname, cooInst.port) resList = output.split('\n') if (status != 0 or len(resList) < 1): return 1, "[%s]: %s" % (cooInst.hostname, output) if (resList[0].strip() == "on"): return 1, "The database is in read only mode." return 0, "success" except Exception as e: return 1, str(e) @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 checkSHA256(binFile, sha256File): """ """ if binFile == "": raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % "bin file") if sha256File == "": raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % "verification file") sha256Obj = hashlib.sha256() if not sha256Obj: raise Exception(ErrorCode.GAUSS_502["GAUSS_50238"] % binFile + "can not get verification Obj.") with open(binFile, "rb") as filebin: while True: strRead = filebin.read(8096) if not strRead: break sha256Obj.update(strRead) strSHA256 = sha256Obj.hexdigest() with open(sha256File, "r") as fileSHA256: strRead = fileSHA256.readline() oldSHA256 = strRead.strip() if strSHA256 != oldSHA256: raise Exception(ErrorCode.GAUSS_502["GAUSS_50238"] % binFile) @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}'" % \ (CmdUtil.getDiskFreeCmd(path), CmdUtil.getAwkCmd()) (status, output) = subprocess.getstatusoutput(dfCmd) if (status != 0): g_logger.logExit(ErrorCode.GAUSS_502["GAUSS_50219"] % "the system file directory" + " Command:%s. Error:\n%s" % (dfCmd, output)) 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 getPrimaryDnNum(dbClusterInfoGucDnPr): """ """ dataCount = 0 dbNodeList = dbClusterInfoGucDnPr.dbNodes for dbNode in dbNodeList: dataCount = dataCount + dbNode.dataNum return dataCount @staticmethod def getPhysicMemo(PhsshTool, instaLocalMode): """ """ if instaLocalMode: cmd = g_file.SHELL_CMD_DICT["physicMemory"] (status, output) = subprocess.getstatusoutput(cmd) if (status != 0): raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + "Error:\n%s" % str(output)) else: memTotalList = output.split("\n") for content in memTotalList: if ("MemTotal" in content): memoList = content.split(":") memo = memoList[1] memo = memo.replace("kB", "") memo = memo.replace("\n", "") memo = memo.strip() memo = int(memo) / 1024 / 1024 return memo physicMemo = [] cmd = g_file.SHELL_CMD_DICT["physicMemory"] (status, output) = PhsshTool.getSshStatusOutput(cmd) for ret in status.values(): if (ret != DefaultValue.SUCCESS): raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + "Error:\n%s" % str(output)) memTotalList = output.split("\n") for content in memTotalList: if ("MemTotal" in content): memoList = content.split(":") memo = memoList[1] memo = memo.replace("kB", "") memo = memo.strip() memo = int(memo) / 1024 / 1024 physicMemo.append(memo) minPhysicMemo = min(physicMemo) return minPhysicMemo @staticmethod def getDataNodeNum(dbClusterInfoGucDn): """ """ dataNodeNum = [] dbNodeList = dbClusterInfoGucDn.dbNodes for dbNode in dbNodeList: dataNodeNum.append(dbNode.dataNum) maxDataNodeNum = max(dataNodeNum) return maxDataNodeNum @staticmethod def dynamicGuc(instanceType, tmpGucFile, gucXml=False): """ function: set hba config input : NA output: NA """ try: instance = instanceType gucList = FileUtil.readFile(tmpGucFile) gucStr = gucList[0].replace("\n", "") dynamicParaList = gucStr.split(",") for guc in dynamicParaList: if (guc == ""): raise Exception(ErrorCode.GAUSS_502["GAUSS_50203"] % gucStr) # getting the path of guc_list.conf. dirName = os.path.dirname(os.path.realpath(__file__)) if gucXml: gucFile = os.path.join(dirName, "./../etc/conf/guc_cloud_list.xml") else: gucFile = os.path.join(dirName, "./../etc/conf/guc_list.xml") gucFile = os.path.normpath(gucFile) # reading xml. gucDict = {} rootNode = ClusterConfigFile.initParserXMLFile(gucFile) instanceEle = rootNode.find(instance) instanceList = instanceEle.findall("PARAM") for gucElement in instanceList: DefaultValue.checkGuc(gucElement.attrib['VALUE']) gucDict[gucElement.attrib['KEY']] = gucElement.attrib['VALUE'] gucParaDict = DefaultValue.initGuc(gucDict, dynamicParaList, gucXml) return gucParaDict except Exception as e: raise Exception(str(e)) @staticmethod def checkGuc(gucValue): """ function: check path vaild input : envValue output: NA """ gucCheckList = ["|", ";", "&", "$", "<", ">", "`", "{", "}", "[", "]", "~", "?", " ", "!"] if (gucValue.strip() == ""): return for rac in gucCheckList: flag = gucValue.find(rac) if gucValue.strip() == "%x %a %m %u %d %h %p %S" and rac == " ": continue if flag >= 0: raise Exception(ErrorCode.GAUSS_502["GAUSS_50219"] % gucValue + " There are illegal characters %s " "in the content." % rac) @staticmethod def calculate_dynamic_size(raw_str, dynamic_para_list): if (int(dynamic_para_list[0]) < 256): ratioNum = 1 elif (int(dynamic_para_list[0]) < 512): ratioNum = 2 else: ratioNum = 3 value = raw_str.replace("PHYSIC_MEMORY", dynamic_para_list[1]) \ .replace("MAX_MASTER_DATANUM_IN_ONENODE", dynamic_para_list[2]) \ .replace("N", str(ratioNum)) try: value = eval(value) except: raise Exception(ErrorCode.GAUSS_516["GAUSS_51632"] % "calculate: %s " % raw_str) return value # float, 单位 GB @staticmethod def initGuc(gucDict, dynamicParaList, gucXml=False): """ dynamicParaList 格式: [主dn的个数, 集群中最小物理内存(单位GB), dn的总数] """ gucDict = {k: v for k, v in gucDict.items() if v} for guc, value in gucDict.items(): if (guc == "comm_max_datanode" and not gucXml): primary_dn_num = int(dynamicParaList[0]) if primary_dn_num < 256: gucDict[guc] = 256 elif primary_dn_num < 512: gucDict[guc] = 512 elif primary_dn_num < 1024: gucDict[guc] = 1024 elif primary_dn_num < 2048: gucDict[guc] = 2048 else: gucDict[guc] = 4096 continue elif guc == "max_process_memory": if "PHYSIC_MEMORY" not in value \ and "MAX_MASTER_DATANUM_IN_ONENODE" not in value: continue # 下面是依据物理内存计算 gigabytes = DefaultValue.calculate_dynamic_size(value, dynamicParaList) if (gigabytes >= 2 and gigabytes <= 2047): gucDict[guc] = str(int(gigabytes)) + "GB" elif (gigabytes < 2): gucDict[guc] = "2GB" else: gucDict[guc] = "2047GB" continue elif guc == "shared_buffers": if "PHYSIC_MEMORY" not in value \ and "MAX_MASTER_DATANUM_IN_ONENODE" not in value: continue gigabytes = DefaultValue.calculate_dynamic_size(value, dynamicParaList) megabytes = int(gigabytes * 1024) if megabytes >= 1024: gucDict[guc] = "1GB" else: gucDict[guc] = str(megabytes) + "MB" return gucDict @staticmethod def getPrivateGucParamList(): """ function : Get the private guc parameter list. input : NA output """ # only used by dummy standby instance # max_connections value is 100 # memorypool_enable value is false # shared_buffers value is 32MB # bulk_write_ring_size value is 32MB # max_prepared_transactions value is 10 # cstore_buffers value is 16MB # autovacuum_max_workers value is 0 # max_pool_size value is 50 # wal_buffers value is -1 # add the parameter content to the dictionary list priavetGucParamDict = {} priavetGucParamDict["max_connections"] = "100" priavetGucParamDict["memorypool_enable"] = "false" priavetGucParamDict["shared_buffers"] = "32MB" priavetGucParamDict["bulk_write_ring_size"] = "32MB" priavetGucParamDict["max_prepared_transactions"] = "10" priavetGucParamDict["cstore_buffers"] = "16MB" priavetGucParamDict["autovacuum_max_workers"] = "0" priavetGucParamDict["wal_buffers"] = "-1" priavetGucParamDict["max_locks_per_transaction"] = "64" priavetGucParamDict["sysadmin_reserved_connections"] = "3" priavetGucParamDict["max_wal_senders"] = "4" return priavetGucParamDict @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 = EnvUtil.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 EnvUtil.getEnv("PGKRBSRVNAME")): return True return False @staticmethod def setActionFlagFile(module="", mode=True): """ function: Set action flag file input : module output: NAself """ if os.getuid() == 0: return # Get the temporary directory from PGHOST tmpDir = EnvUtil.getTmpDirFromEnv() if not tmpDir: raise Exception(ErrorCode.GAUSS_518["GAUSS_51802"] % "PGHOST") # check if tmp dir exists if not os.path.exists(tmpDir): raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % tmpDir + " Please check it.") if not os.access(tmpDir, os.R_OK | os.W_OK | os.X_OK): raise Exception(ErrorCode.GAUSS_501["GAUSS_50103"] % tmpDir) actionFlagFile = os.path.join(tmpDir, DefaultValue.ACTION_FLAG_FILE + "_%s" % os.getpid()) if mode: FileUtil.createFileInSafeMode(actionFlagFile) with open(actionFlagFile, "w") as fp: fp.write(module) fp.flush() os.chmod(actionFlagFile, ConstantsBase.KEY_FILE_PERMISSION) else: if os.path.exists(actionFlagFile): os.remove(actionFlagFile) @staticmethod def isUnderUpgrade(user): tempPath = EnvUtil.getTmpDirFromEnv(user) bakPath = os.path.join(tempPath, "binary_upgrade") if os.path.isdir(bakPath): if os.listdir(bakPath): return True return False @staticmethod def enableWhiteList(sshTool, mpprcFile, nodeNames, logger): """ function: write environment value WHITELIST_ENV for agent mode input : sshTool, mpprcFile, nodeNames, logger output: NA """ env_dist = os.environ if "HOST_IP" in env_dist.keys(): cmd = "sed -i '/WHITELIST_ENV=/d' %s ; " \ "echo 'export WHITELIST_ENV=1' >> %s" % (mpprcFile, mpprcFile) sshTool.executeCommand(cmd, DefaultValue.SUCCESS, nodeNames) logger.debug("Successfully write $WHITELIST_ENV in %s" % mpprcFile) @staticmethod def checkDockerEnv(): cmd = "egrep '^1:.+(docker|lxc|kubepods)' /proc/1/cgroup" (status, output) = subprocess.getstatusoutput(cmd) if output: return True else: return False @staticmethod def getSpecificNode(userProfile, flagStr, logger=None): """ :param flagStr: Primary/Standby/Cascade :return: correspond nodes """ try: count = 0 while count < 30: cmd = "source {0} && gs_om -t query".format( userProfile) (status, output) = subprocess.getstatusoutput(cmd) if status == 0 and ("cluster_state : Normal" in output \ or "cluster_state : Degraded" in output): break if count == 2: start_cmd = "source {0} && gs_om -t start --time-out 30".format(userProfile) _, output = subprocess.getstatusoutput(start_cmd) if logger: logger.debug("Start cluster for get current primary datanode, " "the result is : \n{0}".format(output)) time.sleep(10) count += 1 if status != 0: raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % "Command:%s. Error:\n%s" % (cmd, output)) targetString = output.split("Datanode")[1] dnPrimary = [x for x in re.split(r"[|\n]", targetString) if flagStr in x or "Main" in x] primaryList = [] for dn in dnPrimary: primaryList.append(list(filter(None, dn.split(" ")))[1]) return primaryList, output except Exception as e: raise Exception(str(e)) @staticmethod def getPrimaryNode(userProfile, logger=None): """ :param :return: PrimaryNode """ return DefaultValue.getSpecificNode(userProfile, "Primary", logger) @staticmethod def getStandbyNode(userProfile, logger=None): """ :param :return: StandbyNode """ return DefaultValue.getSpecificNode(userProfile, "Standby", logger) @staticmethod def non_root_owner(filepath): """ :param filepath: :return: """ if not os.path.exists(filepath): return False if os.stat(filepath).st_uid != 0: return True return False @staticmethod def check_cm_package(cluster_info, package_path, logger): """ Check CM package """ if cluster_info.cmscount == 0: logger.debug("No CM instance in configure file.") return True logger.debug("There include cm instance on local node.") if not os.path.isfile(package_path): logger.debug("CM is config in configure file, but not exist cm package.") return False logger.debug("CM is config in configure file and cm package exist.") return True @staticmethod def get_cm_server_num_from_static(cluster_info): """ Get cm_server num from static config file """ cm_server_num = 0 for db_node in cluster_info.dbNodes: cm_server_num += len(db_node.cmservers) return cm_server_num @staticmethod def get_secret(length=32): """ function : random secret input : int output : string """ secret_types = string.ascii_letters + string.digits + string.punctuation exception_str = "`;$'\"{}[\\" while True: secret_word = ''.join(secrets.choice(secret_types) for _ in range(length)) check_flag = False for i in exception_str: if i in secret_word: check_flag = True break if check_flag: continue if (any(c.islower() for c in secret_word) and any(c.isupper() for c in secret_word) and any(c in string.punctuation for c in secret_word) and sum(c.isdigit() for c in secret_word) >= 4): break return secret_word @staticmethod def check_add_cm(old_cluster_config_file, new_cluster_config_file, logger): """ Check need install CM instance """ old_cluster_info = dbClusterInfo() new_cluster_info = dbClusterInfo() user = pwd.getpwuid(os.getuid()).pw_name old_cluster_info.initFromStaticConfig(user, old_cluster_config_file) new_cluster_info.initFromStaticConfig(user, new_cluster_config_file) if DefaultValue.get_cm_server_num_from_static(new_cluster_info) > 0 and \ DefaultValue.get_cm_server_num_from_static(old_cluster_info) == 0: logger.debug("Need to install CM instance to node.") return True logger.debug("No need to install CM instance to node.") return False @staticmethod def try_fast_popen(cmd, retry_time=3, sleep_time=1, check_output=False): """ function : retry getStatusoutput @param cmd: command going to be execute @param retry_time: default retry 3 times after execution failure @param sleep_time: default sleep 1 second then start retry """ retry_time += 1 for i in range(retry_time): proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = proc.communicate() if proc.returncode != 0: time.sleep(sleep_time) elif check_output: if str(stdout+stderr).strip(): break else: time.sleep(sleep_time) else: break return proc.returncode, stdout, stderr @staticmethod def get_ssh_protect_path(): """ get the temp path :return: string """ ssh_protect_path = os.path.expanduser(Constants.SSH_PROTECT_PATH) if not os.path.exists(ssh_protect_path): FileUtil.createDirectory(ssh_protect_path, mode=DefaultValue.KEY_DIRECTORY_MODE) if os.path.isdir(ssh_protect_path): dir_permission = oct(os.stat(ssh_protect_path).st_mode)[-3:] if dir_permission != str(DefaultValue.KEY_DIRECTORY_MODE): os.chmod(ssh_protect_path, stat.S_IRWXU) else: msg = "Failed to create the directory because the file" msg = "%s %s with the same name exists." % ( msg, ssh_protect_path) raise Exception(msg) return ssh_protect_path @staticmethod def get_dn_info(cluster_info): """ Get primary dn info """ instances = [] dn_instances = [dn_inst for db_node in cluster_info.dbNodes for dn_inst in db_node.datanodes if int(dn_inst.mirrorId) == 1] for dn_inst in dn_instances: dn_info = {} dn_info["id"] = dn_inst.instanceId dn_info["data_dir"] = dn_inst.datadir dn_info["host_name"] = dn_inst.hostname instances.append(dn_info) return instances @staticmethod def get_local_ips(): """ get local node all ips :return: """ # eg "ip_mappings: [('lo', '127.0.0.1'), ('eth1', '10.10.10.10')]" ip_mappings = NetUtil.getIpAddressAndNICList() local_ips = [] for ip_info in ip_mappings: local_ips.append(ip_info[1]) return local_ips @staticmethod def get_pid(desc): """ function : get the ID of the process that contains the specified content input : string output : list """ pids = [] cmd = "ps ux | grep '%s' | grep -v grep" % desc proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = proc.communicate() if stderr: raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + "Error: %s." % str(stderr)) for pid_line in stdout.split(os.linesep): if len(pid_line.strip().split()) > 2: pid = pid_line.strip().split()[1] if pid.isdigit(): pids.append(str(pid)) return pids @staticmethod def clear_ssh_id_rsa(mpprcfile, logger=""): """ :param mpprcfile: :param logger: :return: """ clear_cmd = "source %s;ssh-add -D" %mpprcfile status, output = subprocess.getstatusoutput(clear_cmd) if status != 0: if logger: logger.error("Failed to clear id_rsa in ssh-agent,Errors:%s" % output) raise Exception( ErrorCode.GAUSS_516["GAUSS_51632"] % "clear ssh agent" + " Error:\n%s" % (output)) if logger: logger.debug("Successfully to clear id_rsa in ssh-agent") @staticmethod def add_ssh_id_rsa(secret_word, mpprcfile, shell_file, logger=""): """ :param secret_word: :param mpprcfile: :param logger: :return: """ DefaultValue.clear_ssh_id_rsa(mpprcfile, logger) id_rsa_path = DefaultValue.SSH_PRIVATE_KEY cmd = "source %s;echo \"%s\" | /bin/sh %s %s" %( mpprcfile, str(secret_word), shell_file, id_rsa_path) if logger: logger.debug("ssh-add cmd:%s" %cmd) (status, stdout, stderr) = DefaultValue.try_fast_popen(cmd) output = stdout + stderr if logger: logger.debug("add ssh id_rsa status:%s" %status) logger.debug("add ssh id_rsa output:%s" %output) if status != 0: raise Exception("Failed to ssh-add perform.Error: %s" % output) if logger: logger.debug("Successfully to add id_rsa in ssh-agent") @staticmethod def register_ssh_agent(mpprcfile, logger=""): """ function : register ssh agent input : NA output : NA """ if logger: logger.debug("Start to register ssh agent.") agent_path = os.path.join("~/gaussdb_tmp/", "gauss_socket_tmp") agent_path = os.path.expanduser(agent_path) cmd = "ssh-agent -a %s" % (agent_path) cmd_ssh_add = "source %s;ssh-agent -a %s" % (mpprcfile, agent_path) list_pid = DefaultValue.get_pid(cmd) if not list_pid: if os.path.exists(agent_path): os.remove(agent_path) status, output = subprocess.getstatusoutput(cmd_ssh_add) if status != 0 and "Address already in use" not in output: if logger: logger.error("cms is: %s;Errors:%s" % (cmd_ssh_add, output)) raise Exception( ErrorCode.GAUSS_516["GAUSS_51632"] % "register ssh agent" + "cmd is:%s;Error:\n%s" % (cmd_ssh_add, output)) bashrc_file = os.path.join(pwd.getpwuid(os.getuid()).pw_dir, ".bashrc") ProfileFile.updateUserEnvVariable(bashrc_file, "SSH_AUTH_SOCK", agent_path) if logger: logger.debug("Update environment value SSH_AUTH_SOCK successfully.") update_pid_env_flag = False list_pid = DefaultValue.get_pid(cmd) if not list_pid: raise Exception( ErrorCode.GAUSS_516["GAUSS_51632"] % "register ssh agent" + " Error:\nCan't find the process of ssh agent") for pid in list_pid: if str(pid): ProfileFile.updateUserEnvVariable(bashrc_file, "SSH_AGENT_PID", str(pid)) if logger: logger.debug("Update environment value SSH_AGENT_PID successfully.") update_pid_env_flag = True break if not update_pid_env_flag: raise Exception( ErrorCode.GAUSS_518["GAUSS_51804"] % "SSH_AGENT_PID") DefaultValue.check_use_ssh_agent(cmd, bashrc_file, logger) if logger: logger.debug("ssh-add perform successfully.") @staticmethod def check_use_ssh_agent(cmd, mpprcfile, logger="", retry_imes=6): """ function:check whether the ssh-agent process is available :param cmd: :param logger: :param retryTimes: :return: """ RETRY_TIMES = 0 while True: check_cmd = "source %s;ssh-add -D" % mpprcfile proc = FastPopen(check_cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output = stdout + stderr status = proc.returncode if status == 0: if logger: logger.debug("The ssh-agent process is available") break if logger: logger.debug("ssh-add -D status:%s" %status) logger.debug("ssh-add -D output:%s" %output) if RETRY_TIMES >= retry_imes: if logger: logger.error("Failed to check whether thessh-agent " "process is available") raise Exception((ErrorCode.GAUSS_535["GAUSS_53507"] % check_cmd) + "Errors:%s" %output) DefaultValue.eval_ssh_agent(cmd, mpprcfile, logger) time.sleep(2) RETRY_TIMES += 1 @staticmethod def eval_ssh_agent(cmd, mpprcfile, logger): """ eval ssh-agent process and ensure that there is only one ssh-agent working process :param list_pid: :return: """ err_msg = ErrorCode.GAUSS_511["GAUSS_51108"] try: ssh_agent = "ssh-agent" list_agent_pid = DefaultValue.get_pid("ssh-agent") list_pid = DefaultValue.get_pid(cmd) if list_pid and list_agent_pid and len(list_agent_pid) > 1: kill_cmd = "ps ux|grep '%s'|grep -v '%s'|grep -v grep |" \ " awk '{print $2}'| xargs kill -9" % (ssh_agent, cmd) status, output = subprocess.getstatusoutput(kill_cmd) if status != 0: if logger: logger.error( (ErrorCode.GAUSS_535["GAUSS_53507"] % kill_cmd) + "Errors:%s" % output) raise Exception( (ErrorCode.GAUSS_535["GAUSS_53507"] % kill_cmd) + "Errors:%s" % output) eval_ssh_agent = "source %s;eval `ssh-agent -s`" % mpprcfile (status, stdout, stderr) = DefaultValue.try_fast_popen(eval_ssh_agent) output = stdout + stderr if logger: logger.debug("eval_ssh_agent status:%s" % status) logger.debug("eval_ssh_agent output:%s" % output) if status != 0: raise Exception( (ErrorCode.GAUSS_535["GAUSS_53507"] % eval_ssh_agent) + "Errors:%s" % output) if logger: logger.debug("Successfully to eval ssh agent") except Exception as e: raise Exception("%s %s" % (err_msg, str(e))) @staticmethod def register_remote_ssh_agent(session, remote_ip, logger=""): """ function : register ssh agent input : NA output : NA """ if logger: logger.debug("Start to register ssh agent on [%s] node." % remote_ip) agent_path = os.path.join("~/gaussdb_tmp/", "gauss_socket_tmp") agent_path = os.path.expanduser(agent_path) kill_ssh_agent_cmd = "ps ux|grep 'ssh-agent'|grep -v grep |" \ " awk '{print $2}'| xargs kill -9" DefaultValue.kill_remote_process(session, kill_ssh_agent_cmd, logger) DefaultValue.add_remote_ssh_agent(session, agent_path, logger) if logger: logger.debug("ssh-add perform successfully on [%s] node ." % remote_ip) @staticmethod def add_remot_ssh_id_rsa(session, secret_word, mpprcfile, shell_file, logger=""): """ :param session: :param secret_word: :param mpprcfile: :param shell_file: :param logger: :return: """ clear_cmd = "source %s;ssh-add -D" % mpprcfile (env_msg, channel_read) = DefaultValue.ssh_exec_cmd(session, clear_cmd) if env_msg and "All identities removed" not in env_msg: if logger: logger.error( "Failed to clear id_rsa in ssh-agent,Errors:%s" % env_msg) raise Exception( ErrorCode.GAUSS_516["GAUSS_51632"] % "clear ssh agent" + " Error:\n%s" % (env_msg)) if logger: logger.debug("Successfully to clear id_rsa in ssh-agent") id_rsa_path = DefaultValue.SSH_PRIVATE_KEY cmd = "source %s;echo \"%s\" | /bin/sh %s %s" % ( mpprcfile, str(secret_word), shell_file, id_rsa_path) if logger: logger.debug("ssh-add cmd:%s" % cmd) (env_msg, channel_read) = DefaultValue.ssh_exec_cmd(session, cmd) if env_msg: logger.debug("add ssh id_rsa output:%s" % env_msg) raise Exception("Failed to ssh-add perform.Error: %s" % env_msg) if logger: logger.debug("add ssh id_rsa output:%s" % channel_read) logger.debug("Successfully to add id_rsa in ssh-agent") @staticmethod def kill_remote_process(session, kill_cmd, logger=""): """ :param ssh_agent: :return: """ (env_msg, channel_read) = DefaultValue.ssh_exec_cmd(session, kill_cmd) if logger: logger.debug("cmd is %s; result is:%s;error is:%s." % (kill_cmd, channel_read, env_msg)) @staticmethod def add_remote_ssh_agent(session, agent_path, logger=""): """ :param session: :param agent_path: :param logger: :return: """ delete_cmd = "rm -rf %s" % agent_path DefaultValue.ssh_exec_cmd(session, delete_cmd) cmd = "ssh-agent -a %s" % agent_path cmd_ssh_add = "source %s;ssh-agent -a %s" % (ClusterConstants.ETC_PROFILE, agent_path) (env_msg, channel_read) = DefaultValue.ssh_exec_cmd(session, cmd_ssh_add) if env_msg and "Address already in use" not in env_msg: if logger: logger.error("cms is: %s;Errors:%s" % (cmd_ssh_add, env_msg)) raise Exception( ErrorCode.GAUSS_516["GAUSS_51632"] % "register remote ssh agent" + "cmd is:%s;Error:\n%s" % (cmd_ssh_add, env_msg)) bashrc_file = os.path.join(pwd.getpwuid(os.getuid()).pw_dir, ".bashrc") DefaultValue.update_user_env_variable_cmd( session, bashrc_file, "SSH_AUTH_SOCK", agent_path, logger) if logger: logger.debug("Update environment value SSH_AUTH_SOCK successfully.") list_pid = DefaultValue.get_remote_pid(session, cmd, logger) if not list_pid: raise Exception( ErrorCode.GAUSS_516["GAUSS_51632"] % "register ssh agent" + " Error:\nCan't find the process of ssh agent") update_pid_env_flag = False for pid in list_pid: if str(pid): DefaultValue.update_user_env_variable_cmd( session, bashrc_file, "SSH_AGENT_PID", str(pid), logger) if logger: logger.debug("Update environment value SSH_AGENT_PID successfully.") update_pid_env_flag = True break if not update_pid_env_flag: raise Exception( ErrorCode.GAUSS_518["GAUSS_51804"] % "SSH_AGENT_PID") DefaultValue.eval_remote_ssh_agent(session, cmd, bashrc_file, logger) @staticmethod def update_user_env_variable_cmd(session, userProfile, variable, value, logger=""): """ function : Update the user environment variable input : String,String,String output : NA :param session: :param userProfile: :param variable: :param value: :param logger: :return: """ try: # delete old env information delete_content = "^\\s*export\\s*%s=.*$" % variable delete_line_cmd = "sed -i '/%s/d' %s" % (delete_content, userProfile) # write the new env information into userProfile write_content = 'export %s=%s' % (variable, value) write_line_cmd = "sed -i '$a%s' %s" % (write_content, userProfile) update_cmd = "%s && %s" % (delete_line_cmd, write_line_cmd) (env_msg, channel_read) = DefaultValue.ssh_exec_cmd(session, update_cmd) if env_msg: if logger: logger.error( "cms is: %s;Errors:%s" % (update_cmd, env_msg)) raise Exception( ErrorCode.GAUSS_516["GAUSS_51632"] % "update env file;" + "cmd is:%s;Error:\n%s." % (update_cmd, env_msg)) except Exception as e: raise Exception(str(e)) @staticmethod def get_remote_pid(session, process, logger=""): """ function : get the ID of the process that contains the specified content input : string output : list """ pids = [] cmd = "ps ux | grep '%s' | grep -v grep" % process (env_msg, channel_read) = DefaultValue.ssh_exec_cmd(session, cmd) if env_msg: if logger: logger.error("cms is: %s;Errors:%s" % (cmd, env_msg)) raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + "Error: %s." % str(env_msg)) for pid_line in channel_read.split(os.linesep): if len(pid_line.strip().split()) > 2: pid = pid_line.strip().split()[1] if pid.isdigit(): pids.append(str(pid)) return pids @staticmethod def eval_remote_ssh_agent(session, cmd, mpprcfile, logger): """ eval remote ssh-agent process and ensure that there is only one ssh-agent working process :param list_pid: :return: """ err_msg = ErrorCode.GAUSS_511["GAUSS_51108"] try: ssh_agent = "ssh-agent" list_agent_pid = DefaultValue.get_pid("ssh-agent") list_pid = DefaultValue.get_remote_pid(session, cmd, logger) if list_pid and list_agent_pid and len(list_agent_pid) > 1: kill_cmd = "ps ux|grep '%s'|grep -v '%s'|grep -v grep |" \ " awk '{print $2}'| xargs kill -9" % (ssh_agent, cmd) DefaultValue.kill_remote_process(session, kill_cmd, logger) eval_ssh_agent = "source %s;eval `ssh-agent -s`" % mpprcfile (env_msg, channel_read) = DefaultValue.ssh_exec_cmd(session, eval_ssh_agent) if env_msg: raise Exception( (ErrorCode.GAUSS_535["GAUSS_53507"] % eval_ssh_agent) + "Errors:%s" % env_msg) if logger: logger.debug("eval_ssh_agent output:%s" % channel_read) if logger: logger.debug("Successfully to eval ssh agent") except Exception as e: raise Exception("%s %s" % (err_msg, str(e))) @staticmethod def ssh_exec_cmd(session, cmd): ''' ssh remote node and execute cmd :param session: :param cmd: :return: ''' # make sure no echo ssh_channel = session.open_session() ssh_channel.exec_command(cmd) env_msg = ssh_channel.recv_stderr(9999).decode().strip() channel_read = ssh_channel.recv(9999).decode().strip() return env_msg, channel_read @staticmethod def remove_metadata_and_dynamic_config_file(user, ssh_tool, logger): """ Remove CM metadata directory and dynamic_config file, because of CM need flush dcc value. """ logger.debug("Start remove CM metadata directory and dynamic_config_file.") # This cluster info is new cluster info. cluster_info = dbClusterInfo() cluster_info.initFromStaticConfig(user) cluster_dynamic_config = os.path.realpath(os.path.join(cluster_info.appPath, "bin", "cluster_dynamic_config")) for node in cluster_info.dbNodes: cm_meta_data = \ os.path.realpath(os.path.join(os.path.dirname(node.cmagents[0].datadir), "dcf_data", "metadata")) rm_meta_data_cmd = g_file.SHELL_CMD_DICT["deleteDir"] % (cm_meta_data, cm_meta_data) rm_dynamic_cmd = g_file.SHELL_CMD_DICT["deleteFile"] % (cluster_dynamic_config, cluster_dynamic_config) perform_cmd = "{0} && {1}".format(rm_dynamic_cmd, rm_meta_data_cmd) CmdExecutor.execCommandWithMode(perform_cmd, ssh_tool, host_list=[node.name]) logger.debug("Remove dynamic_config_file and CM metadata directory " "on node [{0}] successfully.".format(node.name)) logger.log("Remove dynamic_config_file and CM metadata directory on all nodes.") @staticmethod def distribute_file_to_node(params): """ Distribute file to dest node with path """ dest_ip, from_path, to_path, timeout = params pscp_cmd = "source %s ; pscp -t %s -H %s %s %s" % ( EnvUtil.getMpprcFile(), timeout, dest_ip, from_path, to_path) status, output = CmdUtil.getstatusoutput_by_fast_popen(pscp_cmd) return status, output, dest_ip @staticmethod def check_is_cm_cluster(logger): """ Check cm_ctl is exist. """ cmd = "source %s; cm_ctl view | grep cmDataPath" % EnvUtil.getMpprcFile() status, output = CmdUtil.retryGetstatusoutput(cmd) if status != 0: logger.debug("Check cm_ctl is failed msg: %s." % output) return False logger.debug("Successfully check cm_ctl is available.") return True @staticmethod def is_disaster_cluster(clusterinfo): """ function: determine cluster status normal or disaster input: NA output: NA """ cmd = "source %s; cm_ctl view | grep cmDataPath | awk -F [:] '{print $2}' | head -n 1" % \ EnvUtil.getMpprcFile() proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = proc.communicate() if proc.returncode != 0: raise Exception(ErrorCode.GAUSS_514['GAUSS_51400'] % cmd + "Error:\n%s" % stderr) cm_agent_conf_file = stdout.strip() + "/cm_agent/cm_agent.conf" if not os.path.isfile(cm_agent_conf_file): host_list = clusterinfo.getClusterNodeNames() cm_agent_conf_temp_file = os.path.join(EnvUtil.getTmpDirFromEnv(), "cm_agent_tmp.conf") for host_ip in host_list: get_file_cmd = g_file.SHELL_CMD_DICT["scpFileFromRemote"] % \ (host_ip, NetUtil.GetHostIpOrName(), cm_agent_conf_file, cm_agent_conf_temp_file) proc = FastPopen(get_file_cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = proc.communicate() if not os.path.isfile(cm_agent_conf_temp_file): continue else: break if os.path.isfile(cm_agent_conf_temp_file): with open(cm_agent_conf_temp_file, "r") as cma_conf_file: content = cma_conf_file.read() ret = re.findall(r'agent_backup_open *= *1|agent_backup_open *= *2', content) g_file.removeFile(cm_agent_conf_temp_file) if ret: return True else: return False else: raise Exception(ErrorCode.GAUSS_502['GAUSS_50201'] % cm_agent_conf_file) with open(cm_agent_conf_file, "r") as cma_conf_file: content = cma_conf_file.read() ret = re.findall(r'agent_backup_open *= *1|agent_backup_open *= *2', content) if ret: return True else: return False @staticmethod def cm_exist_and_is_disaster_cluster(clusterinfo, logger): """ check current cluster cm exist and is disaster cluster. """ cm_exist = DefaultValue.check_is_cm_cluster(logger) if not cm_exist: return False is_disaster = DefaultValue.is_disaster_cluster(clusterinfo) if not is_disaster: return False return True @staticmethod def write_content_on_file(dest_file, content, authority=None): """ Write content on file """ authority = authority if authority else DefaultValue.KEY_FILE_MODE_IN_OS with os.fdopen(os.open(dest_file, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, authority), "w") as fp_write: fp_write.write(str(content)) @staticmethod def get_data_ip_info(instance, logger): """ Obtain data ip from file or cluster instance. """ cluster_conf_record = os.path.join(EnvUtil.getEnv("PGHOST"), "streaming_cabin/cluster_conf_record") if not os.path.isfile(cluster_conf_record): raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % cluster_conf_record) with open(cluster_conf_record, 'r') as read_fp: conf_dict = json.load(read_fp) if not conf_dict or len(conf_dict) != 2: logger.debug("Failed obtain data ip list.") raise Exception(ErrorCode.GAUSS_516["GAUSS_51632"] % "check data ip file") inst_data_ip = "" local_shards_list = conf_dict["localClusterConf"]["shards"] for shard_list in local_shards_list: for shard in shard_list: if shard["ip"] not in instance.listenIps: continue inst_data_ip = shard["dataIp"] logger.debug("File record:%s, \nGot data ip:%s for instanceId:%s." % (conf_dict, inst_data_ip, instance.instanceId)) if not inst_data_ip: raise Exception(ErrorCode.GAUSS_516["GAUSS_51632"] % "obtain local data ip") return inst_data_ip @staticmethod def obtain_hadr_user_encrypt_str(cluster_info, db_user, logger, mode, ignore_res=False): """ Obtain hadr user encrypted string """ sql = "select value from gs_global_config where name='hadr_user_info';" instances = [] for node in cluster_info.dbNodes: if cluster_info.isSingleInstCluster(): for inst in node.datanodes: instances.append(inst) for inst in instances: logger.debug("Obtain hadr user info string on node:%s with port:%s." % (inst.hostname, inst.port)) status, output = ClusterCommand.remoteSQLCommand(sql, db_user, inst.hostname, inst.port, maintenance_mode=mode) if status == 0 and output: logger.debug("Successfully obtain hadr user info string.") return output if ignore_res: return logger.debug("Failed obtain hadr user info string.") raise Exception(ErrorCode.GAUSS_516["GAUSS_51632"] % "obtain hadr user info") @staticmethod def getstatusoutput_hide_pass(joint_cmd): """ Hide password of process """ proc = Popen(["sh", "-"], stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True) stdout, stderr = proc.communicate(joint_cmd) text = stderr or stdout sts = proc.returncode if sts is None: sts = 0 if text and text[-1:] == '\n': text = text[:-1] return sts, text @staticmethod def decrypt_hadr_user_info(params): """ Decrypt hadr user info """ if len(params) != 6: raise Exception(ErrorCode.GAUSS_500["GAUSS_50000"] % "decrypt hadr user info") rand_pwd, hadr_str, cluster_info, db_user, logger, mode = params sql = "select pg_catalog.gs_decrypt_aes128('%s', '%s');" % (hadr_str, rand_pwd) instances = [] for node in cluster_info.dbNodes: if cluster_info.isSingleInstCluster(): for inst in node.datanodes: instances.append(inst) else: for inst in node.coordinators: instances.append(inst) for inst in instances: logger.debug("Decrypt hadr user info on node:%s with port:%s." % (inst.hostname, inst.port)) status, output = ClusterCommand.remoteSQLCommand(sql, db_user, inst.hostname, inst.port, maintenance_mode=mode) if status == 0 and output and "|" in output and len(output.split("|")) == 2: logger.debug("Successfully decrypt hadr user info string.") hadr_user, hadr_pwd = output.strip().split("|")[0], output.strip().split("|")[1] return hadr_user, hadr_pwd logger.debug("Failed decrypt hadr user info string.") raise Exception(ErrorCode.GAUSS_516["GAUSS_51632"] % "decrypt hadr user info") @staticmethod def decrypt_hadr_rand_pwd(logger): """ Decrypt hadr rand pwd """ db_user = pwd.getpwuid(os.getuid()).pw_name gauss_home = ClusterDir.getInstallDir(db_user) bin_path = os.path.join(os.path.realpath(gauss_home), "bin") if not bin_path: logger.debug("Failed obtain bin path.") raise Exception(ErrorCode.GAUSS_518["GAUSS_51802"] % "bin path") cipher_file = os.path.join(EnvUtil.getTmpDirFromEnv(), "binary_upgrade/hadr.key.cipher") rand_file = os.path.join(EnvUtil.getTmpDirFromEnv(), "binary_upgrade/hadr.key.rand") if os.path.isfile(cipher_file) and os.path.isfile(rand_file): bin_path = os.path.join(EnvUtil.getTmpDirFromEnv(), "binary_upgrade") rand_pwd = AesCbcUtil.aes_cbc_decrypt_with_path(bin_path, bin_path, key_name="hadr") if rand_pwd: logger.debug("Successfully decrypt rand pwd.") return rand_pwd @staticmethod def get_proc_title(pwd_para_name): """ Obtain the process name after sensitive information is hidden. """ cmd = "cat /proc/%s/cmdline" % os.getpid() status, output = CmdUtil.retryGetstatusoutput(cmd) if status != 0 or not output: raise Exception(ErrorCode.GAUSS_502["GAUSS_50219"] % "proc title" + " Cmd is:%s." % cmd) title_str_list = [] for title_str in output.split("\0"): if "=" in title_str: title_str_list.extend(title_str.split("=")) else: title_str_list.extend(title_str.split(" ")) if pwd_para_name in title_str_list: w_index = title_str_list.index(pwd_para_name) title_str_list[w_index], title_str_list[w_index + 1] = "", "" title_name = " ".join(title_str_list).strip() return title_name @staticmethod def set_proc_title(name): """ set proc title to new name """ new_name = name.encode('ascii', 'replace') try: libc = ctypes.CDLL('libc.so.6') proc_name = ctypes.c_char_p.in_dll(libc, '__progname_full') with open('/proc/self/cmdline') as fp: old_progname_len = len(fp.readline()) if old_progname_len > len(new_name): # padding blank chars new_name += b' ' * (old_progname_len - len(new_name)) # Environment variables are already copied to Python app zone. # We can get environment variables by `os.environ` module, # so we can ignore the destroying from the following action. libc.strcpy(proc_name, ctypes.c_char_p(new_name)) buff = ctypes.create_string_buffer(len(new_name) + 1) buff.value = new_name libc.prctl(15, ctypes.byref(buff), 0, 0, 0) except Exception as err_msg: raise Exception(ErrorCode.GAUSS_505["GAUSS_50503"] + str(err_msg)) @staticmethod def check_is_streaming_dr_cluster(): """check_is_steaming_cluster_cluster""" stream_file = os.path.realpath(os.path.join(EnvUtil.getEnv("PGHOST"), "streaming_cabin")) if os.path.exists(stream_file): sys.exit(ErrorCode.GAUSS_512["GAUSS_51244"] % "current operate on dr cluster") @staticmethod def get_primary_dn_instance_id(inst_status="Primary", ignore=False): """ function: get Primary/Standby dn instance id for centralized/distribute cluster :param: inst_status Primary/Standby return; instance id """ cmd = r"source %s; cm_ctl query -v | grep -E 'instance_state\ *:\ %s' " \ r"-B 4 | grep -E 'type\ *:\ Datanode' -B 5 | grep instance_id | awk " \ r"'{print $NF}'" % (EnvUtil.getMpprcFile(), inst_status) (status, output) = CmdUtil.retryGetstatusoutput(cmd) if status != 0 or not output: if ignore is True: return [] raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error: \n%s" % output) return output.strip().split('\n') @staticmethod def isgreyUpgradeNodeSpecify(user, step=-1, nodes=None, logger=None): """ step = -1 means we just check if step in all the specified nodes is the same otherwise, we check if all the specified nodes is the given step """ try: if nodes: logger.debug( "check if the nodes %s step is %s " % (nodes, step)) else: logger.debug( "check if all the nodes step is %s" % step) # This cluster info is new cluster info. clusterNodes = [] cluster_info = dbClusterInfo() cluster_info.initFromStaticConfig(user) for dbNode in cluster_info.dbNodes: clusterNodes.append(dbNode.name) nodes = copy.deepcopy(clusterNodes) logger.debug( "IsgreyUpgradeNodeSpecify: all the nodes is %s" % nodes) # upgrade backup path tmpDir = EnvUtil.getTmpDirFromEnv(user) if tmpDir == "": raise Exception(ErrorCode.GAUSS_518["GAUSS_51800"] % "$PGHOST") upgradeBackupPath = "%s/%s" % (tmpDir, "binary_upgrade") stepFile = os.path.join(upgradeBackupPath, "upgrade_step.csv") if not os.path.isfile(stepFile): logger.debug( "No step file, which means not in upgrade occasion or " "node %s step is same" % nodes) return True with open(stepFile, 'r') as csvfile: reader = csv.DictReader(csvfile) for row in reader: if row['node_host'] in nodes: if step == -1: step = int(row['step']) else: if step <= int(row['step']): continue else: logger.debug("The nodes %s step is not all %s" % (nodes, step)) return False logger.debug("The nodes %s step is all %s" % (nodes, step)) return True except Exception as e: # failed to read the upgrade_step.csv in isgreyUpgradeNodeSpecify logger.logExit(str(e)) class ClusterCommand(): ''' Common for cluster command ''' def __init__(self): pass # gs_sshexkey execution takes total steps TOTAL_STEPS_SSHEXKEY = 11 # gs_preinstall -L execution takes total steps TOTAL_STEPS_PREINSTALL_L = 14 # gs_preinstall execution takes total steps TOTAL_STEPS_PREINSTALL = 17 # gs_install execution takes total steps TOTAL_STEPS_INSTALL = 7 # gs_om -t managecn -m add execution takes total steps TOTAL_STEPS_OM_ADD = 20 # gs_om -t managecn -m delete execution takes total steps TOTAL_STEPS_OM_DELETE = 16 # gs_om -t changeip execution takes total steps TOTAL_STEPS_OM_CHANGEIP = 11 # gs_expand -t dilatation execution takes total steps TOTAL_STEPS_EXPAND_DILA = 17 # gs_expand -t redistribute execution takes total steps TOTAL_STEPS_EXPAND_REDIS = 6 # gs_shrink -t entry1_percontraction execution takes total steps TOTAL_STEPS_SHRINK_FIRST = 9 # gs_shrink -t entry2_redistributre execution takes total steps TOTAL_STEPS_SHRINK_SECOND = 8 # gs_shrink -t entry3_postcontraction execution takes total steps TOTAL_STEPS_SHRINK_THIRD = 7 # gs_replace -t warm-standby execution takes total steps TOTAL_STEPS_REPLACE_WARM_STANDBY = 11 # gs_replace -t warm-standby rollback replace execution takes total steps TOTAL_STEPS_REPLACE_WARM_STANDBY_REPLACE = 9 # gs_replace -t warm-standby rollback install execution takes total steps TOTAL_STEPS_REPLACE_WARM_STANDBY_INSTALL = 7 # gs_replace -t warm-standby rollback config execution takes total steps TOTAL_STEPS_REPLACE_WARM_STANDBY_CONFIG = 6 # gs_replace -t install execution takes total steps TOTAL_STEPS_REPLACE_INSTALL = 6 # gs_replace -t config execution takes total steps TOTAL_STEPS_REPLACE_CONFIG = 6 # gs_replace -t start execution takes total steps TOTAL_STEPS_REPLACE_START = 3 # gs_uninstall execution takes total steps TOTAL_STEPS_UNINSTALL = 8 # gs_upgradectl -t auto-upgrade execution takes total steps TOTAL_STEPS_GREY_UPGRADECTL = 12 # gs_upgradectl -t auto-upgrade --inplace execution takes total steps TOTAL_STEPS_INPLACE_UPGRADECTL = 15 # gs_postuninstall execution takes total steps TOTAL_STEPS_POSTUNINSTALL = 3 # warm-standby rollback to flag of begin warm standby WARM_STEP_INIT = "Begin warm standby" # warm-standby rollback to flag of replace IP finished WARM_STEP_REPLACEIPS = "Replace IP finished" # warm-standby rollback to flag of install warm standby nodes finished WARM_STEP_INSTALL = "Install warm standby nodes finished" # warm-standby rollback to flag of configure warm standby nodes finished WARM_STEP_CONFIG = "Configure warm standby nodes finished" # rollback to flag of start cluster INSTALL_STEP_CONFIG = "Config cluster" # rollback to flag of start cluster INSTALL_STEP_START = "Start cluster" @staticmethod def getStartCmd(nodeId=0, timeout=DefaultValue.TIMEOUT_CLUSTER_START, datadir="", azName = ""): """ function : Start all cluster or a node input : String,int,String,String output : String """ user_profile = EnvUtil.getMpprcFile() cmd = "%s %s ; cm_ctl start" % (CmdUtil.SOURCE_CMD, user_profile) # check node id if nodeId > 0: cmd += " -n %d" % nodeId # check data directory if datadir != "": cmd += " -D %s" % datadir # check timeout if timeout > 0: cmd += " -t %d" % timeout # azName if azName != "": cmd += " -z%s" % azName return cmd @staticmethod def getStopCmd(nodeId=0, stopMode="", timeout=0, datadir="", azName = ""): """ function : Stop all cluster or a node iinput : String,int,String,String output : String """ userProfile = EnvUtil.getMpprcFile() cmd = "%s %s ; cm_ctl stop" % (CmdUtil.SOURCE_CMD, userProfile) # check node id if nodeId > 0: cmd += " -n %d" % nodeId # check data directory if datadir != "": cmd += " -D %s" % datadir # check stop mode if stopMode != "": cmd += " -m %s" % stopMode # check timeout if timeout > 0: cmd += " -t %d" % timeout # azName if azName != "": cmd += " -z%s" % azName return cmd @staticmethod def getQueryStatusCmdForDisplay(nodeId=0, outFile="", clusterType="", showDetail=True, showAll=True): """ function : Get the command of querying status of cluster or node input : String output : String """ user_profile = EnvUtil.getMpprcFile() cmd = "%s %s ; cm_ctl query" % (CmdUtil.SOURCE_CMD, user_profile) # check node id if nodeId > 0: cmd += " -v -n %d" % nodeId # check -v if showDetail: if (clusterType == DefaultValue.CLUSTER_TYPE_SINGLE_PRIMARY_MULTI_STANDBY): cmd += " -v -C -i -d -z ALL" else: cmd += " -v -C -i -d" else: if showAll: cmd += " -v" # check out put file if outFile != "": cmd += " > %s" % outFile return cmd @staticmethod def getQueryStatusCmd(hostName="", outFile="", showAll=True): """ function : Get the command of querying status of cluster or node input : String output : String """ userProfile = EnvUtil.getMpprcFile() cmd = "%s %s ; gs_om -t status" % (CmdUtil.SOURCE_CMD, userProfile) # check node id if (hostName != ""): cmd += " -h %s" % hostName else: if (showAll): cmd += " --all" # check out put file if (outFile != ""): cmd += " > %s" % outFile return cmd @staticmethod def execSQLCommand(sql, user, host, port, database="postgres", option="", IsInplaceUpgrade=False): """ function : Execute sql command input : String,String,String,int output : String """ database = database.replace('$', '\$') currentTime = datetime.utcnow().strftime("%Y-%m-%d_%H%M%S%f") pid = os.getpid() # init SQL query file sqlFile = os.path.join( EnvUtil.getTmpDirFromEnv(user), "gaussdb_query.sql_%s_%s_%s" % (str(port), str(currentTime), str(pid))) # init SQL result file queryResultFile = os.path.join( EnvUtil.getTmpDirFromEnv(user), "gaussdb_result.sql_%s_%s_%s" % (str(port), str(currentTime), str(pid))) if os.path.exists(sqlFile) or os.path.exists(queryResultFile): LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile)) # create an empty sql query file try: FileUtil.createFile(sqlFile, True, DefaultValue.KEY_FILE_MODE) except Exception as e: if os.path.exists(sqlFile): os.remove(sqlFile) return 1, str(e) # witer the SQL command into sql query file try: FileUtil.createFileInSafeMode(sqlFile) with open(sqlFile, 'w') as fp: fp.writelines(sql) except Exception as e: LocalRemoteCmd.cleanFile(sqlFile) return 1, str(e) try: # init hostPara userProfile = EnvUtil.getMpprcFile() hostPara = ("-h %s" % host) if host != "" else "" # build shell command # if the user is root, switch the user to execute if (IsInplaceUpgrade): gsqlCmd = SqlCommands.getSQLCommandForInplaceUpgradeBackup( port, database) else: gsqlCmd = SqlCommands.getSQLCommand( port, database) executeCmd = "%s %s -f '%s' --output '%s' -t -A -X %s" % ( gsqlCmd, hostPara, sqlFile, queryResultFile, option) cmd = CmdUtil.getExecuteCmdWithUserProfile(user, userProfile, executeCmd, False) (status, output) = subprocess.getstatusoutput(cmd) if SqlFile.findErrorInSqlFile(sqlFile, output): status = 1 if (status != 0): LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile)) return (status, output) # read the content of query result file. except Exception as e: LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile)) raise Exception(str(e)) try: with open(queryResultFile, 'r') as fp: rowList = fp.readlines() except Exception as e: LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile)) return 1, str(e) # remove local sqlFile LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile)) return (0, "".join(rowList)[:-1]) @staticmethod def remoteSQLCommand(sql, user, host, port, ignoreError=True, database="postgres", useTid=False, IsInplaceUpgrade=False, maintenance_mode=False, user_name="", user_pwd=""): """ function : Execute sql command on remote host input : String,String,String,int output : String,String """ database = database.replace('$', '\$') currentTime = datetime.utcnow().strftime("%Y-%m-%d_%H%M%S%f") pid = os.getpid() # clean old sql file # init SQL query file sqlFile = os.path.join(EnvUtil.getTmpDirFromEnv(user), "gaussdb_remote_query.sql_%s_%s_%s" % ( str(port), str(currentTime), str(pid))) # init SQL result file queryResultFile = os.path.join(EnvUtil.getTmpDirFromEnv(user), "gaussdb_remote_result.sql_%s_%s_%s" % ( str(port), str(currentTime), str(pid))) RE_TIMES = 3 if useTid: threadPid = CDLL('libc.so.6').syscall(186) sqlFile = sqlFile + str(threadPid) queryResultFile = queryResultFile + str(threadPid) if (os.path.exists(sqlFile) or os.path.exists(queryResultFile)): LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile)) # create new sql file if (os.getuid() == 0): cmd = "su - %s -c 'touch %s && chmod %s %s'" % ( user, sqlFile, DefaultValue.KEY_FILE_MODE, sqlFile) else: cmd = "touch %s && chmod %s %s" % (sqlFile, DefaultValue.KEY_FILE_MODE, sqlFile) (status, output) = subprocess.getstatusoutput(cmd) if (status != 0): output = "%s\n%s" % (cmd, output) if (os.path.exists(sqlFile) or os.path.exists(queryResultFile)): LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile)) return (status, output) # witer the SQL command into sql query file try: FileUtil.createFileInSafeMode(sqlFile) with open(sqlFile, 'w') as fp: fp.writelines(sql) except Exception as e: LocalRemoteCmd.cleanFile(sqlFile) return (1, str(e)) # send new sql file to remote node if needed localHost = NetUtil.GetHostIpOrName() if str(localHost) != str(host): cmd = LocalRemoteCmd.getRemoteCopyCmd(sqlFile, sqlFile, host) if os.getuid() == 0 and user != "": cmd = "su - %s \"%s\"" % (user, cmd) (status, output) = subprocess.getstatusoutput(cmd) if status != 0: LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile)) output = "%s\n%s" % (cmd, output) return (status, output) # execute sql file mpprcFile = EnvUtil.getMpprcFile() if IsInplaceUpgrade: gsql_cmd = SqlCommands.getSQLCommandForInplaceUpgradeBackup( port, database) else: gsql_cmd = SqlCommands.getSQLCommand(port, database, user_name=user_name, user_pwd=user_pwd) if maintenance_mode: gsql_cmd += " -m " if str(localHost) != str(host): sshCmd = CmdUtil.getSshCmd(host) if os.getuid() == 0 and user != "": cmd = " %s 'su - %s -c \"" % (sshCmd, user) if mpprcFile != "" and mpprcFile is not None: cmd += "source %s;" % mpprcFile cmd += "%s -f %s --output %s -t -A -X \"'" % (gsql_cmd, sqlFile, queryResultFile) if ignoreError: cmd += " 2>/dev/null" else: cmd = "" if mpprcFile != "" and mpprcFile is not None: cmd += "source %s;" % mpprcFile cmd += "%s -f %s --output %s -t -A -X " % (gsql_cmd, sqlFile, queryResultFile) if user_pwd: cmd = "echo \"%s\" | %s" % (cmd, sshCmd) else: cmd = "%s '%s'" % (sshCmd, cmd) if ignoreError: cmd += " 2>/dev/null" for i in range(RE_TIMES): proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output1 = stdout + stderr status1 = proc.returncode if SqlFile.findErrorInSqlFile(sqlFile, output1): if SqlFile.findTupleErrorInSqlFile(output1): time.sleep(1) # find tuple error --> retry else: # find error not tuple error status1 = 1 break else: # not find error break # if failed to execute gsql, then clean the sql query file on # current node and other node if (status1 != 0): LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile)) LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile), host) return (status1, output1) else: if (os.getuid() == 0 and user != ""): cmd = "su - %s -c \"" % user if (mpprcFile != "" and mpprcFile is not None): cmd += "source %s;" % mpprcFile cmd += "%s -f %s --output %s -t -A -X \"" % (gsql_cmd, sqlFile, queryResultFile) if (ignoreError): cmd += " 2>/dev/null" else: cmd = "" if (mpprcFile != "" and mpprcFile is not None): cmd += "source %s;" % mpprcFile cmd += "%s -f %s --output %s -t -A -X " % (gsql_cmd, sqlFile, queryResultFile) if (ignoreError): cmd += " 2>/dev/null" for i in range(RE_TIMES): proc = FastPopen(cmd, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid, close_fds=True) stdout, stderr = proc.communicate() output1 = stdout + stderr status1 = proc.returncode if SqlFile.findErrorInSqlFile(sqlFile, output1): if SqlFile.findTupleErrorInSqlFile(output1): time.sleep(1) # find tuple error --> retry else: # find error not tuple error status1 = 1 break else: # not find error break # if failed to execute gsql, then clean the sql query file # on current node and other node if (status1 != 0): LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile)) return (status1, output1) if (str(localHost) != str(host)): remoteCmd = LocalRemoteCmd.getRemoteCopyCmd( queryResultFile, EnvUtil.getTmpDirFromEnv(user) + "/", str(localHost)) cmd = "%s \"%s\"" % (sshCmd, remoteCmd) (status, output) = subprocess.getstatusoutput(cmd) if (status != 0): output = "%s\n%s" % (cmd, output) LocalRemoteCmd.cleanFile(sqlFile) LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile), host) return (status, output) # read the content of query result file. try: with open(queryResultFile, 'r') as fp: rowList = fp.readlines() except Exception as e: LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile)) if (str(localHost) != str(host)): LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile), host) return (1, str(e)) # remove local sqlFile LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile)) # remove remote sqlFile if (str(localHost) != str(host)): LocalRemoteCmd.cleanFile("%s,%s" % (queryResultFile, sqlFile), host) return (0, "".join(rowList)[:-1]) @staticmethod def countTotalSteps(script, act="", model=""): """ function: get script takes steps in total input: script: command name act: the type of command model: mode setting """ try: totalSteps = 0 if (script == "gs_preinstall"): if model: totalSteps = ClusterCommand.TOTAL_STEPS_PREINSTALL_L else: totalSteps = ClusterCommand.TOTAL_STEPS_PREINSTALL elif (script == "gs_install"): if (model == ClusterCommand.INSTALL_STEP_CONFIG): totalSteps = ClusterCommand.TOTAL_STEPS_INSTALL - 1 elif (model == ClusterCommand.INSTALL_STEP_START): totalSteps = ClusterCommand.TOTAL_STEPS_INSTALL - 2 else: totalSteps = ClusterCommand.TOTAL_STEPS_INSTALL elif (script == "gs_om"): if (act == "managecn"): if (model == "add"): totalSteps = ClusterCommand.TOTAL_STEPS_OM_ADD if (model == "delete"): totalSteps = ClusterCommand.TOTAL_STEPS_OM_DELETE if (act == "changeip"): totalSteps = ClusterCommand.TOTAL_STEPS_OM_CHANGEIP elif (script == "gs_expand"): if (act == "dilatation"): totalSteps = ClusterCommand.TOTAL_STEPS_EXPAND_DILA if (act == "redistribute"): totalSteps = ClusterCommand.TOTAL_STEPS_EXPAND_REDIS elif (script == "gs_shrink"): if (act == "entry1"): totalSteps = ClusterCommand.TOTAL_STEPS_SHRINK_FIRST if (act == "entry2"): totalSteps = ClusterCommand.TOTAL_STEPS_SHRINK_SECOND if (act == "entry3"): totalSteps = ClusterCommand.TOTAL_STEPS_SHRINK_THIRD elif (script == "gs_sshexkey"): if model: totalSteps = ClusterCommand.TOTAL_STEPS_SSHEXKEY - 2 else: totalSteps = ClusterCommand.TOTAL_STEPS_SSHEXKEY elif (script == "gs_replace"): if (act == "warm-standby"): if (model == ClusterCommand.WARM_STEP_INIT): totalSteps = ClusterCommand. \ TOTAL_STEPS_REPLACE_WARM_STANDBY if (model == ClusterCommand.WARM_STEP_REPLACEIPS): totalSteps = ClusterCommand. \ TOTAL_STEPS_REPLACE_WARM_STANDBY_REPLACE if (model == ClusterCommand.WARM_STEP_INSTALL): totalSteps = ClusterCommand. \ TOTAL_STEPS_REPLACE_WARM_STANDBY_INSTALL if (model == ClusterCommand.WARM_STEP_CONFIG): totalSteps = ClusterCommand. \ TOTAL_STEPS_REPLACE_WARM_STANDBY_CONFIG if (act == "install"): totalSteps = ClusterCommand.TOTAL_STEPS_REPLACE_INSTALL if (act == "config"): totalSteps = ClusterCommand.TOTAL_STEPS_REPLACE_CONFIG if (act == "start"): totalSteps = ClusterCommand.TOTAL_STEPS_REPLACE_START elif (script == "gs_upgradectl"): if (act == "small-binary-upgrade" or act == "large-binary-upgrade"): totalSteps = ClusterCommand.TOTAL_STEPS_GREY_UPGRADECTL if (act == "inplace-binary-upgrade"): totalSteps = ClusterCommand.TOTAL_STEPS_INPLACE_UPGRADECTL elif (script == "gs_uninstall"): totalSteps = ClusterCommand.TOTAL_STEPS_UNINSTALL elif (script == "gs_postuninstall"): totalSteps = ClusterCommand.TOTAL_STEPS_POSTUNINSTALL return totalSteps except Exception as e: raise Exception(str(e)) @staticmethod def aes_cbc_encrypt_with_multi(passwd, dest_path, logger): # # check if the password contains illegal characters PasswordUtil.checkPasswordVaild(passwd) # encrypt tool path encrypt_path = os.path.realpath("%s/../clib" % os.path.dirname(os.path.realpath(__file__))) # encrypt ca path encrypt_ca_path = dest_path cmd = "export LD_LIBRARY_PATH={encrypt_path}" cmd += " && if [ -e {encrypt_ca_path} ];then rm -rf {encrypt_ca_path}/;fi" cmd += " && mkdir -p {encrypt_ca_path}/cipher && mkdir -p {encrypt_ca_path}/rand" cmd += " && cd {encrypt_path}" cmd += " && ./encrypt {passwd} {encrypt_ca_path}/cipher {encrypt_ca_path}/rand" cmd = cmd.format(encrypt_path=encrypt_path, passwd=passwd, encrypt_ca_path=encrypt_ca_path) status, output = CmdUtil.getstatusoutput_by_fast_popen(cmd) if status != 0 and "encrypt success" not in output: raise Exception(ErrorCode.GAUSS_511["GAUSS_51103"] % "encrypt ..." + "Error is:%s" % SensitiveMask.mask_pwd(output)) logger.log("Generate cluster user password files successfully.\n") @staticmethod def executeSQLOnRemoteHost(hostName, port, sql, outputfile, snapid="defaultNone", database="postgres"): """ function: execute SQL on remote host input :hostName, port, sql, outputfile, database output: NA """ from gspylib.threads.SshTool import SshTool from gspylib.common.OMCommand import OMCommand hosts = [] hosts.append(hostName) gs_sshTool = SshTool(hosts) currentTime = datetime.utcnow().strftime("%Y-%m-%d_%H%M%S%f") pid = os.getpid() sqlfile = "%s_%s_%s.sql" % (hostName, pid, currentTime) tmpDir = EnvUtil.getTmpDirFromEnv() + "/" sqlfilepath = os.path.join(tmpDir, sqlfile) FileUtil.createFileInSafeMode(sqlfilepath) try: with open(sqlfilepath, "w") as fp: fp.write(sql) fp.flush() LocalRemoteCmd.scpFile(hostName, sqlfilepath, tmpDir) cmd = "%s -p %s -S %s -f %s -s %s -d %s" % ( OMCommand.getLocalScript("Local_Execute_Sql"), port, sqlfilepath, outputfile, snapid, database) gs_sshTool.executeCommand(cmd) cmd = "%s %s" % (CmdUtil.getRemoveCmd("directory"), sqlfilepath) (status, output) = subprocess.getstatusoutput(cmd) except Exception as e: cmd = "%s %s" % (CmdUtil.getRemoveCmd("directory"), sqlfilepath) (status, output) = subprocess.getstatusoutput(cmd) raise Exception(str(e)) @staticmethod def get_pass_phrase(): """ :return: """ encrypt_dir = DefaultValue.get_ssh_protect_path() if os.path.isdir(encrypt_dir): output = AesCbcUtil.aes_cbc_decrypt_with_multi(*AesCbcUtil.format_path(encrypt_dir)) if len(str(output).strip().split()) < 1: raise Exception( "Decrypt key failed from protect ssh directory.") data = str(output).strip().split()[-1] return data else: raise Exception("Get passphrase failed.") class ClusterInstanceConfig(): """ Set Instance Config """ def __init__(self): pass @staticmethod def setConfigItem(typename, datadir, configFile, parmeterDict): """ function: Modify a parameter input : typename, datadir, configFile, parmeterDict output: NA """ # check mpprc file path mpprcFile = EnvUtil.getMpprcFile() # comment out any existing entries for this setting if (typename == DefaultValue.INSTANCE_ROLE_CMSERVER or typename == DefaultValue.INSTANCE_ROLE_CMAGENT): # gs_guc only support for DB instance # if the type is cm_server or cm_agent, we will use sed to # instead of it for entry in parmeterDict.items(): key = entry[0] value = entry[1] # delete the old parameter information cmd = "sed -i 's/^.*\(%s.*=.*\)/#\\1/g' %s" % (key, configFile) (status, output) = subprocess.getstatusoutput(cmd) if (status != 0): raise Exception(ErrorCode.GAUSS_500["GAUSS_50008"] + " Command:%s. Error:\n%s" % (cmd, output)) # append new config to file cmd = 'echo " " >> %s' % (configFile) (status, output) = subprocess.getstatusoutput(cmd) if (status != 0): raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error: \n%s" % output) cmd = 'echo "%s = %s" >> %s' % (key, value, configFile) (status, output) = subprocess.getstatusoutput(cmd) if (status != 0): raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error: \n%s" % output) else: # build GUC parameter string gucstr = "" for entry in parmeterDict.items(): gucstr += " -c \"%s=%s\"" % (entry[0], entry[1]) # check the GUC parameter string if (gucstr == ""): return cmd = "source %s; gs_guc set -D %s %s" % \ (mpprcFile, datadir, gucstr) DefaultValue.retry_gs_guc(cmd) @staticmethod def setReplConninfo(dbInst, peerInsts, clusterInfo): """ function: Modify replconninfo for datanode input : dbInst output: NA """ masterInst = None standbyInst = None dummyStandbyInst = None nodename = "" # init masterInst, standbyInst and dummyStandbyInst for pi in iter(peerInsts): if (pi.instanceType == DefaultValue.MASTER_INSTANCE): masterInst = pi elif (pi.instanceType == DefaultValue.STANDBY_INSTANCE): standbyInst = pi elif (pi.instanceType == DefaultValue.DUMMY_STANDBY_INSTANCE): dummyStandbyInst = pi if (dbInst.instanceType == DefaultValue.MASTER_INSTANCE): masterInst = dbInst nodename = "dn_%d_%d" % (masterInst.instanceId, standbyInst.instanceId) elif (dbInst.instanceType == DefaultValue.STANDBY_INSTANCE): standbyInst = dbInst nodename = "dn_%d_%d" % (masterInst.instanceId, standbyInst.instanceId) elif (dbInst.instanceType == DefaultValue.DUMMY_STANDBY_INSTANCE): dummyStandbyInst = dbInst nodename = "dn_%d_%d" % (masterInst.instanceId, dummyStandbyInst.instanceId) if (len(masterInst.haIps) == 0 or len(standbyInst.haIps) == 0): raise Exception(ErrorCode.GAUSS_516["GAUSS_51621"] + " Data directory: %s." % dbInst.datadir) if (dummyStandbyInst is not None and len(dummyStandbyInst.haIps) == 0): raise Exception(ErrorCode.GAUSS_516["GAUSS_51621"] + " Data directory: %s." % dbInst.datadir) connInfo1 = "" connInfo2 = "" channelCount = len(masterInst.haIps) # get master instance number masterDbNode = clusterInfo.getDbNodeByName(masterInst.hostname) if masterDbNode is None: raise Exception(ErrorCode.GAUSS_502["GAUSS_50204"] % ("database node configuration on host [%s]" % masterInst.hostname)) masterDataNum = masterDbNode.getDnNum(masterInst.instanceType) # get standby instance number standbyDbNode = clusterInfo.getDbNodeByName(standbyInst.hostname) if standbyDbNode is None: raise Exception(ErrorCode.GAUSS_502["GAUSS_50204"] % ("database node configuration on host [%s]" % standbyInst.hostname)) standbyDataNum = standbyDbNode.getDnNum(standbyInst.instanceType) # get dummy instance number if dummyStandbyInst is not None: dummyDbNode = clusterInfo.getDbNodeByName( dummyStandbyInst.hostname) if dummyDbNode is None: raise Exception(ErrorCode.GAUSS_502["GAUSS_50204"] % ("database node configuration on host [%s]" % dummyStandbyInst.hostname)) dummyDataNum = dummyDbNode.getDnNum(dummyStandbyInst.instanceType) for i in range(channelCount): if (dbInst.instanceType == DefaultValue.MASTER_INSTANCE): if (i > 0): connInfo1 += "," connInfo1 += "localhost=%s localport=%d localservice=%s " \ "remotehost=%s remoteport=%d remoteservice=%s" % \ (dbInst.haIps[i], dbInst.haPort, (dbInst.port + masterDataNum * 4), standbyInst.haIps[i], standbyInst.haPort, (standbyInst.port + standbyDataNum * 4)) if dummyStandbyInst is not None: if (i > 0): connInfo2 += "," connInfo2 += "localhost=%s localport=%d localservice=%s " \ "remotehost=%s remoteport=%d " \ "remoteservice=%s" % \ (dbInst.haIps[i], dbInst.haPort, (dbInst.port + masterDataNum * 4), dummyStandbyInst.haIps[i], dummyStandbyInst.haPort, (dummyStandbyInst.port + dummyDataNum * 4)) elif dbInst.instanceType == DefaultValue.STANDBY_INSTANCE: if i > 0: connInfo1 += "," connInfo1 += "localhost=%s localport=%d " \ "localservice=%s remotehost=%s remoteport=%d " \ "remoteservice=%s" % \ (dbInst.haIps[i], dbInst.haPort, (dbInst.port + standbyDataNum * 4), masterInst.haIps[i], masterInst.haPort, (masterInst.port + masterDataNum * 4)) if (dummyStandbyInst is not None): if i > 0: connInfo2 += "," connInfo2 += "localhost=%s localport=%d localservice=%s " \ "remotehost=%s remoteport=%d " \ "remoteservice=%s" % \ (dbInst.haIps[i], dbInst.haPort, (dbInst.port + standbyDataNum * 4), dummyStandbyInst.haIps[i], dummyStandbyInst.haPort, (dummyStandbyInst.port + dummyDataNum * 4)) elif (dbInst.instanceType == DefaultValue.DUMMY_STANDBY_INSTANCE): if i > 0: connInfo1 += "," connInfo1 += "localhost=%s localport=%d localservice=%s " \ "remotehost=%s remoteport=%d remoteservice=%s" % \ (dbInst.haIps[i], dbInst.haPort, (dbInst.port + dummyDataNum * 4), masterInst.haIps[i], masterInst.haPort, (masterInst.port + masterDataNum * 4)) if i > 0: connInfo2 += "," connInfo2 += "localhost=%s localport=%d " \ "localservice=%s remotehost=%s remoteport=%d " \ "remoteservice=%s" % \ (dbInst.haIps[i], dbInst.haPort, (dbInst.port + dummyDataNum * 4), standbyInst.haIps[i], standbyInst.haPort, (standbyInst.port + standbyDataNum * 4)) return connInfo1, connInfo2, dummyStandbyInst, nodename @staticmethod def getInstanceInfoForSinglePrimaryMultiStandbyCluster(dbInst, peerInsts): """ function: get the instance name, master instance and standby instance list input : dbInst output: NA """ masterInst = None standbyInstIdLst = [] instancename = "" # init masterInst, standbyInst for pi in iter(peerInsts): if pi.instanceType == DefaultValue.MASTER_INSTANCE: masterInst = pi elif pi.instanceType == DefaultValue.STANDBY_INSTANCE or \ pi.instanceType == DefaultValue.CASCADE_STANDBY: standbyInstIdLst.append(pi.instanceId) if dbInst.instanceType == DefaultValue.MASTER_INSTANCE: masterInst = dbInst instancename = "dn_%d" % masterInst.instanceId standbyInstIdLst.sort() for si in iter(standbyInstIdLst): instancename += "_%d" % si elif dbInst.instanceType == DefaultValue.STANDBY_INSTANCE or \ dbInst.instanceType == DefaultValue.CASCADE_STANDBY: instancename = "dn_%d" % masterInst.instanceId standbyInstIdLst.append(dbInst.instanceId) standbyInstIdLst.sort() for si in iter(standbyInstIdLst): instancename += "_%d" % si return (instancename, masterInst, standbyInstIdLst) @staticmethod def setReplConninfoForSinglePrimaryMultiStandbyCluster(dbInst, peerInsts, clusterInfo): """ function: Modify replconninfo for datanode input : dbInst output: NA """ masterInst = None standbyInstIdLst = [] nodename = "" connInfo1 = [] (nodename, masterInst, standbyInstIdLst) = ClusterInstanceConfig. \ getInstanceInfoForSinglePrimaryMultiStandbyCluster(dbInst, peerInsts) if len(masterInst.haIps) == 0: raise Exception(ErrorCode.GAUSS_516["GAUSS_51621"] + " Data directory: %s." % dbInst.datadir) if len(standbyInstIdLst) == 0: return connInfo1, nodename dbNode = clusterInfo.getDbNodeByName(dbInst.hostname) if dbNode is None: raise Exception(ErrorCode.GAUSS_502["GAUSS_50204"] % ("database node configuration on host [%s]" % dbInst.hostname)) channelCount = len(masterInst.haIps) if dbInst.instanceType == DefaultValue.MASTER_INSTANCE: for pj in iter(peerInsts): peerDbNode = clusterInfo.getDbNodeByName(pj.hostname) if peerDbNode is None: raise Exception(ErrorCode.GAUSS_502["GAUSS_50204"] % ("database node configuration on host [%s]" % pj.hostname)) chanalInfo = "" for i in range(channelCount): if i > 0: chanalInfo += "," chanalInfo += "localhost=%s localport=%d " \ "localheartbeatport=%d localservice=%s " \ "remotehost=%s remoteport=%d " \ "remoteheartbeatport=%d remoteservice=%s" % \ (dbInst.haIps[i], dbInst.haPort, dbInst.port + 5, (dbInst.port + 4), pj.haIps[i], pj.haPort, pj.port + 5, pj.port + 4) if pj.instanceType == DefaultValue.CASCADE_STANDBY: chanalInfo += " iscascade=true" connInfo1.append(chanalInfo) else: for pj in iter(peerInsts): peerDbNode = clusterInfo.getDbNodeByName(pj.hostname) if peerDbNode is None: raise Exception(ErrorCode.GAUSS_502["GAUSS_50204"] % ("database node configuration on host [%s]" % pj.hostname)) chanalInfo = "" for i in range(channelCount): if i > 0: chanalInfo += "," chanalInfo += "localhost=%s localport=%d " \ "localheartbeatport=%d localservice=%s " \ "remotehost=%s remoteport=%d " \ "remoteheartbeatport=%d remoteservice=%s" % \ (dbInst.haIps[i], dbInst.haPort, dbInst.port + 5, (dbInst.port + 4), pj.haIps[i], pj.haPort, pj.port + 5, (pj.port + 4)) if pj.instanceType == DefaultValue.CASCADE_STANDBY: chanalInfo += " iscascade=true" connInfo1.append(chanalInfo) return connInfo1, nodename @staticmethod def get_data_from_dcc(cluster_info, logger, user, paralist): """ function: get value from dcc :param cluster_info: cluster info :param logger: logger obj :param user: cluster user :param paralist: paralist :return: key-value map dict """ gausshome = ClusterDir.getInstallDir(user) cm_ctl = os.path.realpath(os.path.join(gausshome, "bin/cm_ctl")) if not os.path.isfile(cm_ctl): raise Exception(ErrorCode.GAUSS_502["GAUSS-50201"] % "file cm_ctl") cms_count = 0 etcd_count = 0 for dbnode in cluster_info.dbNodes: for _ in dbnode.cmservers: cms_count += 1 for _ in dbnode.etcds: etcd_count += 1 if cms_count == 0 or etcd_count > 1: raise Exception(ErrorCode.GAUSS_500["GAUSS-50011"] % paralist) para_value_map = {} for para_key in paralist: cmd = "source %s; %s ddb --get '%s'" % (EnvUtil.getMpprcFile(), cm_ctl, para_key) logger.debug("Get dcc value cmd:%s." % cmd) (status, output) = subprocess.getstatusoutput(cmd) if status != 0: raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd, "Error:%s" % output) logger.debug("Get dcc value:%s." % output) res = output.strip("\n").split("\n") if len(res) != 2: raise Exception(ErrorCode.GAUSS_500["GAUSS-50019"] % res) if res[-1].find("Key not found") > -1: para_value_map[para_key] = "" continue para_value_map[para_key] = res[-1].split(":")[-1].strip() logger.debug("Get all values from dcc component res:%s." % para_value_map) return para_value_map @staticmethod def set_data_on_dcc(cluster_info, logger, user, paradict): """ function: set data on dcc :param cluster_info: cluster info :param logger: logger obj :param user: cluster user :param paradict: paradict :return: NA """ gausshome = ClusterDir.getInstallDir(user) cm_ctl = os.path.realpath(os.path.join(gausshome, "bin/cm_ctl")) if not os.path.isfile(cm_ctl): raise Exception(ErrorCode.GAUSS_502["GAUSS-50201"] % "file cm_ctl") cms_count = 0 etcd_count = 0 for dbnode in cluster_info.dbNodes: for _ in dbnode.cmservers: cms_count += 1 for _ in dbnode.etcds: etcd_count += 1 if cms_count == 0 or etcd_count > 1: raise Exception(ErrorCode.GAUSS_500["GAUSS-50011"] % paradict) for para_key in list(paradict.keys()): cmd = "source %s; %s ddb --put '%s' '%s'" % \ (EnvUtil.getMpprcFile(), cm_ctl, para_key, paradict[para_key]) logger.debug("Set dcc value cmd:%s." % cmd) (status, output) = subprocess.getstatusoutput(cmd) if status != 0: raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd, "Error:%s" % output) logger.debug("Set dcc data:%s." % output) res = output.strip("\n").split("\n") if len(res) != 2: raise Exception(ErrorCode.GAUSS_500["GAUSS-50019"] % res) logger.debug("Successfully set the dcc data information.") class TempfileManagement(): """ create and remove temp file or directory """ def __init__(self): """ function: init function input: NA output: NA """ pass @staticmethod def removeTempFile(filename, Fuzzy=False): """ function: remove temp files in PGHOST input: fileName string Specified file name or keywords Fuzzy bool Whether to remove files with the same prefix, default is False output: NA """ if Fuzzy: keywords = filename + "*" FileUtil.removeFile(keywords, "shell") else: FileUtil.removeFile(filename) class CmPackageException(BaseException): def __init__(self): BaseException.__init__(self) self.error_info = "Cm package exception. " \ "Please check the installation package " \ "or delete the CM configuration from the XML file." def __str__(self): return self.error_info