469 lines
18 KiB
Python
469 lines
18 KiB
Python
# -*- 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
|
|
|
|
|
|
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.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.debug("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 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.clean_dss_home()
|
|
self.CleanLog()
|
|
self.logger.log("Uninstallation succeeded.")
|
|
except Exception as e:
|
|
self.logger.logExit(str(e))
|