Files
openGauss-OM/script/gs_expansion

752 lines
32 KiB
Python

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
#############################################################################
# Copyright (c) 2020 Huawei Technologies Co.,Ltd.
#
# openGauss is licensed under Mulan PSL v2.
# You can use this software according to the terms
# and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
# ----------------------------------------------------------------------------
# Description : gs_expansion is a utility to expansion standby node databases
#############################################################################
import os
import sys
import subprocess
import socket
import pwd
package_path = os.path.dirname(os.path.realpath(__file__))
ld_path = package_path + "/gspylib/clib"
if 'LD_LIBRARY_PATH' not in os.environ:
os.environ['LD_LIBRARY_PATH'] = ld_path
os.execve(os.path.realpath(__file__), sys.argv, os.environ)
if not os.environ.get('LD_LIBRARY_PATH').startswith(ld_path):
os.environ['LD_LIBRARY_PATH'] = \
ld_path + ":" + os.environ['LD_LIBRARY_PATH']
os.execve(os.path.realpath(__file__), sys.argv, os.environ)
sys.path.append(sys.path[0])
from gspylib.common.copy_python_lib import copy_lib
copy_lib()
from gspylib.common.DbClusterInfo import dbClusterInfo, \
checkPathVaild, dbNodeInfo, instanceInfo
from gspylib.common.GaussLog import GaussLog
from gspylib.common.Common import DefaultValue
from gspylib.common.ErrorCode import ErrorCode
from gspylib.common.ParallelBaseOM import ParallelBaseOM
from gspylib.common.ParameterParsecheck import Parameter
from gspylib.threads.SshTool import SshTool
from impl.expansion.ExpansionImpl import ExpansionImpl
from impl.expansion.expansion_impl_with_cm import ExpansionImplWithCm
from impl.expansion.expansion_impl_with_cm_local import ExpansionImplWithCmLocal
from domain_utils.cluster_file.cluster_config_file import ClusterConfigFile
from domain_utils.cluster_file.cluster_log import ClusterLog
from base_utils.os.env_util import EnvUtil
from base_utils.os.user_util import UserUtil
from base_utils.os.cmd_util import CmdUtil
from base_utils.os.file_util import FileUtil
from base_utils.os.net_util import NetUtil
from base_utils.os.hosts_util import HostsUtil
ENV_LIST = ["MPPDB_ENV_SEPARATE_PATH", "GPHOME", "PATH",
"LD_LIBRARY_PATH", "PYTHONPATH", "GAUSS_WARNING_TYPE",
"GAUSSHOME", "PATH", "LD_LIBRARY_PATH",
"S3_CLIENT_CRT_FILE", "GAUSS_VERSION", "PGHOST",
"GS_CLUSTER_NAME", "GAUSSLOG", "GAUSS_ENV", "umask"]
# The following attributes are skipped because the information
# in the static configuration file of the OpenGauss is incorrect.
ABORT_CHECK_PROPERTY = ["xmlFile", "id", "gtmNum", "instanceId",
"masterBasePorts", "standbyBasePorts",
"instanceType", "_dbClusterInfo__newInstanceId",
"_dbClusterInfo__newMirrorId", "version",
"installTime", "localNodeId", "nodeCount",
"_dbClusterInfo__newGroupId", "cmsNum", "datadir",
"enable_dcf", "dcf_config", "dcf_data_path", "cmscount", "casecadeRole",
"enable_dss", "dss_config", "dss_home", "cm_vote_disk", "cm_share_disk",
"dss_pri_disks", "dss_shared_disks", "dss_vg_info", "dss_vgname",
"dss_ssl_enable", "ss_rdma_work_config", "ss_interconnect_type", "syncNumFirst"]
IGNORE_CHECK_KEY = ["cascadeRole"]
# uwal num
BASE_ID_GTM = 4001
class Expansion(ParallelBaseOM):
"""
"""
def __init__(self):
"""
"""
ParallelBaseOM.__init__(self)
# new added standby node backip list
self.newHostList = []
self.clusterInfoDict = {}
self.backIpNameMap = {}
self.newHostCasRoleMap = {}
self.hostAzNameMap = {}
self.packagepath = os.path.realpath(
os.path.join(os.path.realpath(__file__), "../../"))
self.standbyLocalMode = False
self.time_out = None
self.envFile = EnvUtil.getEnv("MPPDB_ENV_SEPARATE_PATH")
self.new_hostname_ip_map = {}
self.new_hostname_list = []
def usage(self):
"""
gs_expansion is a utility to expansion standby node for a cluster, streaming cluster does not yet support.
Usage:
gs_expansion -? | --help
gs_expansion -V | --version
gs_expansion -U USER -G GROUP -X XMLFILE -h nodeList [-L]
General options:
-U Cluster user.
-G Group of the cluster user.
-X Path of the XML configuration file.
-h New standby node backip list.
Separate multiple nodes with commas (,).
such as '-h 192.168.0.1,192.168.0.2'
-L The standby database installed with
local mode.
--time-out=SECS Maximum waiting time when send the
packages to new standby nodes.
-?, --help Show help information for this
utility, and exit the command line mode.
-V, --version Show version information.
"""
print(self.usage.__doc__)
def check_current_user(self):
user_info = UserUtil.getUserInfo()
if user_info['uid'] == 0:
self.current_user_root = True
else:
self.current_user_root = False
self.user = user_info['name']
self.group = user_info['g_name']
def parseCommandLine(self):
"""
parse parameter from command line
"""
ParaObj = Parameter()
ParaDict = ParaObj.ParameterCommandLine("expansion")
# parameter -h or -?
if (ParaDict.__contains__("helpFlag")):
self.usage()
sys.exit(0)
# check no root parameter
self.check_no_root_parameter(ParaDict)
# Resolves command line arguments
# parameter -U
if (ParaDict.__contains__("user")):
self.user = ParaDict.get("user")
DefaultValue.checkPathVaild(self.user)
# parameter -G
if (ParaDict.__contains__("group")):
self.group = ParaDict.get("group")
# parameter -X
if (ParaDict.__contains__("confFile")):
self.xmlFile = ParaDict.get("confFile")
# parameter -L
if (ParaDict.__contains__("localMode")):
self.localMode = ParaDict.get("localMode")
self.standbyLocalMode = ParaDict.get("localMode")
# parameter -l
if (ParaDict.__contains__("logFile")):
self.logFile = ParaDict.get("logFile")
#parameter -h
if (ParaDict.__contains__("nodename")):
self.newHostList = ParaDict.get("nodename")
# parameter --time-out
if (ParaDict.__contains__("time_out")):
self.time_out = ParaDict.get("time_out")
def check_no_root_parameter(self, para_dict):
"""
function: Check no root user paramter
input: NA
output: NA
"""
if not self.current_user_root:
if (para_dict.__contains__("user") and (para_dict.get("user") != self.user)):
GaussLog.exitWithError(ErrorCode.GAUSS_503["GAUSS_50324"])
if (para_dict.__contains__("group") and (para_dict.get("group") != self.group)):
GaussLog.exitWithError(ErrorCode.GAUSS_503["GAUSS_50324"])
def checkParameters(self):
"""
function: Check parameter from command line
input: NA
output: NA
"""
# check user | group | xmlfile | node
if self.current_user_root:
if len(self.user) == 0:
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35701"] % "-U")
if len(self.group) == 0:
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35701"] % "-G")
if len(self.newHostList) == 0:
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35701"] % "-h")
# convert to compressed IP address
clusterInfo = dbClusterInfo()
clusterInfo.initFromStaticConfig(self.user)
self.newHostList = clusterInfo.compress_ips(self.newHostList)
# check if upgrade action is exist
if DefaultValue.isUnderUpgrade(self.user):
GaussLog.exitWithError(ErrorCode.GAUSS_529["GAUSS_52936"])
if (self.time_out is None):
self.time_out = DefaultValue.TIMEOUT_CLUSTER_START
else:
# The timeout parameter must be a pure number
if (not str(self.time_out).isdigit()):
GaussLog.exitWithError(
ErrorCode.GAUSS_500["GAUSS_50003"] %
("-time-out", "a nonnegative integer"))
self.time_out = int(self.time_out)
# The timeout parameter must be greater than 0
# The timeout parameter must be less than the integer maximum
if (self.time_out <= 0 or self.time_out
>= 2147483647):
GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50004"]
% "-time-out")
# check if the new hosts is in xml file
if self.xmlFile and self.newHostList:
cluster_info = dbClusterInfo()
cluster_info.initFromXml(self.xmlFile)
self.newHostList = cluster_info.compress_ips(self.newHostList)
node_ips = cluster_info.getClusterSshIps()[0]
for host in self.newHostList:
if host not in node_ips:
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35702"] % host)
def _get_node_dn_port(self, node_name):
"""
Get data node port
"""
if not self.clusterInfo.clusterType == DefaultValue.CLUSTER_TYPE_SINGLE_INST:
self.logger.log("The cluster type is not single-inst.")
raise Exception("Cluster type is not single-inst.")
node = self.clusterInfo.getDbNodeByName(node_name)
if node.datanodes:
return node.datanodes[0].port
return None
def _getClusterInfoDict(self):
self.check_xml_config()
clusterInfo = ExpansionClusterInfo()
self.clusterInfo = clusterInfo
hostNameIpDict = clusterInfo.initFromXml(self.xmlFile)
clusterDict = clusterInfo.get_cluster_directory_dict()
# get corepath and toolpath from xml file
corePath = clusterInfo.readClustercorePath(self.xmlFile)
toolPath = clusterInfo.getToolPath(self.xmlFile)
# parse xml file and cache node info
clusterInfoDict = {}
clusterInfoDict["appPath"] = clusterDict["appPath"][0]
clusterInfoDict["logPath"] = clusterDict["logPath"][0]
clusterInfoDict["corePath"] = corePath
clusterInfoDict["toolPath"] = toolPath
for nodeName in self.nodeNameList:
hostInfo = hostNameIpDict[nodeName]
ipList = hostInfo[0]
backIp = ipList[0]
sshIp = ipList[1]
port = self._get_node_dn_port(nodeName)
if clusterDict[nodeName]["dn"]["data_dir"]:
data_node = clusterDict[nodeName]["dn"]["data_dir"][0]
else:
data_node = ""
dbNode = clusterInfo.getDbNodeByName(nodeName)
clusterInfoDict[nodeName] = {
"backIp": backIp,
"sshIp": sshIp,
"port": port,
"localport": int(port) + 1,
"localservice": int(port) + 4,
"heartBeatPort": int(port) + 5,
"dataNode": data_node,
"instanceType": -1,
"azPriority": dbNode.azPriority
}
if dbNode and len(dbNode.datanodes) > 0:
clusterInfoDict[nodeName]["instanceId"] = dbNode.datanodes[0].instanceId
# fill uwal config into clusterInfo
if clusterInfo.enable_uwal == 'on':
clusterInfoDict[nodeName]["remotenodeid"] = int(dbNode.id) - 1
clusterInfoDict[nodeName]["remoteuwalhost"] = ipList[-1]
clusterInfoDict[nodeName]["remoteuwalport"] = port + BASE_ID_GTM
clusterInfoDict[nodeName]["enable_uwal"] = clusterInfo.enable_uwal
clusterInfoDict[nodeName]["uwal_disk_size"] = clusterInfo.uwal_disk_size
clusterInfoDict[nodeName]["uwal_devices_path"] = clusterInfo.uwal_devices_path
clusterInfoDict[nodeName]["uwal_log_path"] = clusterInfo.uwal_log_path
clusterInfoDict[nodeName]["uwal_rpc_compression_switch"] = clusterInfo.uwal_rpc_compression_switch
clusterInfoDict[nodeName]["uwal_rpc_flowcontrol_switch"] = clusterInfo.uwal_rpc_flowcontrol_switch
clusterInfoDict[nodeName]["uwal_rpc_flowcontrol_value"] = clusterInfo.uwal_rpc_flowcontrol_value
clusterInfoDict[nodeName]["uwal_async_append_switch"] = clusterInfo.uwal_async_append_switch
nodeIdList = clusterInfo.getClusterNodeIds()
for id in nodeIdList:
insType = clusterInfo.getdataNodeInstanceType(id)
hostName = clusterInfo.getHostNameByNodeId(id)
clusterInfoDict[hostName]["instanceType"] = insType
clusterInfoDict[hostName]["localnodeid"] = id - 1
self.clusterInfoDict = clusterInfoDict
def initLogs(self):
"""
init log file
"""
# if no log file
if (self.logFile == ""):
self.logFile = ClusterLog.getOMLogPath(
DefaultValue.EXPANSION_LOG_FILE, self.user, "",
self.xmlFile)
# if not absolute path
if (not os.path.isabs(self.logFile)):
GaussLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50213"] % "log")
self.initLogger("gs_expansion")
# change the owner of gs_expansion.log to the db user
if os.path.isfile(self.logger.logFile):
(status, output) = subprocess.getstatusoutput("ls %s -al | cut -d' ' -f3" % self.logger.logFile)
if output != self.user:
subprocess.getstatusoutput("chown {}:{} {}".format(self.user, self.group, self.logger.logFile))
self.logger.ignoreErr = True
# init cluster info from xml or static file
if self.xmlFile:
self.initClusterInfo()
else:
self.initClusterInfoFromStaticFile(self.user)
# init node ip list
self.node_ip_list = self.clusterInfo.getClusterSshIps()[0]
for ip in self.newHostList:
if ip not in self.node_ip_list:
self.node_ip_list.append(ip)
def global_init(self):
"""
init node name list
"""
self.initClusterInfo()
self.nodeNameList = self.clusterInfo.getClusterNodeNames()
# write new hosts to host file
self.write_new_hosts_to_hosts_file()
def write_new_hosts_to_hosts_file(self):
# 1.get gphme
gp_home = os.environ.get("GPHOME")
hosts_file1 = os.path.normpath(os.path.join(gp_home, "hosts"))
contents = HostsUtil.read_hosts_file(hosts_file1)
contents.update(self.new_hostname_ip_map)
HostsUtil.write_hosts_file(hosts_file1, contents)
# 2.get gauss_om dir
user_home = os.path.expanduser(f"~{self.user}")
gauss_om = os.path.normpath(os.path.join(user_home, "gauss_om"))
hosts_file2 = os.path.join(gauss_om, "hosts")
HostsUtil.write_hosts_file(hosts_file2, contents)
FileUtil.changeMode(DefaultValue.KEY_FILE_MODE, hosts_file1)
FileUtil.changeOwner(self.user, hosts_file1)
FileUtil.changeMode(DefaultValue.KEY_FILE_MODE, hosts_file2)
FileUtil.changeOwner(self.user, hosts_file2)
def check_env_variable(self):
"""
check whether env file is sourced
"""
self.logger.debug("Checking environment variable.")
if not self.envFile:
self.envFile = "/home/%s/.bashrc" % self.user
cmd = "source %s" % self.envFile
(status, output) = subprocess.getstatusoutput(cmd)
if status != 0:
raise Expansion("not found envfile.")
if not EnvUtil.getEnv("GPHOME"):
GaussLog.exitWithError(ErrorCode.GAUSS_518["GAUSS_51802"] % (
"\"GPHOME\", please import environment variable"))
if not EnvUtil.getEnv("GAUSSHOME"):
GaussLog.exitWithError(ErrorCode.GAUSS_518["GAUSS_51802"] % (
"\"GAUSSHOME\", please import environment variable"))
if not EnvUtil.getEnv("PGHOST"):
GaussLog.exitWithError(ErrorCode.GAUSS_518["GAUSS_51802"] % (
"\"PGHOST\", please import environment variable"))
self.logger.debug("Successfully checked environment variable.")
def generate_xml(self):
if self.xmlFile:
return
self.logger.log("Start generate xml")
# get current path
currentPath = os.path.dirname(os.path.realpath(__file__))
gs_om = os.path.join(currentPath, "gs_om")
# get new hostname and hostip
hostip_str = ",".join(self.newHostList)
hostname_str = ",".join(self.new_hostname_list)
# execute gs_om -t generate_xml
user_path = pwd.getpwnam(self.user).pw_dir
if not self.envFile:
self.envFile = os.path.normpath(os.path.join(user_path, ".bashrc"))
cmd = "source %s; %s -t generate_xml --add-hostname=%s --add-hostip=%s" % (self.envFile, gs_om, hostname_str, hostip_str)
if os.getuid() == 0:
cmd = "su - %s -c '%s'" % (self.user, cmd)
status, output = subprocess.getstatusoutput(cmd)
if status != 0:
GaussLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50231"] % self.xmlFile)
xml_tmp_file = os.path.normpath(os.path.join(user_path, "tmp_generate_xml"))
if not os.path.exists(xml_tmp_file):
GaussLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50201"] % xml_tmp_file)
self.xmlFile = FileUtil.readFile(xml_tmp_file)[0].strip()
# delete xml tmp file
FileUtil.removeFile(xml_tmp_file)
self.logger.log("Successfully generate xml, the xml file is %s" % self.xmlFile)
def get_new_hostname_and_hostip(self):
gpHome = EnvUtil.getEnv("GPHOME")
pssh_path = "python3 %s/script/gspylib/pssh/bin/pssh" % gpHome
for ip in self.newHostList:
cmd = "source ~/.bashrc && source %s; %s -s -H %s 'hostname'" \
%(self.envFile, pssh_path, ip)
(status, output) = subprocess.getstatusoutput(cmd)
if status != 0:
raise Exception("Failed to pssh -s -H %s 'hostname'" % ip)
else:
self.new_hostname_list.append(str(output).strip())
self.new_hostname_ip_map[ip] = str(output).strip()
def getExpansionInfo(self):
self._getClusterInfoDict()
self._getBackIpNameMap()
self._getHostAzNameMap()
self._getNewHostCasRoleMap()
def checkXmlIncludeNewHost(self):
"""
check parameter node must in xml config file
"""
ips_type = []
backIpList = self.clusterInfo.getClusterBackIps()
for nodeIp in self.newHostList:
if nodeIp not in backIpList:
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35702"] %
nodeIp)
ips_type.append(NetUtil.get_ip_version(nodeIp))
if len(set(ips_type)) != 1:
GaussLog.exitWithError(ErrorCode.GAUSS_506["GAUSS_50624"] +
"The types of these ip addresses are %s" % ips_type + ". Please "
"check it.")
def _getBackIpNameMap(self):
backIpList = self.clusterInfo.getClusterBackIps()
for backip in backIpList:
self.backIpNameMap[backip] = \
self.clusterInfo.getNodeNameByBackIp(backip)
def checkExecutingHost(self):
"""
check whether current host is primary host
"""
currentHost = socket.gethostname()
primaryHost = ""
for nodeName in self.nodeNameList:
if self.clusterInfoDict[nodeName]["instanceType"] \
== 0:
primaryHost = nodeName
break
if currentHost != primaryHost:
GaussLog.exitWithError(ErrorCode.GAUSS_501["GAUSS_50110"] %
(currentHost + ", which is not primary"))
def checkTrust(self):
"""
check trust between primary/current host and every host in hostList
"""
gpHome = EnvUtil.getEnv("GPHOME")
psshPath = "python3 %s/script/gspylib/pssh/bin/pssh" % gpHome
create_ssh = False
for host in self.node_ip_list:
if os.getuid() == 0:
# check individual user's trust
check_user_trust_cmd = "su - %s -c '%s -s -H %s pwd'" % (self.user, psshPath, host)
(status, output) = subprocess.getstatusoutput(check_user_trust_cmd)
if status != 0:
create_ssh = True
# check current user's trust
check_user_trust_cmd = "%s -s -H %s 'pwd'" % (psshPath, host)
(status, output) = subprocess.getstatusoutput(check_user_trust_cmd)
if status != 0:
create_ssh = True
# output ssh exception info if ssh connect failed
if create_ssh:
self.logger.log("The cluster need create ssh trust")
self.create_trust(self.node_ip_list)
else:
self.logger.log("The cluster no need create ssh trust")
def create_trust(self, node_ips):
if os.getuid() == 0:
self.create_trust_for_user("root", node_ips)
self.create_trust_for_user(self.user, node_ips)
def create_trust_for_user(self, user, all_ips):
self.logger.log("Please enter password for %s" % user)
self.sshTool = SshTool(all_ips, self.logFile, DefaultValue.TIMEOUT_PSSH_PREINSTALL)
self.sshTool.createTrust(user, all_ips)
self.logger.debug("Successfully created SSH trust for the %s" % user)
def check_xml_env_consistent(self):
"""
check whether info in XML is consistent with environment variable
"""
clusterInfoDict = self.clusterInfoDict
toolPath = EnvUtil.getEnv("GPHOME")
appPath = EnvUtil.getEnv("GAUSSHOME")
if toolPath != clusterInfoDict["toolPath"]:
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35711"] % "toolPath")
if appPath != clusterInfoDict["appPath"]:
GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35711"] % "appPath")
def _getHostAzNameMap(self):
"""
get azName of all hosts
"""
for dbnode in self.clusterInfo.dbNodes:
self.hostAzNameMap[dbnode.backIps[0]] = dbnode.azName
def _getNewHostCasRoleMap(self):
"""
get cascadeRole of newHosts
"""
for dbnode in self.clusterInfo.dbNodes:
if dbnode.backIps[0] in self.newHostList:
self.newHostCasRoleMap[dbnode.backIps[0]] = dbnode.cascadeRole
def check_cm_component(self):
"""
Init cluster information
"""
db_cluster_info = dbClusterInfo()
db_cluster_info.initFromStaticConfig(self.user)
if DefaultValue.get_cm_server_num_from_static(db_cluster_info) > 0:
return True
return False
def check_xml_config(self):
"""
Check XML configuration
"""
expand_cluster_info = ExpansionClusterInfo()
expand_cluster_info.initFromXml(self.xmlFile)
xml_cluster_info = dbClusterInfo()
xml_cluster_info.initFromXml(self.xmlFile)
static_cluster_info = dbClusterInfo()
static_cluster_info.initFromStaticConfig(self.user)
expand_cluster_info.compare_cluster_info(static_cluster_info,
xml_cluster_info)
def expand_run(self, expansion):
"""
This is expansion frame start
"""
if self.check_cm_component() and self.standbyLocalMode:
expand_impl = ExpansionImplWithCmLocal(expansion)
self.logger.log("Start expansion with cluster manager component on standby node.")
elif self.check_cm_component():
expand_impl = ExpansionImplWithCm(expansion)
self.logger.log("Start expansion with cluster manager component.")
else:
expand_impl = ExpansionImpl(expansion)
self.logger.log("Start expansion without cluster manager component.")
expand_impl.run()
class ExpansionClusterInfo(dbClusterInfo):
def __init__(self):
dbClusterInfo.__init__(self)
self.collect_compare_result = list()
def _remove_normal_msg(self, key):
"""
Remove normal message in alarm_message
"""
if key in self.collect_compare_result:
self.collect_compare_result.remove(key)
def _add_alarm_msg(self, key):
"""
Remove normal message in alarm_message
"""
self.collect_compare_result.append(key)
def getToolPath(self, xmlFile):
"""
function : Read tool path from default xml file
input : String
output : String
"""
ClusterConfigFile.setDefaultXmlFile(xmlFile)
# read gaussdb tool path from xml file
(retStatus, retValue) = ClusterConfigFile.readOneClusterConfigItem(
ClusterConfigFile.initParserXMLFile(xmlFile), "gaussdbToolPath", "cluster")
if retStatus != 0:
raise Exception(ErrorCode.GAUSS_512["GAUSS_51200"]
% "gaussdbToolPath" + " Error: \n%s" % retValue)
toolPath = os.path.normpath(retValue)
checkPathVaild(toolPath)
return toolPath
def find_right_node(self, a_node, b_list):
"""
Find node in b_list
"""
for node in b_list:
if node.name == a_node.name:
return node
raise Exception("Node {0} not config in XML.".format(a_node.name))
def find_right_instance(self, a_inst, b_list):
"""
Find instance in b_list
"""
for inst in b_list:
if inst.hostname == a_inst.hostname:
return inst
raise Exception("Instance {0} not config in XML.".format(inst.instanceId))
def compare_list(self, a_list, b_list):
"""
Compare list object
"""
for a_index in range(len(a_list)):
if isinstance(a_list[a_index], dbNodeInfo):
self._add_alarm_msg("node: {0}".format(a_list[a_index].name))
b_list_node = self.find_right_node(a_list[a_index], b_list)
self.compare_dict(a_list[a_index].__dict__, b_list_node.__dict__)
self._remove_normal_msg("node: {0}".format(a_list[a_index].name))
elif isinstance(a_list[a_index], instanceInfo):
self._add_alarm_msg("instance: {0}".format(str(a_list[a_index].instanceId)))
b_list_inst = self.find_right_instance(a_list[a_index], b_list)
self.compare_dict(a_list[a_index].__dict__, b_list_inst.__dict__)
self._remove_normal_msg("instance: {0}".format(str(a_list[a_index].instanceId)))
elif isinstance(a_list[a_index], dict):
self._add_alarm_msg(a_list[a_index])
self.compare_dict(a_list[a_index], b_list[a_index])
self._remove_normal_msg(a_list[a_index])
elif isinstance(a_list[a_index], list):
self._add_alarm_msg(a_list[a_index])
self.compare_list(a_list[a_index], b_list[a_index])
self._remove_normal_msg(a_list[a_index])
elif isinstance(a_list[a_index], str):
self._add_alarm_msg(a_list[a_index])
self.compare_string(a_list[a_index], b_list[a_index])
self._remove_normal_msg(a_list[a_index])
elif isinstance(a_list[a_index], int):
self._add_alarm_msg(a_list[a_index])
self.compare_int(a_list[a_index], b_list[a_index])
self._remove_normal_msg(a_list[a_index])
def compare_string(self, a_string, b_string):
"""
Compare list object
"""
if a_string != b_string:
raise Exception((ErrorCode.GAUSS_357["GAUSS_35711"] %
self.collect_compare_result[-1]) +
"XML configure string item failed: {0} . "
"Static config {1}. "
"XML config {2}".format(self.collect_compare_result,
a_string, b_string))
def compare_int(self, a_integer, b_integer):
"""
Compare list object
"""
if a_integer != b_integer:
raise Exception((ErrorCode.GAUSS_357["GAUSS_35711"] %
self.collect_compare_result[-1]) +
"XML configure integer item failed. : {0} . "
"Static config {1}. "
"XML config {2}".format(self.collect_compare_result,
a_integer, b_integer))
def compare_dict(self, a_dict, b_dict):
"""
Compare dict object
"""
for a_key in a_dict.keys():
if a_key in ABORT_CHECK_PROPERTY:
self._remove_normal_msg(a_key)
continue
if type(a_dict.get(a_key)) is not type(b_dict.get(a_key)):
raise Exception("The value type of the XML configuration item [{0}] "
"is inconsistent with that "
"in the static configuration.".format(a_key))
self._add_alarm_msg(a_key)
if isinstance(a_dict.get(a_key), dict):
self.compare_dict(a_dict.get(a_key), b_dict.get(a_key))
self._remove_normal_msg(a_key)
elif isinstance(a_dict.get(a_key), list):
self.compare_list(a_dict.get(a_key), b_dict.get(a_key))
self._remove_normal_msg(a_key)
elif isinstance(a_dict.get(a_key), str):
pass
elif isinstance(a_dict.get(a_key), int):
pass
else:
raise Exception("Not support type. key is {0} , "
"static value is {1}, XML value is {2}, "
"type is {3}".format(a_key, a_dict.get(a_key),
b_dict.get(a_key), type(a_dict.get(a_key))))
def compare_cluster_info(self, static_cluster_info, xml_cluster_info):
"""
Compare cluster_info
"""
if len(static_cluster_info.dbNodes) >= len(xml_cluster_info.dbNodes):
raise Exception("XML configuration failed, "
"node count in expantion XML must be more than static file.")
self.compare_dict(static_cluster_info.__dict__, xml_cluster_info.__dict__)
if __name__ == "__main__":
"""
"""
expansion = Expansion()
expansion.check_current_user()
expansion.parseCommandLine()
expansion.checkParameters()
expansion.initLogs()
expansion.check_env_variable()
expansion.checkTrust()
expansion.get_new_hostname_and_hostip()
expansion.generate_xml()
expansion.global_init()
expansion.getExpansionInfo()
expansion.check_xml_env_consistent()
expansion.checkXmlIncludeNewHost()
expansion.checkExecutingHost()
expansion.expand_run(expansion)