# -*- 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. # ---------------------------------------------------------------------------- import sys import subprocess import time import os sys.path.append(sys.path[0] + "/../") from gspylib.common.Common import DefaultValue, ClusterCommand from gspylib.common.OMCommand import OMCommand from gspylib.common.ErrorCode import ErrorCode from gspylib.os.gsfile import g_file from base_utils.executor.cmd_executor import CmdExecutor from domain_utils.cluster_file.cluster_dir import ClusterDir from base_utils.os.env_util import EnvUtil from base_utils.os.file_util import FileUtil from base_utils.os.net_util import NetUtil from gspylib.common.DbClusterInfo import dbNodeInfo, \ dbClusterInfo, compareObject from domain_utils.cluster_file.profile_file import ProfileFile class UninstallImpl: """ init the command options save command line parameter values """ def __init__(self, unstallation): """ function: constructor """ self.logFile = unstallation.logFile self.cleanInstance = unstallation.cleanInstance self.clearDisk = unstallation.clearDisk self.localLog = unstallation.localLog self.user = unstallation.user self.group = unstallation.group self.mpprcFile = unstallation.mpprcFile self.localMode = unstallation.localMode self.logger = unstallation.logger self.sshTool = unstallation.sshTool self.tmpDir = EnvUtil.getTmpDirFromEnv(self.user) try: # Initialize the unstallation.clusterInfo variable unstallation.initClusterInfoFromStaticFile(self.user) self.clusterInfo = unstallation.clusterInfo nodeNames = self.clusterInfo.getClusterNodeNames() # Initialize the self.sshTool variable unstallation.initSshTool(nodeNames, DefaultValue.TIMEOUT_PSSH_UNINSTALL) self.sshTool = unstallation.sshTool except Exception as e: self.logger.logExit(str(e)) def checkLogFilePath(self): """ function: Check log file path input : NA output: NA """ clusterPath = [] try: # get tool path clusterPath.append(ClusterDir.getClusterToolPath(self.user)) # get tmp path tmpDir = EnvUtil.getTmpDirFromEnv() clusterPath.append(tmpDir) # get cluster path hostName = NetUtil.GetHostIpOrName() dirs = self.clusterInfo.getClusterDirectorys(hostName, False) # loop all cluster path for checkdir in dirs.values(): clusterPath.extend(checkdir) self.logger.debug("Cluster paths %s." % clusterPath) # check directory FileUtil.checkIsInDirectory(self.logFile, clusterPath) except Exception as e: self.logger.logExit(str(e)) def checkUninstall(self): """ function: Check uninstall input : NA output: NA """ # Checking uninstallation self.logger.log("Checking uninstallation.", "addStep") # use check uninstall to check every nodes cmd = "%s -R '%s' -U %s -l %s" % ( OMCommand.getLocalScript("Local_Check_Uninstall"), self.clusterInfo.appPath, self.user, self.localLog) # check if need to clean instance if (self.cleanInstance): cmd += " -d" self.logger.debug("Command for checking uninstallation: " + cmd) CmdExecutor.execCommandWithMode(cmd, self.sshTool, self.localMode, self.mpprcFile) self.logger.log("Successfully checked uninstallation.", "constant") def cm_stop_cluster(self): """ Stop cluster with CM """ # get stop command, if node_id is not zero, then only stop local node node_id = 0 cmd = ClusterCommand.getStopCmd(node_id, "i") if self.localMode: local_node_list = [node for node in self.clusterInfo.dbNodes if node.name == NetUtil.GetHostIpOrName()] if not local_node_list: self.logger.logExit(ErrorCode.GAUSS_516["GAUSS_51610"] % "the cluster" + " Error:\nLocal node is not in the static file.") cmd = ClusterCommand.getStopCmd(local_node_list[0].id, "i") (status, output) = subprocess.getstatusoutput(cmd) # if do command fail, throw error if status != 0: self.logger.logExit(ErrorCode.GAUSS_516["GAUSS_51610"] % "the cluster" + " Error:\n%s" % output) if self.localMode: self.logger.log("Successfully stopped local node.", "constant") else: self.logger.log("Successfully stopped the cluster.", "constant") # check and kill all processes about # clean cm_agent,cm_server,gs_gtm,gaussdb(CN/DN) and etcd. self.logger.debug("Checking and killing processes.", "addStep") # local mode, kill all process in local node if self.localMode: for prog_name in ["cm_agent", "cm_server", "gaussdb", "CheckDataDiskUsage"]: DefaultValue.KillAllProcess(self.user, prog_name) # kill process in all nodes else: cm_agent_file = "%s/bin/cm_agent" % self.clusterInfo.appPath cm_server_file = "%s/bin/cm_server" % self.clusterInfo.appPath gaussdb_file = "%s/bin/gaussdb" % self.clusterInfo.appPath check_file = "CheckDataDiskUsage" for prog_name in [cm_agent_file, cm_server_file, gaussdb_file, check_file]: self.CheckAndKillAliveProc(prog_name) self.logger.debug("Successfully checked and killed processes.", "constant") def StopCluster(self): """ function: Stopping the cluster input : NA output: NA """ self.logger.log("Stopping the cluster.", "addStep") # get the static config static_config = \ "%s/bin/cluster_static_config" % self.clusterInfo.appPath static_config_bak = \ "%s/bin/cluster_static_config_bak" % self.clusterInfo.appPath # if cluster_static_config_bak exists # and static_config does not exists, mv it to static_config if (not os.path.exists(static_config) and os.path.exists( static_config_bak)): cmd = "mv %s %s" % (static_config_bak, static_config) (status, output) = subprocess.getstatusoutput(cmd) if (status != 0): self.logger.debug("The cmd is %s " % cmd) self.logger.error("rename cluster_static_config_bak failed") self.logger.debug("Error:\n%s" % output) # if path not exits, can not stop cluster if not os.path.exists(static_config): self.logger.debug("Failed to stop the cluster.", "constant") return if DefaultValue.get_cm_server_num_from_static(self.clusterInfo) == 0: # Stop cluster applications cmd = "source %s; %s -U %s -R %s -l %s" % ( self.mpprcFile, OMCommand.getLocalScript("Local_StopInstance"), self.user, self.clusterInfo.appPath, self.localLog) self.logger.debug("Command for stop cluster: %s" % cmd) CmdExecutor.execCommandWithMode(cmd, self.sshTool, self.localMode, self.mpprcFile) self.logger.log("Successfully stopped the cluster.") else: self.cm_stop_cluster() def CheckAndKillAliveProc(self, procFileName): """ function: When uninstall gaussdb cluster. After it is stopped, We must make sure that all process about gaussdb cluster have been stopped. Not including om_monitor. input : procFileName output: NA """ try: failedNodes = [] validNodeName = self.clusterInfo.getClusterNodeNames() # the command for killing all process cmd_check_kill = DefaultValue.killInstProcessCmd(procFileName, True, 9, False) # use sshTool to kill process in all nodes (status, output) = self.sshTool.getSshStatusOutput(cmd_check_kill, validNodeName) # get the node which not be killed for node in validNodeName: if (status[node] != DefaultValue.SUCCESS): failedNodes.append(node) # kill process in nodes again if (len(failedNodes)): time.sleep(1) (status, output) = self.sshTool.getSshStatusOutput( cmd_check_kill, failedNodes) for node in failedNodes: # if still fail, throw error if (status[node] != DefaultValue.SUCCESS): raise Exception(output) except Exception as e: raise Exception(str(e)) def CleanInstance(self): """ function: clean instance input : NA output : NA """ self.logger.debug("Deleting instance.", "addStep") # check if need delete instance if (not self.cleanInstance): self.logger.debug("No need to delete data.", "constant") return # Clean instance data cmd = "%s -U %s -l %s" % ( OMCommand.getLocalScript("Local_Clean_Instance"), self.user, self.localLog) self.logger.debug("Command for deleting instance: %s" % cmd) CmdExecutor.execCommandWithMode(cmd, self.sshTool, self.localMode, self.mpprcFile) # clean upgrade temp backup path upgrade_bak_dir = ClusterDir.getBackupDir("upgrade", self.user) cmd = g_file.SHELL_CMD_DICT["cleanDir"] % ( upgrade_bak_dir, upgrade_bak_dir, upgrade_bak_dir) CmdExecutor.execCommandWithMode(cmd, self.sshTool, self.localMode, self.mpprcFile) self.logger.log("Successfully deleted instances.", "constant") def CleanTmpFiles(self): """ function: clean temp files input : NA output: NA """ self.logger.debug("Deleting temporary files.", "addStep") try: # copy record_app_directory file tmpDir = EnvUtil.getTmpDirFromEnv(self.user) if tmpDir == "": raise Exception(ErrorCode.GAUSS_518["GAUSS_51800"] % "$PGHOST") upgradeBackupPath = os.path.join(tmpDir, "binary_upgrade") copyPath = os.path.join(upgradeBackupPath, "record_app_directory") appPath = ClusterDir.getInstallDir(self.user) if appPath == "": raise Exception(ErrorCode.GAUSS_518["GAUSS_51800"] % "$PGHOST") if copyPath != "": copyCmd = "(if [ -f '%s' ];then cp -f -p '%s' '%s/';fi)" % ( copyPath, copyPath, appPath) CmdExecutor.execCommandWithMode( copyCmd, self.sshTool, self.localMode, self.mpprcFile) cmd = g_file.SHELL_CMD_DICT["cleanDir"] % ( self.tmpDir, self.tmpDir, self.tmpDir) # clean dir of PGHOST CmdExecutor.execCommandWithMode(cmd, self.sshTool, self.localMode, self.mpprcFile) except Exception as e: self.logger.logExit(str(e)) self.logger.debug("Successfully deleted temporary files.", "constant") def UninstallApp(self): """ function: Uninstall application input : NA output: NA """ self.logger.log("Uninstalling application.", "addStep") cmd = "%s -R '%s' -U %s -l %s -T" % ( OMCommand.getLocalScript("Local_Uninstall"), self.clusterInfo.appPath, self.user, self.localLog) self.logger.debug("Command for Uninstalling: %s" % cmd) # clean application CmdExecutor.execCommandWithMode(cmd, self.sshTool, self.localMode, self.mpprcFile) self.logger.log("Successfully uninstalled application.", "constant") def CleanStaticConfFile(self): """ function: clean static conf file input : NA output: NA """ self.logger.debug("Deleting static configuration file.", "addStep") try: cmd = "rm -rf '%s'/bin " % self.clusterInfo.appPath # delete bin dir in GAUSSHOME CmdExecutor.execCommandWithMode( cmd, self.sshTool, self.localMode, self.mpprcFile) except Exception as e: self.logger.exitWithError(str(e)) self.logger.debug("Successfully deleted static configuration file.", "constant") def CleanRackFile(self): """ function: clean rack information file input : NA output: NA """ gp_home = EnvUtil.getEnv("GPHOME") if os.path.exists(gp_home): gp_home = os.path.realpath(gp_home) rack_conf_file = os.path.realpath( os.path.join(gp_home, "script/gspylib/etc/conf/rack_info.conf")) if os.path.isfile(rack_conf_file): cmd = "rm -f %s" % rack_conf_file CmdExecutor.execCommandWithMode(cmd, self.sshTool, self.localMode, mpprc_file=self.mpprcFile) self.logger.debug("Successfully deleted rack information file.") def clean_dss_home(self): """ function: Clean default log input : NA output: NA """ self.logger.debug("Deleting dss_home.", "addStep") # check if need delete instance if not self.cleanInstance: self.logger.debug("No need to delete data.", "constant") return try: # clean log dss_home = EnvUtil.getEnvironmentParameterValue("DSS_HOME", self.user) cmd = g_file.SHELL_CMD_DICT["cleanDir"] % ( dss_home, dss_home, dss_home) # delete log dir CmdExecutor.execCommandWithMode(cmd, self.sshTool, self.localMode, self.mpprcFile) except Exception as e: self.logger.exitWithError(str(e)) self.logger.debug("Successfully deleted log.", "constant") def CleanLog(self): """ function: Clean default log input : NA output: NA """ self.logger.debug("Deleting log.", "addStep") # check if need delete instance if (not self.cleanInstance): self.logger.debug("No need to delete data.", "constant") return try: # clean log userLogDir = ClusterDir.getUserLogDirWithUser(self.user) cmd = g_file.SHELL_CMD_DICT["cleanDir"] % ( userLogDir, userLogDir, userLogDir) # delete log dir CmdExecutor.execCommandWithMode(cmd, self.sshTool, self.localMode, self.mpprcFile) except Exception as e: self.logger.exitWithError(str(e)) self.logger.log("Successfully deleted log.", "constant") def checkEnv(self): """ function: check if GAUSS_ENV is 2 input : NA output: NA """ pass def ReCleanEtcdPath(self): """ function: make sure the etcd path is clean. input : NA output: NA """ pass def ReKillEtcdProcess(self): """ function: make sure the etcd process is clean. input : NA output: NA """ if (self.localMode): DefaultValue.KillAllProcess(self.user, "etcd") # kill process in all nodes else: etcd_file = "%s/bin/etcd" % self.clusterInfo.appPath self.CheckAndKillAliveProc(etcd_file) def check_drop_node(self): """ Check flag file of drop node """ flag_file = os.path.realpath(os.path.join(self.clusterInfo.appPath, "bin", "drop_node_flag")) if os.path.isfile(flag_file): self.logger.log("This is a node where the gs_dropnode command has been executed. " "Uninstall a single node instead of the gs_dropnode command.") self.localMode = True def check_dss(self): """ function: make sure the etcd process is clean. input : NA output: NA """ enable_dssLine = 'export ENABLE_DSS=ON\n' is_enabledssset = EnvUtil.getEnv("ENABLE_DSS") is_dsshome = EnvUtil.getEnv("DSS_HOME") if self.mpprcFile and os.path.isfile(self.mpprcFile): source_file = self.mpprcFile if is_dsshome and not is_enabledssset: with open(source_file, 'a') as file: file.write(enable_dssLine) def clear_dss_disk(self): """ function: clear dss disk if dss_mode enabled. input : NA output: NA """ if not self.clearDisk: self.logger.log("No need to clear dss disk.") return try: enabled_dss = EnvUtil.getEnv("DSS_HOME") if enabled_dss: disks = [] dss_vg_info = enabled_dss + os.sep + "cfg" + os.sep + "dss_vg_conf.ini" cm_vg_info = enabled_dss + os.sep + "cfg" + os.sep + "dss_cm_conf.ini" with open(dss_vg_info, 'r') as fr_dss: for dss_info in fr_dss.readlines(): disks.append(dss_info.split(':')[1].strip()) with open(cm_vg_info, 'r') as fr_cm: for cm_info in fr_cm.readlines(): disks.append(cm_info.strip()) for disk in list(map(os.path.realpath, disks)): subprocess.getstatusoutput("dd if=/dev/zero of=" + disk) self.logger.log("dd if=/dev/zero of=" + disk + "complete.") except Exception as e: self.logger.exitWithError(str(e)) self.logger.log("Successfully clear dss disk.") def run(self): """ function: Uninstall database cluster input : NA output: NA """ try: self.checkEnv() self.checkLogFilePath() self.check_drop_node() # do uninstall self.checkUninstall() self.StopCluster() self.CleanInstance() self.CleanTmpFiles() self.UninstallApp() self.ReCleanEtcdPath() self.ReKillEtcdProcess() self.logger.closeLog() self.CleanStaticConfFile() self.CleanRackFile() self.clear_dss_disk() self.clean_dss_home() self.CleanLog() self.check_dss() self.logger.log("Uninstallation succeeded.") except Exception as e: self.logger.logExit(str(e))