diff --git a/tool/cm_tool/Common.py b/tool/cm_tool/Common.py index 7f6377a..a4aa83f 100644 --- a/tool/cm_tool/Common.py +++ b/tool/cm_tool/Common.py @@ -18,6 +18,7 @@ # Description : Common.py includes some public function ############################################################################# +import os import subprocess from CMLog import CMLog from ErrorCode import ErrorCode @@ -40,3 +41,38 @@ def executeCmdOnHost(host, cmd, isLocal = False): cmd = 'ssh -o ConnectTimeout=5 %s \"%s\"' % (host, cmd) status, output = subprocess.getstatusoutput(cmd) return status, output + +def checkXMLFile(xmlFile): + """ + function: check XML file + 1.check whether XML file exists + 2.check whether XML file is file + 3.permission + input : NA + output: NA + """ + if xmlFile.startswith('~/'): + homePath = os.path.expanduser('~') + xmlFile = homePath + xmlFile[1:] + if not os.path.exists(xmlFile): + CMLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50201"] % "xmlFile") + if not os.path.isfile(xmlFile): + CMLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50210"] % "xmlFile") + if not os.access(xmlFile, os.R_OK): + CMLog.exitWithError(ErrorCode.GAUSS_501["GAUSS_50100"] % (xmlFile, "current user")) + +def checkHostsTrust(hosts, localhost = ""): + """ + check trust between current host and the given hosts + """ + hostsWithoutTrust = [] + for host in hosts: + if host == localhost: + continue + checkTrustCmd = "ssh -o ConnectTimeout=3 -o ConnectionAttempts=5 -o PasswordAuthentication=no " \ + "-o StrictHostKeyChecking=no %s 'pwd > /dev/null'" % host + status, output = subprocess.getstatusoutput(checkTrustCmd) + if status != 0: + hostsWithoutTrust.append(host) + if hostsWithoutTrust != []: + CMLog.exitWithError(ErrorCode.GAUSS_511["GAUSS_51100"] % ','.join(hostsWithoutTrust)) diff --git a/tool/cm_tool/cm_install b/tool/cm_tool/cm_install index af540a7..a2a117f 100644 --- a/tool/cm_tool/cm_install +++ b/tool/cm_tool/cm_install @@ -19,6 +19,7 @@ # Description : cm_install is a utility to deploy CM tool to openGauss database cluster. ############################################################################# +import cmd import getopt import os import sys @@ -45,7 +46,7 @@ class Install: self.toolPath = "" self.tmpPath = "" self.cmDirs = [] - self.hostNames = [] + self.hostnames = [] self.localhostName = "" self.cmpkg = "" @@ -59,28 +60,6 @@ class Install: self.toolPath = getEnvParam(self.envFile, "GPHOME") self.tmpPath = getEnvParam(self.envFile, "PGHOST") - def checkXMLFile(self): - """ - function: check XML file - 1.check -X parameter - 2.check XML file exists - 3.check XML file an absolute path - 4.permission - input : NA - output: NA - """ - if self.xmlFile.startswith('~/'): - homePath = os.path.expanduser('~') - self.xmlFile = homePath + self.xmlFile[1:] - if not os.path.isfile(self.xmlFile): - CMLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50210"] % "xmlFile") - if not os.path.exists(self.xmlFile): - CMLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50201"] % "xmlFile") - if not os.path.isabs(self.xmlFile): - CMLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50213"] % "xmlFile") - if not os.access(self.xmlFile, os.R_OK): - CMLog.exitWithError(ErrorCode.GAUSS_501["GAUSS_50100"] % (self.xmlFile, "current user")) - def checkExeUser(self): if os.getuid() == 0: CMLog.exitWithError(ErrorCode.GAUSS_501["GAUSS_50105"]) @@ -125,13 +104,23 @@ General options: def checkParam(self): if self.xmlFile == "": - CMLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % 'X or xml' + ".") + CMLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % 'X' + ".") + checkXMLFile(self.xmlFile) if self.cmpkg == "": - CMLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % 'p or cmpkg' + ".") + CMLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % '-cmpkg' + ".") + if not os.path.exists(self.cmpkg): + CMLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50201"] % self.cmpkg) if self.envFile == "": - self.envFile = "~/.bashrc" + self.envFile = os.path.join(os.environ['HOME'], ".bashrc") + if not os.path.exists(self.envFile): + CMLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50201"] % ("envFile " + self.envFile)) + if not os.path.isfile(self.envFile): + CMLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50210"] % ("envFile " + self.envFile)) + self.envFile = getEnvParam(self.envFile, "MPPDB_ENV_SEPARATE_PATH") + if self.envFile == "" or not os.path.exists(self.envFile) or not os.path.isfile(self.envFile): + CMLog.exitWithError(ErrorCode.GAUSS_518["GAUSS_51802"] % 'MPPDB_ENV_SEPARATE_PATH' + ".") def checkOm(self): """ @@ -180,6 +169,8 @@ General options: def getInfoListOfAllNodes(self): """ get hostname and cmDir list of all nodes + check other CM infos in xml + TODO: check the consistence of xml and installed cluster. """ self.localhostName = getLocalhostName() @@ -189,28 +180,38 @@ General options: raise Exception(ErrorCode.GAUSS_512["GAUSS_51200"] % elementName) deviceArray = rootNode.findall('DEVICELIST')[0] deviceNodes = deviceArray.findall('DEVICE') + cmDict = {"cmsNum": "", "cmServerPortBase": "", "cmServerPortStandby": "", + "cmServerlevel": "", "cmServerListenIp1": "", "cmServerRelation": ""} for dev in deviceNodes: paramList = dev.findall('PARAM') for param in paramList: - if param.attrib['name'] == 'name': - self.hostNames.append(param.attrib['value']) - if param.attrib['name'] == 'cmDir': - self.cmDirs.append(param.attrib['value']) - - def _checkTrust(self, host): - """ - check trust between current host and the given host - """ - checkTrustCmd = "source %s; pssh -s -H %s 'pwd'" % (self.envFile, host) - status, output = subprocess.getstatusoutput(checkTrustCmd) - return status + paraName = param.attrib['name'] + paraValue = param.attrib['value'] + if paraName == 'name': + self.hostnames.append(paraValue) + elif paraName == 'cmDir': + self.cmDirs.append(paraValue) + elif paraName in cmDict.keys(): + cmDict[paraName] = paraValue + # check params in xml + for item in cmDict: + if item == 'cmServerPortStandby': + continue + if cmDict[item] == "": + CMLog.exitWithError(ErrorCode.GAUSS_512["GAUSS_51200"] % item) + if cmDict['cmsNum'] != '1': + CMLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50024"] % 'cmsNum') + if cmDict['cmServerlevel'] != '1': + CMLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50024"] % 'cmServerlevel') + if not cmDict['cmServerPortBase'].isdigit(): + CMLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50024"] % 'cmServerPortBase') + if cmDict['cmServerPortStandby'] != "" and not cmDict['cmServerPortStandby'].isdigit(): + CMLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50024"] % 'cmServerPortStandby') + if len(self.hostnames) != len(self.cmDirs): + CMLog.exitWithError("\"cmDir\" of all nodes must be provided.") def checkHostTrust(self): - for host in self.hostNames: - if host == self.localhostName: - continue - if self._checkTrust(host) != 0: - CMLog.exitWithError(ErrorCode.GAUSS_511["GAUSS_51100"] % host) + checkHostsTrust(self.hostnames, self.localhostName) def initLogger(self): logPath = os.path.join(self.gaussLog, "cm", "cm_tool") @@ -233,7 +234,6 @@ General options: self.checkParam() self.checkOm() self.checkCM() - self.checkXMLFile() self.getEnvParams() self.initLogger() self.getLocalhostName() diff --git a/tool/cm_tool/cm_uninstall b/tool/cm_tool/cm_uninstall index b175d89..a1f007a 100644 --- a/tool/cm_tool/cm_uninstall +++ b/tool/cm_tool/cm_uninstall @@ -26,7 +26,7 @@ import subprocess from CMLog import CMLog from ErrorCode import ErrorCode from InstallImpl import InstallImpl -from Common import executeCmdOnHost, getEnvParam, getLocalhostName +from Common import * class UnIntall: def __init__(self) -> None: @@ -40,7 +40,7 @@ class UnIntall: def usage(self): """ -cm_uninstall is a utility to deploy CM tool to openGauss database cluster. +cm_uninstall is a utility to uninstall CM tool to openGauss database cluster. Usage: cm_uninstall -? | --help @@ -82,11 +82,25 @@ General options: def checkParam(self): if self.xmlFile == "": - CMLog.exitWithError( - ErrorCode.GAUSS_500["GAUSS_50001"] % 'X' + ".") + CMLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % 'X' + ".") + checkXMLFile(self.xmlFile) if self.envFile == "": - self.envFile = "~/.bashrc" + self.envFile = os.path.join(os.environ['HOME'], ".bashrc") + if not os.path.exists(self.envFile): + CMLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50201"] % ("envFile " + self.envFile)) + if not os.path.isfile(self.envFile): + CMLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50210"] % ("envFile " + self.envFile)) + self.envFile = getEnvParam(self.envFile, "MPPDB_ENV_SEPARATE_PATH") + if self.envFile == "" or not os.path.exists(self.envFile) or not os.path.isfile(self.envFile): + CMLog.exitWithError(ErrorCode.GAUSS_518["GAUSS_51802"] % 'MPPDB_ENV_SEPARATE_PATH' + ".") + + def checkXMLContainCMInfo(self): + cmd = "grep -E 'cmDir|cmsNum|cmServerPortBase|cmServerPortStandby|cmServerlevel|" \ + "cmServerListenIp1|cmServerRelation' " + self.xmlFile + status, output = subprocess.getstatusoutput(cmd) + if status == 0: + CMLog.exitWithError("%s should not contain CM infos.\nDetail:\n%s" % (self.xmlFile, output)) def getHostnames(self): """ @@ -134,7 +148,10 @@ General options: crontab {cronContentTmpFile} """.format(cronContentTmpFile=cronContentTmpFile) for host in self.hostnames: - status, output = executeCmdOnHost(host, cmd) + isLocal = False + if host == self.localhostName: + isLocal = True + status, output = executeCmdOnHost(host, cmd, isLocal) if status != 0: errorDetail = "\nCommand: %s\nStatus: %s\nOutput: %s" % (cmd, status, output) self.logger.logExit(("Failed to cancle monitor crontab on host %s." % host) + errorDetail) @@ -190,15 +207,16 @@ General options: if not self.bDeleteData: return self.logger.log("Deleting CM data path.") + self.logger.closeLog() for host, path in zip(self.hostnames, self.cmDataPaths): isLocal = False if host == self.localhostName: isLocal = True - cmd = "source %s; rm -rf %s" % (self.envFile, path) + cmd = "source %s; rm -rf %s $GAUSSLOG/cm" % (self.envFile, path) status, output = executeCmdOnHost(host, cmd, isLocal) if status != 0: errorDetail = "\nCommand: %s\nStatus: %s\nOutput: %s" % (cmd, status, output) - self.logger.exitWithError(("Failed to delete CM data path on host %s." % host) + errorDetail) + CMLog.exitWithError(("Failed to delete CM data path on host %s." % host) + errorDetail) def deleteBinary(self): """ @@ -211,11 +229,12 @@ General options: isLocal = False if host == self.localhostName: isLocal = True - cmd = "source %s; cd $GAUSSHOME/bin; rm -f om_monitor cm_agent cm_server cm_ctl; cd -" % self.envFile + cmd = "source %s; cd $GAUSSHOME/bin; rm -f om_monitor* cm_agent* cm_server* " \ + "cm_ctl* *manual*start*; cd -" % self.envFile status, output = executeCmdOnHost(host, cmd, isLocal) if status != 0: errorDetail = "\nCommand: %s\nStatus: %s\nOutput: %s" % (cmd, status, output) - self.logger.exitWithError(("Failed to delete CM binaries on host %s." % host) + errorDetail) + self.logger.logExit(("Failed to delete CM binaries on host %s." % host) + errorDetail) def initLogger(self): gaussLog = getEnvParam(self.envFile, "GAUSSLOG") @@ -228,22 +247,29 @@ General options: if os.getuid() == 0: CMLog.exitWithError(ErrorCode.GAUSS_501["GAUSS_50105"]) + def checkHostTrust(self): + checkHostsTrust(self.hostnames, self.localhostName) + def run(self): self.checkExeUser() self.parseCommandLine() self.checkParam() + self.checkXMLContainCMInfo() self.initLogger() - self.logger.log("Start to uninstall CM.") self.getHostnames() + self.checkHostTrust() + self.logger.log("Start to uninstall CM.") self.getCMDataPaths() self.cancleMonitorCrontab() self.stopCMProcess() self.refreshStaticAndDynamicFile() - self.deleteData() self.deleteBinary() - self.logger.log("Uninstall CM tool success.") - + self.deleteData() + if self.bDeleteData: + self.logger.printMessage("Uninstall CM tool success.") + else: + self.logger.logExit("Uninstall CM tool success.") if __name__ == "__main__": unInstall = UnIntall() - unInstall.run() \ No newline at end of file + unInstall.run()