cm安装解耦
This commit is contained in:
parent
fc46835e5d
commit
14bc8a3c91
@ -150,7 +150,8 @@ function pkg() {
|
||||
fi
|
||||
|
||||
cd ${OUT_PATH}
|
||||
tar -czf "${bin_tar}" bin lib share
|
||||
cp ${PROJECT_ROOT_PATH}/tool . -R
|
||||
tar -czf "${bin_tar}" bin lib share tool
|
||||
if [ -d symbols ]; then
|
||||
tar -czf "${sym_tar}" symbols
|
||||
fi
|
||||
|
398
tool/cm_tool/CMLog.py
Normal file
398
tool/cm_tool/CMLog.py
Normal file
@ -0,0 +1,398 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
#############################################################################
|
||||
# Portions Copyright (c) 2022 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 : CMLog.py is utility to handle the log
|
||||
#############################################################################
|
||||
import os
|
||||
import sys
|
||||
import datetime
|
||||
import subprocess
|
||||
import _thread as thread
|
||||
import re
|
||||
import logging.handlers as _handlers
|
||||
import time
|
||||
|
||||
sys.path.append(sys.path[0] + "/../../")
|
||||
|
||||
from ErrorCode import ErrorCode
|
||||
|
||||
# import typing for comment.
|
||||
try:
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
except ImportError:
|
||||
Dict = dict
|
||||
List = list
|
||||
|
||||
# max log file size
|
||||
# 16M
|
||||
MAXLOGFILESIZE = 16 * 1024 * 1024
|
||||
|
||||
LOG_DEBUG = 1
|
||||
LOG_INFO = 2
|
||||
LOG_WARNING = 2.1
|
||||
LOG_ERROR = 3
|
||||
LOG_FATAL = 4
|
||||
|
||||
|
||||
class CMLog:
|
||||
"""
|
||||
Class to handle log file
|
||||
"""
|
||||
|
||||
def __init__(self, logPath, module, prefix, suffix = ".log", expectLevel=LOG_DEBUG, traceId=None):
|
||||
"""
|
||||
function: Constructor
|
||||
input : NA
|
||||
output: NA
|
||||
"""
|
||||
self.logFile = ""
|
||||
self.expectLevel = expectLevel
|
||||
self.moduleName = module
|
||||
self.fp = None
|
||||
self.size = 0
|
||||
self.suffix = suffix
|
||||
self.prefix = prefix
|
||||
self.logPath = logPath
|
||||
self.pid = os.getpid()
|
||||
self.step = 0
|
||||
self.lock = thread.allocate_lock()
|
||||
self.tmpFile = None
|
||||
self.ignoreErr = False
|
||||
self.traceId = traceId
|
||||
|
||||
try:
|
||||
if not os.path.isdir(logPath):
|
||||
print(ErrorCode.GAUSS_502["GAUSS_50211"] % logPath)
|
||||
sys.exit(1)
|
||||
# check log path
|
||||
if not os.path.exists(logPath):
|
||||
try:
|
||||
os.makedirs(logPath, 0o700)
|
||||
except Exception as e:
|
||||
raise Exception(ErrorCode.GAUSS_502["GAUSS_50208"] %
|
||||
logPath + " Error:\n%s" % str(e))
|
||||
# create new log file
|
||||
self.__openLogFile()
|
||||
except Exception as ex:
|
||||
print(str(ex))
|
||||
sys.exit(1)
|
||||
|
||||
def __checkLink(self):
|
||||
"""
|
||||
function: check log file is link
|
||||
input : NA
|
||||
output: list of
|
||||
"""
|
||||
if os.path.islink(self.logFile):
|
||||
raise Exception(ErrorCode.GAUSS_502["GAUSS_50206"] % self.logFile)
|
||||
|
||||
def __checkLogFileExist(self):
|
||||
"""
|
||||
check whether log file exists, if exist, get log file name
|
||||
log file name format:
|
||||
prefix-YYYY-mm-DD_HHMMSSsuffix = cm_install-YYYY-mm-DD_HHMMSS.log
|
||||
"""
|
||||
logFileList = "%s/logFileList_%s.dat" % (self.logPath, self.pid)
|
||||
cmd = "ls %s | grep '^%s-.*%s$' > %s" % (
|
||||
self.logPath, self.prefix, self.suffix, logFileList)
|
||||
(status, output) = subprocess.getstatusoutput(cmd)
|
||||
if status != 0:
|
||||
if os.path.exists(logFileList):
|
||||
os.remove(logFileList)
|
||||
return False
|
||||
with open(logFileList, "r") as fp:
|
||||
filenameList = []
|
||||
while True:
|
||||
# get real file name
|
||||
filename = (fp.readline()).strip()
|
||||
if not filename:
|
||||
break
|
||||
existedResList = filename.split(".")
|
||||
if len(existedResList) > 2:
|
||||
continue
|
||||
(existedPrefix, existedSuffix) = \
|
||||
os.path.splitext(filename)
|
||||
if existedSuffix != self.suffix:
|
||||
continue
|
||||
if len(filename) != len(self.prefix) + \
|
||||
len(self.suffix) + 18:
|
||||
continue
|
||||
timeStamp = existedPrefix[-17:]
|
||||
# check log file name
|
||||
if self.__isValidDate(timeStamp):
|
||||
filenameList.append(filename)
|
||||
# cleanup logFileList
|
||||
if os.path.exists(logFileList):
|
||||
os.remove(logFileList)
|
||||
|
||||
if len(filenameList) == 0:
|
||||
return False
|
||||
# get logFile
|
||||
fileName = max(filenameList)
|
||||
self.logFile = os.path.join(self.logPath, fileName)
|
||||
self.__checkLink()
|
||||
return True
|
||||
|
||||
def __openLogFile(self):
|
||||
"""
|
||||
function: open log file
|
||||
input : NA
|
||||
output: NA
|
||||
"""
|
||||
try:
|
||||
if self.__checkLogFileExist():
|
||||
self.fp = open(self.logFile, "a")
|
||||
return
|
||||
# get current time
|
||||
currentTime = time.strftime("%Y-%m-%d_%H%M%S")
|
||||
# init log file
|
||||
self.logFile = os.path.join(self.logPath, self.prefix + "-" + currentTime + self.suffix)
|
||||
# Re-create the log file to add a retry 3 times mechanism,
|
||||
# in order to call concurrently between multiple processes
|
||||
retryTimes = 3
|
||||
count = 0
|
||||
while (True):
|
||||
(status, output) = self.__createLogFile()
|
||||
if status == 0:
|
||||
break
|
||||
count = count + 1
|
||||
time.sleep(1)
|
||||
if (count > retryTimes):
|
||||
raise Exception(output)
|
||||
# open log file
|
||||
self.__checkLink()
|
||||
self.fp = open(self.logFile, "a")
|
||||
except Exception as e:
|
||||
raise Exception(ErrorCode.GAUSS_502["GAUSS_50206"]
|
||||
% self.logFile + " Error:\n%s" % str(e))
|
||||
|
||||
def __createLogFile(self):
|
||||
"""
|
||||
function: create log file
|
||||
input : NA
|
||||
output: (status, output)
|
||||
"""
|
||||
try:
|
||||
if (not os.path.exists(self.logFile)):
|
||||
os.mknod(self.logFile)
|
||||
return (0, "")
|
||||
except Exception as e:
|
||||
return (1, str(e))
|
||||
|
||||
def __isValidDate(self, datastr):
|
||||
"""
|
||||
function: Judge if date valid
|
||||
input : datastr
|
||||
output: bool
|
||||
"""
|
||||
try:
|
||||
time.strptime(datastr, "%Y-%m-%d_%H%M%S")
|
||||
return True
|
||||
except Exception as ex:
|
||||
return False
|
||||
|
||||
def closeLog(self):
|
||||
"""
|
||||
function: Function to close log file
|
||||
input : NA
|
||||
output: NA
|
||||
"""
|
||||
try:
|
||||
if self.fp:
|
||||
self.fp.flush()
|
||||
self.fp.close()
|
||||
self.fp = None
|
||||
except Exception as ex:
|
||||
if self.fp:
|
||||
self.fp.close()
|
||||
raise Exception(str(ex))
|
||||
|
||||
# print the flow message to console window and log file
|
||||
# AddInfo: constant represent step constant, addStep represent step
|
||||
# plus, None represent no step
|
||||
def log(self, msg, stepFlag=""):
|
||||
"""
|
||||
function:print the flow message to console window and log file
|
||||
input: msg,stepFlag
|
||||
control: when stepFlag="", the OM background log does not display
|
||||
step information.
|
||||
when stepFlag="addStep", the OM background log step will
|
||||
add 1.
|
||||
when stepFlag="constant", the OM background log step
|
||||
defaults to the current step.
|
||||
output: NA
|
||||
"""
|
||||
if (LOG_INFO >= self.expectLevel):
|
||||
print(msg)
|
||||
self.__writeLog("LOG", msg, stepFlag)
|
||||
|
||||
# print the flow message to log file only
|
||||
def debug(self, msg, stepFlag=""):
|
||||
"""
|
||||
function:print the flow message to log file only
|
||||
input: msg,stepFlag
|
||||
control: when stepFlag="", the OM background log does not display
|
||||
step information.
|
||||
when stepFlag="addStep", the OM background log step will
|
||||
add 1.
|
||||
when stepFlag="constant", the OM background log step
|
||||
defaults to the current step.
|
||||
output: NA
|
||||
"""
|
||||
if (LOG_DEBUG >= self.expectLevel):
|
||||
self.__writeLog("DEBUG", msg, stepFlag)
|
||||
|
||||
def warn(self, msg, stepFlag=""):
|
||||
"""
|
||||
function:print the flow message to log file only
|
||||
input: msg,stepFlag
|
||||
control: when stepFlag="", the OM background log does not display
|
||||
step information.
|
||||
when stepFlag="addStep", the OM background log step will
|
||||
add 1.
|
||||
when stepFlag="constant", the OM background log step
|
||||
defaults to the current step.
|
||||
output: NA
|
||||
"""
|
||||
if (LOG_WARNING >= self.expectLevel):
|
||||
print(msg)
|
||||
self.__writeLog("WARNING", msg, stepFlag)
|
||||
|
||||
# print the error message to console window and log file
|
||||
def error(self, msg):
|
||||
"""
|
||||
function: print the error message to console window and log file
|
||||
input : msg
|
||||
output: NA
|
||||
"""
|
||||
if (LOG_ERROR >= self.expectLevel):
|
||||
print(msg)
|
||||
self.__writeLog("ERROR", msg)
|
||||
|
||||
# print the error message to console window and log file,then exit
|
||||
def logExit(self, msg):
|
||||
"""
|
||||
function: print the error message to console window and log file,
|
||||
then exit
|
||||
input : msg
|
||||
output: NA
|
||||
"""
|
||||
if (LOG_FATAL >= self.expectLevel):
|
||||
print(msg)
|
||||
try:
|
||||
self.__writeLog("ERROR", msg)
|
||||
except Exception as ex:
|
||||
print(str(ex))
|
||||
self.closeLog()
|
||||
sys.exit(1)
|
||||
|
||||
def Step(self, stepFlag):
|
||||
"""
|
||||
function: return Step number info
|
||||
input: add
|
||||
output: step number
|
||||
"""
|
||||
if (stepFlag == "constant"):
|
||||
return self.step
|
||||
else:
|
||||
self.step = self.step + 1
|
||||
return self.step
|
||||
|
||||
def __getLogFileLine(self):
|
||||
f = sys._getframe().f_back.f_back.f_back
|
||||
return "%s(%s:%s)" % (os.path.basename(f.f_code.co_filename), f.f_code.co_name,
|
||||
str(f.f_lineno))
|
||||
|
||||
def __writeLog(self, level, msg, stepFlag=""):
|
||||
"""
|
||||
function: Write log to file
|
||||
input: level, msg, stepFlag
|
||||
output: NA
|
||||
"""
|
||||
if self.fp is None:
|
||||
return
|
||||
|
||||
try:
|
||||
self.lock.acquire()
|
||||
# if the log file does not exits, create it
|
||||
if (not os.path.exists(self.logFile)):
|
||||
self.__openLogFile()
|
||||
else:
|
||||
logPer = oct(os.stat(self.logFile).st_mode)[-3:]
|
||||
self.__checkLink()
|
||||
if not logPer == "600":
|
||||
os.chmod(self.logFile, 0o600)
|
||||
# check if need switch to an new log file
|
||||
self.size = os.path.getsize(self.logFile)
|
||||
if self.size >= MAXLOGFILESIZE and os.getuid() != 0:
|
||||
self.closeLog()
|
||||
self.__openLogFile()
|
||||
|
||||
replaceReg = re.compile(r'-W[ ]*[^ ]*[ ]*')
|
||||
msg = replaceReg.sub('-W *** ', str(msg))
|
||||
|
||||
if msg.find("gs_redis") >= 0:
|
||||
replaceReg = re.compile(r'-A[ ]*[^ ]*[ ]*')
|
||||
msg = replaceReg.sub('-A *** ', str(msg))
|
||||
|
||||
strTime = datetime.datetime.now()
|
||||
fileLine = self.__getLogFileLine()
|
||||
if stepFlag == "":
|
||||
if self.traceId:
|
||||
print("[%s][%s][%d][%s][%s]:%s"
|
||||
% (self.traceId, strTime, self.pid, self.moduleName,
|
||||
level, msg), file=self.fp)
|
||||
else:
|
||||
print("[%s][%d][%s][%s]:%s" % (
|
||||
strTime, self.pid, self.moduleName, level, msg),
|
||||
file=self.fp)
|
||||
else:
|
||||
stepnum = self.Step(stepFlag)
|
||||
print("[%s][%d][%s][%s][%s][Step%d]:%s" % (
|
||||
strTime, self.pid, fileLine, self.moduleName, level, stepnum, msg),
|
||||
file=self.fp)
|
||||
self.fp.flush()
|
||||
self.lock.release()
|
||||
except Exception as ex:
|
||||
self.lock.release()
|
||||
if self.ignoreErr:
|
||||
return
|
||||
raise Exception(ErrorCode.GAUSS_502["GAUSS_50205"]
|
||||
% (("log file %s") % self.logFile) +
|
||||
" Error:\n%s" % str(ex))
|
||||
|
||||
@staticmethod
|
||||
def exitWithError(msg, status=1):
|
||||
"""
|
||||
function: Exit with error message
|
||||
input: msg, status=1
|
||||
output: NA
|
||||
"""
|
||||
sys.stderr.write("%s\n" % msg)
|
||||
sys.exit(status)
|
||||
|
||||
@staticmethod
|
||||
def printMessage(msg):
|
||||
"""
|
||||
function: Print the String message
|
||||
input: msg
|
||||
output: NA
|
||||
"""
|
||||
sys.stdout.write("%s\n" % msg)
|
||||
|
||||
|
42
tool/cm_tool/Common.py
Normal file
42
tool/cm_tool/Common.py
Normal file
@ -0,0 +1,42 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
#############################################################################
|
||||
# Copyright (c) 2022 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.py includes some public function
|
||||
#############################################################################
|
||||
|
||||
import subprocess
|
||||
from CMLog import CMLog
|
||||
from ErrorCode import ErrorCode
|
||||
|
||||
def getEnvParam(envFile, param):
|
||||
cmd = "source {envFile}; echo ${param}".format(envFile=envFile, param=param)
|
||||
status, output = subprocess.getstatusoutput(cmd)
|
||||
if status != 0:
|
||||
errorDetail = "\nCommand: %s\nStatus: %s\nOutput: %s\n" % (
|
||||
cmd, status, output)
|
||||
CMLog.exitWithError(ErrorCode.GAUSS_518["GAUSS_51802"] % param)
|
||||
return output
|
||||
|
||||
def getLocalhostName():
|
||||
import socket
|
||||
return socket.gethostname()
|
||||
|
||||
def executeCmdOnHost(host, cmd, isLocal = False):
|
||||
if not isLocal:
|
||||
cmd = 'ssh -o ConnectTimeout=5 %s \"%s\"' % (host, cmd)
|
||||
status, output = subprocess.getstatusoutput(cmd)
|
||||
return status, output
|
1173
tool/cm_tool/ErrorCode.py
Normal file
1173
tool/cm_tool/ErrorCode.py
Normal file
File diff suppressed because it is too large
Load Diff
307
tool/cm_tool/InstallImpl.py
Normal file
307
tool/cm_tool/InstallImpl.py
Normal file
@ -0,0 +1,307 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
#############################################################################
|
||||
# Copyright (c) 2022 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 : InstallImpl.py
|
||||
#############################################################################
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import xml.etree.cElementTree as ETree
|
||||
from ErrorCode import ErrorCode
|
||||
from Common import executeCmdOnHost
|
||||
from CMLog import CMLog
|
||||
|
||||
class InstallImpl:
|
||||
def __init__(self, install):
|
||||
self.cmpkg = install.cmpkg
|
||||
self.context = install
|
||||
self.envFile = install.envFile
|
||||
self.xmlFile = install.xmlFile
|
||||
self.cmDirs = install.cmDirs
|
||||
self.hostNames = install.hostNames
|
||||
self.gaussHome = install.gaussHome
|
||||
self.gaussLog = install.gaussLog
|
||||
self.toolPath = install.toolPath
|
||||
self.tmpPath = install.tmpPath
|
||||
self.localhostName = install.localhostName
|
||||
self.logger = install.logger
|
||||
|
||||
def executeCmdOnHost(self, host, cmd, isLocal = False):
|
||||
if host == self.localhostName:
|
||||
isLocal = True
|
||||
return executeCmdOnHost(host, cmd, isLocal)
|
||||
|
||||
def prepareCMPath(self):
|
||||
"""
|
||||
create path: cmdir、cmdir/cm_server、cmdir/cm_agent
|
||||
"""
|
||||
self.logger.log("Preparing CM path.")
|
||||
for (cmdir, host) in zip(self.cmDirs, self.hostNames):
|
||||
cmd = "mkdir -p {cmdir}/cm_server {cmdir}/cm_agent".format(cmdir=cmdir)
|
||||
status, output = self.executeCmdOnHost(host, cmd)
|
||||
if status != 0:
|
||||
self.logger.debug("Command: " + cmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit("Failed to create CM path." + errorDetail)
|
||||
|
||||
def decompressCMPkg(self):
|
||||
self.logger.log("Decompressing CM pacakage.")
|
||||
if self.cmpkg == "":
|
||||
return
|
||||
# decompress cm pkg on localhost
|
||||
decompressCmd = "tar -zxf %s -C %s" % (self.cmpkg, self.gaussHome)
|
||||
status, output = subprocess.getstatusoutput(decompressCmd)
|
||||
if status != 0:
|
||||
self.logger.debug("Command: " + decompressCmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit("Failed to decompress cm pacakage to on localhost." + errorDetail)
|
||||
|
||||
# If the version of CM pacakage is inconsistent with that of gaussdb,
|
||||
# then exit. So no need to send CM pacakage to other nodes.
|
||||
self.checkCMPkgVersion()
|
||||
|
||||
# decompress cmpkg on other hosts
|
||||
cmpkgName = os.path.basename(self.cmpkg)
|
||||
for host in self.hostNames:
|
||||
if host == self.localhostName:
|
||||
continue
|
||||
# copy cm pacakage to other hosts
|
||||
scpCmd = "scp %s %s:%s" % (self.cmpkg, host, self.toolPath)
|
||||
status, output = subprocess.getstatusoutput(scpCmd)
|
||||
if status != 0:
|
||||
self.logger.debug("Command: " + scpCmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit(("Failed to send cm pacakage to %s." % host) + errorDetail)
|
||||
pkgPath = os.path.join(self.toolPath, cmpkgName)
|
||||
decompressCmd = "tar -zxf %s -C %s" % (pkgPath, self.gaussHome)
|
||||
status, output = self.executeCmdOnHost(host, decompressCmd)
|
||||
if status != 0:
|
||||
self.logger.debug("Command: " + decompressCmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit(("Failed to decompress cm pacakage to on host %s." % host) + errorDetail)
|
||||
|
||||
def checkCMPkgVersion(self):
|
||||
getCMVersionCmd = "source %s; cm_ctl -V" % self.envFile
|
||||
status, output = subprocess.getstatusoutput(getCMVersionCmd)
|
||||
if status != 0:
|
||||
self.logger.logExit("Failed to get CM pacakage version.")
|
||||
cmVersionList = re.findall(r'openGauss CM (\d.*\d) build', output)
|
||||
if len(cmVersionList) == 0:
|
||||
self.logger.logExit("Failed to get CM pacakage version.")
|
||||
cmVersion = cmVersionList[0]
|
||||
|
||||
getGaussdbVersionCmd = "source %s; gaussdb -V" % self.envFile
|
||||
status, output = subprocess.getstatusoutput(getGaussdbVersionCmd)
|
||||
if status != 0:
|
||||
self.logger.logExit("Failed to get gaussdb version.")
|
||||
gaussdbVersionList = re.findall(r'openGauss (\d.*\d) build', output)
|
||||
if len(gaussdbVersionList) == 0:
|
||||
self.logger.logExit("Failed to get gaussdb version.")
|
||||
gaussdbVersion = gaussdbVersionList[0]
|
||||
|
||||
if gaussdbVersion != cmVersion:
|
||||
self.logger.logExit("The version of CM pacakage(%s) is inconsistent "
|
||||
"with that of gaussdb(%s)." % (cmVersion, gaussdbVersion))
|
||||
|
||||
def createManualStartFile(self):
|
||||
self.logger.log("Creating cluster_manual_start file.")
|
||||
cmd = """
|
||||
if [ ! -f {gaussHome}/bin/cluster_manual_start ]; then
|
||||
touch {gaussHome}/bin/cluster_manual_start
|
||||
fi
|
||||
""".format(gaussHome=self.gaussHome)
|
||||
for host in self.hostNames:
|
||||
status, output = self.executeCmdOnHost(host, cmd)
|
||||
if status != 0:
|
||||
self.logger.debug("Command: " + cmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit("Failed to create cluster_manual_start file." + errorDetail)
|
||||
|
||||
def initCMServer(self):
|
||||
self.logger.log("Initializing cm_server.")
|
||||
for (cmdir, host) in zip(self.cmDirs, self.hostNames):
|
||||
cmd = """
|
||||
cp {gaussHome}/share/config/cm_server.conf.sample {cmdir}/cm_server/cm_server.conf
|
||||
sed 's#log_dir = .*#log_dir = {gaussLog}/cm/cm_server#' {cmdir}/cm_server/cm_server.conf -i
|
||||
""".format(gaussHome=self.gaussHome, gaussLog=self.gaussLog, cmdir=cmdir)
|
||||
status, output = self.executeCmdOnHost(host, cmd)
|
||||
if status != 0:
|
||||
self.logger.debug("Command: " + cmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit("Failed to initialize cm_server." + errorDetail)
|
||||
|
||||
def initCMAgent(self):
|
||||
self.logger.log("Initializing cm_agent.")
|
||||
for (cmdir, host) in zip(self.cmDirs, self.hostNames):
|
||||
cmd = """
|
||||
cp {gaussHome}/share/config/cm_agent.conf.sample {cmdir}/cm_agent/cm_agent.conf &&
|
||||
sed 's#log_dir = .*#log_dir = {gaussLog}/cm/cm_agent#' {cmdir}/cm_agent/cm_agent.conf -i &&
|
||||
sed 's#unix_socket_directory = .*#unix_socket_directory = {gaussHome}#' {cmdir}/cm_agent/cm_agent.conf -i
|
||||
""".format(gaussHome=self.gaussHome, gaussLog=self.gaussLog, cmdir=cmdir)
|
||||
status, output = self.executeCmdOnHost(host, cmd)
|
||||
if status != 0:
|
||||
self.logger.debug("Command: " + cmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit("Failed to initialize cm_agent." + errorDetail)
|
||||
|
||||
def setMonitorCrontab(self):
|
||||
"""
|
||||
set om_monitor crontab
|
||||
"""
|
||||
self.logger.log("Setting om_monitor crontab.")
|
||||
# save old crontab content to cronContentTmpFile
|
||||
cronContentTmpFile = os.path.join(self.tmpPath, "cronContentTmpFile_" + str(os.getpid()))
|
||||
listCronCmd = "crontab -l > %s" % cronContentTmpFile
|
||||
status, output = self.executeCmdOnHost(self.localhostName, listCronCmd)
|
||||
if status != 0:
|
||||
self.logger.debug("Command: " + listCronCmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit(ErrorCode.GAUSS_508["GAUSS_50804"] + errorDetail)
|
||||
# if old crontab content contains om_monitor, clear it
|
||||
clearMonitorCmd = "sed '/.*om_monitor.*/d' %s -i" % cronContentTmpFile
|
||||
status, output = subprocess.getstatusoutput(clearMonitorCmd)
|
||||
if status != 0:
|
||||
os.remove(cronContentTmpFile)
|
||||
self.logger.debug("Command: " + clearMonitorCmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit("Failed to clear old om_monitor crontab." + errorDetail)
|
||||
|
||||
# generate om_monitor crontab command and append it to cronContentTmpFile
|
||||
startMonitorCmd = "source /etc/profile;(if [ -f ~/.profile ];" \
|
||||
"then source ~/.profile;fi);source ~/.bashrc;"
|
||||
if self.envFile != "~/.bashrc":
|
||||
startMonitorCmd += "source %s; " % (self.envFile)
|
||||
monitorLogPath = os.path.join(self.gaussLog, "cm")
|
||||
if not os.path.exists(monitorLogPath):
|
||||
os.makedirs(monitorLogPath)
|
||||
startMonitorCmd += "nohup om_monitor -L %s/om_monitor >>/dev/null 2>&1 &" % monitorLogPath
|
||||
monitorCron = "*/1 * * * * " + startMonitorCmd + os.linesep
|
||||
with open(cronContentTmpFile, 'a+', encoding='utf-8') as fp:
|
||||
fp.writelines(monitorCron)
|
||||
fp.flush()
|
||||
|
||||
# set crontab on other hosts
|
||||
setCronCmd = "crontab %s" % cronContentTmpFile
|
||||
cleanTmpFileCmd = "rm %s -f" % cronContentTmpFile
|
||||
for host in self.hostNames:
|
||||
if host == self.localhostName:
|
||||
continue
|
||||
# copy cronContentTmpFile to other host
|
||||
scpCmd = "scp %s %s:%s" % (cronContentTmpFile, host, self.tmpPath)
|
||||
status, output = subprocess.getstatusoutput(scpCmd)
|
||||
if status != 0:
|
||||
self.logger.debug("Command: " + scpCmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit(("Failed to copy cronContentTmpFile to %s." % host) + errorDetail)
|
||||
# set om_monitor crontab
|
||||
status, output = self.executeCmdOnHost(host, setCronCmd)
|
||||
# cleanup cronContentTmpFile
|
||||
self.executeCmdOnHost(host, cleanTmpFileCmd)
|
||||
if status != 0:
|
||||
self.logger.debug("Command: " + setCronCmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit(ErrorCode.GAUSS_508["GAUSS_50801"] + errorDetail)
|
||||
|
||||
# start om_monitor
|
||||
status, output = self.executeCmdOnHost(host, startMonitorCmd)
|
||||
if status != 0:
|
||||
self.logger.debug("Command: " + startMonitorCmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit((ErrorCode.GAUSS_516["GAUSS_51607"] % "om_monitor") + errorDetail)
|
||||
|
||||
# set crontab on localhost
|
||||
status, output = subprocess.getstatusoutput(setCronCmd)
|
||||
if status != 0:
|
||||
self.logger.debug("Command: " + setCronCmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit(ErrorCode.GAUSS_508["GAUSS_50801"] + errorDetail)
|
||||
os.remove(cronContentTmpFile)
|
||||
|
||||
status, output = subprocess.getstatusoutput(startMonitorCmd)
|
||||
if status != 0:
|
||||
self.logger.debug("Command: " + startMonitorCmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit((ErrorCode.GAUSS_516["GAUSS_51607"] % "om_monitor") + errorDetail)
|
||||
|
||||
def startCluster(self):
|
||||
self.logger.log("Starting cluster.")
|
||||
startCmd = "source %s; cm_ctl start" % self.envFile
|
||||
status, output = subprocess.getstatusoutput(startCmd)
|
||||
if status != 0:
|
||||
self.logger.debug("Command: " + startCmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit("Failed to start cluster." + errorDetail)
|
||||
queryCmd = "source %s; cm_ctl query -Cv" % self.envFile
|
||||
status, output = subprocess.getstatusoutput(queryCmd)
|
||||
if status != 0:
|
||||
self.logger.debug("Command: " + queryCmd)
|
||||
errorDetail = "\nStatus: %s\nOutput: %s" % (status, output)
|
||||
self.logger.logExit("Failed to query cluster status." + errorDetail)
|
||||
self.logger.log(output)
|
||||
self.logger.log("Install CM tool success.")
|
||||
|
||||
@staticmethod
|
||||
def refreshStaticFile(envFile, xmlFile):
|
||||
"""
|
||||
refresh static and dynamic file using xml file with cm
|
||||
"""
|
||||
# refresh static file
|
||||
cmd = """
|
||||
source {envFile};
|
||||
gs_om -t generateconf -X {xmlFile} --distribute
|
||||
""".format(envFile=envFile, xmlFile=xmlFile)
|
||||
status, output = subprocess.getstatusoutput(cmd)
|
||||
errorDetail = ""
|
||||
if status != 0:
|
||||
errorDetail = "\nCommand: %s\nStatus: %s\nOutput: %s" % (cmd, status, output)
|
||||
return status, errorDetail
|
||||
|
||||
@staticmethod
|
||||
def refreshDynamicFile(envFile):
|
||||
# refresh dynamic file
|
||||
getStatusCmd = "source %s; gs_om -t status --detail | grep 'Primary Normal' > /dev/null" % envFile
|
||||
status, output = subprocess.getstatusoutput(getStatusCmd)
|
||||
if status != 0:
|
||||
CMLog.printMessage("Normal primary doesn't exist in the cluster, no need to refresh dynamic file.")
|
||||
return 0, ""
|
||||
refreshDynamicFileCmd = "source %s; gs_om -t refreshconf" % envFile
|
||||
status, output = subprocess.getstatusoutput(refreshDynamicFileCmd)
|
||||
errorDetail = ""
|
||||
if status != 0:
|
||||
errorDetail = "\nCommand: %s\nStatus: %s\nOutput: %s" % (refreshDynamicFileCmd, status, output)
|
||||
return status, errorDetail
|
||||
|
||||
def refreshStaticAndDynamicFile(self):
|
||||
self.logger.log("Refreshing static and dynamic file using xml file with cm.")
|
||||
status, output = InstallImpl.refreshStaticFile(self.envFile, self.xmlFile)
|
||||
if status != 0:
|
||||
self.logger.logExit("Failed to refresh static file." + output)
|
||||
status, output = InstallImpl.refreshDynamicFile(self.envFile)
|
||||
if status != 0:
|
||||
self.logger.logExit("Failed to refresh dynamic file." + output)
|
||||
|
||||
def run(self):
|
||||
self.logger.log("Start to install cm tool.")
|
||||
self.prepareCMPath()
|
||||
self.decompressCMPkg()
|
||||
self.createManualStartFile()
|
||||
self.initCMServer()
|
||||
self.initCMAgent()
|
||||
self.refreshStaticAndDynamicFile()
|
||||
self.setMonitorCrontab()
|
||||
self.startCluster()
|
0
tool/cm_tool/__init__.py
Normal file
0
tool/cm_tool/__init__.py
Normal file
247
tool/cm_tool/cm_install
Normal file
247
tool/cm_tool/cm_install
Normal file
@ -0,0 +1,247 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding:utf-8 -*-
|
||||
#############################################################################
|
||||
# Copyright (c) 2022 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 : cm_install is a utility to deploy CM tool to openGauss database cluster.
|
||||
#############################################################################
|
||||
|
||||
import getopt
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import subprocess
|
||||
import xml.etree.cElementTree as ETree
|
||||
from CMLog import CMLog
|
||||
from Common import *
|
||||
from ErrorCode import ErrorCode
|
||||
from InstallImpl import InstallImpl
|
||||
|
||||
sys.path.append(sys.path[0] + "/../../")
|
||||
|
||||
class Install:
|
||||
"""
|
||||
The class is used to do perform installation
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.envFile = ""
|
||||
self.xmlFile = ""
|
||||
self.gaussHome = ""
|
||||
self.gaussLog = ""
|
||||
self.toolPath = ""
|
||||
self.tmpPath = ""
|
||||
self.cmDirs = []
|
||||
self.hostNames = []
|
||||
self.localhostName = ""
|
||||
self.cmpkg = ""
|
||||
|
||||
def getLocalhostName(self):
|
||||
import socket
|
||||
self.localhostName = socket.gethostname()
|
||||
|
||||
def getEnvParams(self):
|
||||
self.gaussHome = getEnvParam(self.envFile, "GAUSSHOME")
|
||||
self.gaussLog = getEnvParam(self.envFile, "GAUSSLOG")
|
||||
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"])
|
||||
|
||||
def usage(self):
|
||||
"""
|
||||
cm_install is a utility to deploy CM tool to openGauss database cluster.
|
||||
|
||||
Usage:
|
||||
cm_install -? | --help
|
||||
cm_install -X XMLFILE [-e envFile] --cmpkg=cmpkgPath
|
||||
General options:
|
||||
-X Path of the XML configuration file.
|
||||
-e Path of env file.
|
||||
Default value "~/.bashrc".
|
||||
--cmpkg Path of CM pacakage.
|
||||
-?, --help Show help information for this
|
||||
utility, and exit the command line mode.
|
||||
"""
|
||||
print(self.usage.__doc__)
|
||||
|
||||
def parseCommandLine(self):
|
||||
if len(sys.argv) == 1:
|
||||
self.usage()
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "?X:e:", ["help", "cmpkg="])
|
||||
except getopt.GetoptError as e:
|
||||
CMLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50000"] % str(e))
|
||||
|
||||
for opt, value in opts:
|
||||
if opt in ("-?", "--help"):
|
||||
self.usage()
|
||||
sys.exit(0)
|
||||
elif opt in ("-X"):
|
||||
self.xmlFile = value
|
||||
elif opt in ("-e"):
|
||||
self.envFile = value
|
||||
elif opt in ("--cmpkg"):
|
||||
self.cmpkg = value
|
||||
|
||||
def checkParam(self):
|
||||
if self.xmlFile == "":
|
||||
CMLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % 'X or xml' + ".")
|
||||
|
||||
if self.cmpkg == "":
|
||||
CMLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % 'p or cmpkg' + ".")
|
||||
|
||||
if self.envFile == "":
|
||||
self.envFile = "~/.bashrc"
|
||||
|
||||
def checkOm(self):
|
||||
"""
|
||||
check whether there is om tool
|
||||
"""
|
||||
cmd = "source %s; gs_om --version" % self.envFile
|
||||
status, output = subprocess.getstatusoutput(cmd)
|
||||
if status != 0:
|
||||
errorDetail = "\nCommand: %s\nStatus: %s\nOutput: %s\n" % (
|
||||
cmd, status, output)
|
||||
CMLog.exitWithError("OM tool is required." + errorDetail)
|
||||
|
||||
def checkXMLFileSecurity(self):
|
||||
"""
|
||||
function : check XML contain DTDs
|
||||
input : String
|
||||
output : NA
|
||||
"""
|
||||
# Check xml for security requirements
|
||||
# if it have "<!DOCTYPE" or it have "<!ENTITY",
|
||||
# exit and print "File have security risks."
|
||||
try:
|
||||
with open(self.xmlFile, "r", encoding='utf-8') as fb:
|
||||
lines = fb.readlines()
|
||||
for line in lines:
|
||||
if re.findall("<!DOCTYPE", line) or re.findall("<!ENTITY", line):
|
||||
raise Exception("File have security risks.")
|
||||
except Exception as e:
|
||||
raise Exception(str(e))
|
||||
|
||||
def initParserXMLFile(self):
|
||||
"""
|
||||
function : Init parser xml file
|
||||
input : String
|
||||
output : Object
|
||||
"""
|
||||
try:
|
||||
# check xml for security requirements
|
||||
self.checkXMLFileSecurity()
|
||||
dom_tree = ETree.parse(self.xmlFile)
|
||||
rootNode = dom_tree.getroot()
|
||||
except Exception as e:
|
||||
raise Exception(ErrorCode.GAUSS_512["GAUSS_51236"] + " Error: \n%s." % str(e))
|
||||
return rootNode
|
||||
|
||||
def getInfoListOfAllNodes(self):
|
||||
"""
|
||||
get hostname and cmDir list of all nodes
|
||||
"""
|
||||
self.localhostName = getLocalhostName()
|
||||
|
||||
rootNode = self.initParserXMLFile()
|
||||
elementName = 'DEVICELIST'
|
||||
if not rootNode.findall('DEVICELIST'):
|
||||
raise Exception(ErrorCode.GAUSS_512["GAUSS_51200"] % elementName)
|
||||
deviceArray = rootNode.findall('DEVICELIST')[0]
|
||||
deviceNodes = deviceArray.findall('DEVICE')
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
def initLogger(self):
|
||||
logPath = os.path.join(self.gaussLog, "cm", "cm_tool")
|
||||
if not os.path.exists(logPath):
|
||||
os.makedirs(logPath)
|
||||
self.logger = CMLog(logPath, "cm_install", "cm_install")
|
||||
|
||||
def checkCM(self):
|
||||
"""
|
||||
Check whether there is CM in current cluster.
|
||||
"""
|
||||
checkCMExistCmd = "source %s; gs_om -t status --detail | " \
|
||||
"grep 'CMServer State' > /dev/null" % self.envFile
|
||||
status, output = subprocess.getstatusoutput(checkCMExistCmd)
|
||||
if status == 0:
|
||||
CMLog.exitWithError("CM exists in current cluster.")
|
||||
def run(self):
|
||||
self.checkExeUser()
|
||||
self.parseCommandLine()
|
||||
self.checkParam()
|
||||
self.checkOm()
|
||||
self.checkCM()
|
||||
self.checkXMLFile()
|
||||
self.getEnvParams()
|
||||
self.initLogger()
|
||||
self.getLocalhostName()
|
||||
self.getInfoListOfAllNodes()
|
||||
self.checkHostTrust()
|
||||
installImpl = InstallImpl(self)
|
||||
installImpl.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
install = Install()
|
||||
install.run()
|
249
tool/cm_tool/cm_uninstall
Normal file
249
tool/cm_tool/cm_uninstall
Normal file
@ -0,0 +1,249 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding:utf-8 -*-
|
||||
#############################################################################
|
||||
# Copyright (c) 2022 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 : cm_install is a utility to uninstall CM tool to openGauss database cluster.
|
||||
#############################################################################
|
||||
|
||||
import os
|
||||
import sys
|
||||
import getopt
|
||||
import subprocess
|
||||
from CMLog import CMLog
|
||||
from ErrorCode import ErrorCode
|
||||
from InstallImpl import InstallImpl
|
||||
from Common import executeCmdOnHost, getEnvParam, getLocalhostName
|
||||
|
||||
class UnIntall:
|
||||
def __init__(self) -> None:
|
||||
self.envFile = ""
|
||||
self.xmlFile = ""
|
||||
self.bDeleteData = False
|
||||
self.bDeleteBinary = False
|
||||
self.hostnames = []
|
||||
self.cmDataPaths = []
|
||||
self.localhostName = getLocalhostName()
|
||||
|
||||
def usage(self):
|
||||
"""
|
||||
cm_uninstall is a utility to deploy CM tool to openGauss database cluster.
|
||||
|
||||
Usage:
|
||||
cm_uninstall -? | --help
|
||||
cm_uninstall -X XMLFILE [-e envFile] [--deleteData] [--deleteBinary]
|
||||
General options:
|
||||
-X Path of the XML configuration file.
|
||||
-e Path of env file.
|
||||
Default value "~/.bashrc".
|
||||
--deleteData Specify to true if you want to remove cmdatapath and GAUSSLOG/cm.
|
||||
--deleteBinary Specify to true if you want to remove CM binary file.
|
||||
-?, --help Show help information for this
|
||||
utility, and exit the command line mode.
|
||||
"""
|
||||
print(self.usage.__doc__)
|
||||
|
||||
def parseCommandLine(self):
|
||||
if len(sys.argv) == 1:
|
||||
self.usage()
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "?X:e:",
|
||||
["help", "deleteData", "deleteBinary"])
|
||||
except getopt.GetoptError as e:
|
||||
CMLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50000"] % str(e))
|
||||
|
||||
for opt, value in opts:
|
||||
if opt in ("-?", "--help"):
|
||||
self.usage()
|
||||
sys.exit(0)
|
||||
elif opt in ("-X"):
|
||||
self.xmlFile = value
|
||||
elif opt in ("-e"):
|
||||
self.envFile = value
|
||||
elif opt in ("--deleteData"):
|
||||
self.bDeleteData = True
|
||||
elif opt in ("--deleteBinary"):
|
||||
self.bDeleteBinary = True
|
||||
|
||||
def checkParam(self):
|
||||
if self.xmlFile == "":
|
||||
CMLog.exitWithError(
|
||||
ErrorCode.GAUSS_500["GAUSS_50001"] % 'X' + ".")
|
||||
|
||||
if self.envFile == "":
|
||||
self.envFile = "~/.bashrc"
|
||||
|
||||
def getHostnames(self):
|
||||
"""
|
||||
Get hostnames of all nodes from static file.
|
||||
"""
|
||||
self.logger.debug("Getting hostnames")
|
||||
cmd = "source %s; cm_ctl view | grep 'nodeName'" % self.envFile
|
||||
status, output = subprocess.getstatusoutput(cmd)
|
||||
if status != 0:
|
||||
self.logger.logExit((ErrorCode.GAUSS_512["GAUSS_51203"] % "hostnames") + output)
|
||||
hostnames = output.split('\n')
|
||||
for i in range(0, len(hostnames)):
|
||||
hostname = hostnames[i].split(':')[1].strip()
|
||||
self.hostnames.append(hostname)
|
||||
self.logger.debug("hostnames=" + ','.join(self.hostnames))
|
||||
|
||||
def getCMDataPaths(self):
|
||||
"""
|
||||
Get cmDataPaths of all nodes from static file.
|
||||
"""
|
||||
if not self.bDeleteData:
|
||||
return
|
||||
self.logger.debug("Getting CM datapaths.")
|
||||
cmd = "source %s; cm_ctl view | grep -E 'cmDataPath'" % self.envFile
|
||||
status, output = subprocess.getstatusoutput(cmd)
|
||||
if status != 0:
|
||||
self.logger.logExit((ErrorCode.GAUSS_512["GAUSS_51203"] % "cmDataPaths") + output)
|
||||
cmDataPaths = output.split('\n')
|
||||
for p in cmDataPaths:
|
||||
cmDataPath = p.split(':')[1].strip()
|
||||
self.cmDataPaths.append(cmDataPath)
|
||||
if self.cmDataPaths == []:
|
||||
self.logger.logExit("")
|
||||
self.logger.debug("cmDataPaths=" + ','.join(self.cmDataPaths))
|
||||
|
||||
def cancleMonitorCrontab(self):
|
||||
"""
|
||||
Cancle monitor crontab of all nodes.
|
||||
"""
|
||||
self.logger.log("Cancling monitor crontab.")
|
||||
cronContentTmpFile = os.path.join("/tmp", "cronContentTmpFile_" + str(os.getpid()))
|
||||
cmd = """
|
||||
crontab -l > {cronContentTmpFile};
|
||||
sed '/.*om_monitor.*/d' {cronContentTmpFile} -i;
|
||||
crontab {cronContentTmpFile}
|
||||
""".format(cronContentTmpFile=cronContentTmpFile)
|
||||
for host in self.hostnames:
|
||||
status, output = executeCmdOnHost(host, cmd)
|
||||
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)
|
||||
|
||||
def stopCMProcess(self):
|
||||
"""
|
||||
Stop CM process of all nodes, includeing om_monitor, cm_agent, cm_server, gaussdb fence
|
||||
"""
|
||||
self.logger.log("Stopping CM process.")
|
||||
# When you execute the awk command through Python, sometimes the awk command is invalid,
|
||||
# just like your command does not use the awk command. Therefore, we have to avoid using awk.
|
||||
getPidsCmd = "ps -xo pid,command | grep -E 'om_monitor|cm_agent|cm_server|fenced UDF' | grep -v grep"
|
||||
for host in self.hostnames:
|
||||
isLocal = False
|
||||
if host == self.localhostName:
|
||||
isLocal = True
|
||||
# get CM process pids
|
||||
status, output = executeCmdOnHost(host, getPidsCmd, isLocal)
|
||||
self.logger.debug("Command: " + getPidsCmd)
|
||||
self.logger.debug("Status: " + str(status))
|
||||
self.logger.debug("Output: " + output)
|
||||
if output == "":
|
||||
continue
|
||||
processList = output.strip().split('\n')
|
||||
pidList = []
|
||||
for process in processList:
|
||||
pid = process.split()[0]
|
||||
if pid.isdigit():
|
||||
pidList.append(pid)
|
||||
if pidList == []:
|
||||
continue
|
||||
# kill CM process
|
||||
pidsStr = ' '.join(pidList)
|
||||
killCMProcessCmd = "kill -9 " + pidsStr
|
||||
status, output = executeCmdOnHost(host, killCMProcessCmd, isLocal)
|
||||
if status != 0:
|
||||
errorDetail = "\nCommand: %s\nStatus: %s\nOutput: %s" % (killCMProcessCmd, status, output)
|
||||
self.logger.logExit((ErrorCode.GAUSS_516["GAUSS_51606"] % "CM") + errorDetail)
|
||||
|
||||
def refreshStaticAndDynamicFile(self):
|
||||
self.logger.log("Refreshing static and dynamic file using xml file without cm.")
|
||||
status, output = InstallImpl.refreshStaticFile(self.envFile, self.xmlFile)
|
||||
if status != 0:
|
||||
self.logger.logExit("Failed to refresh static file." + output)
|
||||
status, output = InstallImpl.refreshDynamicFile(self.envFile)
|
||||
if status != 0:
|
||||
self.logger.logExit("Failed to refresh dynamic file." + output)
|
||||
|
||||
def deleteData(self):
|
||||
"""
|
||||
remove cmdatapath
|
||||
"""
|
||||
if not self.bDeleteData:
|
||||
return
|
||||
self.logger.log("Deleting CM data path.")
|
||||
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)
|
||||
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)
|
||||
|
||||
def deleteBinary(self):
|
||||
"""
|
||||
delete CM binaries, include om_monitor, cm_agent, cm_server, cm_ctl
|
||||
"""
|
||||
if not self.bDeleteBinary:
|
||||
return
|
||||
self.logger.log("Deleting CM binaries.")
|
||||
for host in self.hostnames:
|
||||
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
|
||||
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)
|
||||
|
||||
def initLogger(self):
|
||||
gaussLog = getEnvParam(self.envFile, "GAUSSLOG")
|
||||
logPath = os.path.join(gaussLog, "cm", "cm_tool")
|
||||
if not os.path.exists(logPath):
|
||||
os.makedirs(logPath)
|
||||
self.logger = CMLog(logPath, module="cm_uninstall", prefix="cm_uninstall")
|
||||
|
||||
def checkExeUser(self):
|
||||
if os.getuid() == 0:
|
||||
CMLog.exitWithError(ErrorCode.GAUSS_501["GAUSS_50105"])
|
||||
|
||||
def run(self):
|
||||
self.checkExeUser()
|
||||
self.parseCommandLine()
|
||||
self.checkParam()
|
||||
self.initLogger()
|
||||
self.logger.log("Start to uninstall CM.")
|
||||
self.getHostnames()
|
||||
self.getCMDataPaths()
|
||||
self.cancleMonitorCrontab()
|
||||
self.stopCMProcess()
|
||||
self.refreshStaticAndDynamicFile()
|
||||
self.deleteData()
|
||||
self.deleteBinary()
|
||||
self.logger.log("Uninstall CM tool success.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unInstall = UnIntall()
|
||||
unInstall.run()
|
Loading…
x
Reference in New Issue
Block a user