370 lines
14 KiB
Python
370 lines
14 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 : Uninstall.py is a utility to uninstall Gauss MPP Database.
|
|
#############################################################################
|
|
|
|
import getopt
|
|
import os
|
|
import sys
|
|
import re
|
|
|
|
sys.path.append(sys.path[0] + "/../")
|
|
from gspylib.common.GaussLog import GaussLog
|
|
from gspylib.common.ParameterParsecheck import Parameter
|
|
from gspylib.common.ErrorCode import ErrorCode
|
|
from gspylib.common.LocalBaseOM import LocalBaseOM
|
|
from domain_utils.cluster_file.cluster_dir import ClusterDir
|
|
from domain_utils.cluster_file.cluster_log import ClusterLog
|
|
from base_utils.os.crontab_util import CrontabUtil
|
|
from base_utils.os.env_util import EnvUtil
|
|
from base_utils.os.file_util import FileUtil
|
|
from domain_utils.cluster_file.profile_file import ProfileFile
|
|
from base_utils.os.process_util import ProcessUtil
|
|
from domain_utils.domain_common.cluster_constants import ClusterConstants
|
|
|
|
|
|
class Uninstall(LocalBaseOM):
|
|
"""
|
|
uninstall the cluster
|
|
"""
|
|
|
|
def __init__(self):
|
|
"""
|
|
Constructor
|
|
"""
|
|
super(Uninstall, self).__init__()
|
|
self.installPath = ""
|
|
self.user = ""
|
|
self.keepDir = False
|
|
self.mpprcFile = ""
|
|
self.logFile = ""
|
|
self.logger = None
|
|
self.installflag = False
|
|
self.clusterInfo = None
|
|
self.localNode = None
|
|
self.keepData = True
|
|
self.method = ""
|
|
self.action = ""
|
|
|
|
##########################################################################
|
|
# Help context. U:R:oC:v:
|
|
##########################################################################
|
|
def usage(self):
|
|
"""
|
|
function: usage
|
|
"""
|
|
print("Uninstall.py is a utility to uninstall Gauss MPP Database.")
|
|
print(" ")
|
|
print("Usage:")
|
|
print(" python3 Uninstall.py --help")
|
|
print(" python3 Uninstall.py -U user -R installpath [-c] [-l log]")
|
|
print(" ")
|
|
print("Common options:")
|
|
print(" -U the database program and cluster owner")
|
|
print(" -R the database program install path")
|
|
print(" -l the log path")
|
|
print(" --help show this help, then exit")
|
|
print(" ")
|
|
|
|
##########################################################################
|
|
# This is the main uninstall flow.
|
|
##########################################################################
|
|
def uninstall(self):
|
|
"""
|
|
function: Remove install path content, which depend on $GAUSSHOME
|
|
input : NA
|
|
output: NA
|
|
"""
|
|
try:
|
|
self.logger.debug("OLAP's local uninstall.")
|
|
self.__cleanMonitor()
|
|
self.__cleanInstallProgram()
|
|
self.__changeuserEnv()
|
|
self.logger.closeLog()
|
|
except Exception as e:
|
|
raise Exception(str(e))
|
|
|
|
def __changeuserEnv(self):
|
|
"""
|
|
function: Change user GAUSS_ENV
|
|
input : NA
|
|
output: NA
|
|
"""
|
|
# clean os user environment variable
|
|
self.logger.log("Modifying user's environmental variable $GAUSS_ENV.")
|
|
userProfile = self.mpprcFile
|
|
ProfileFile.updateUserEnvVariable(userProfile, "GAUSS_ENV", "1")
|
|
if "HOST_IP" in os.environ.keys():
|
|
FileUtil.deleteLine(userProfile, "^\\s*export\\s*WHITELIST_ENV=.*$")
|
|
self.logger.log("Successfully modified user's environmental"
|
|
" variable GAUSS_ENV.")
|
|
|
|
self.logger.debug("Deleting symbolic link to $GAUSSHOME if exists.")
|
|
gaussHome = ClusterDir.getInstallDir(self.user)
|
|
if gaussHome == "":
|
|
raise Exception(ErrorCode.GAUSS_518["GAUSS_51800"] % "$GAUSSHOME")
|
|
if os.path.islink(gaussHome):
|
|
self.installPath = os.path.realpath(gaussHome)
|
|
os.remove(gaussHome)
|
|
else:
|
|
self.logger.debug("symbolic link does not exists.")
|
|
self.logger.debug("Deleting bin file in installation path.")
|
|
FileUtil.removeDirectory("%s/bin" % self.installPath)
|
|
self.logger.debug("Successfully deleting bin file in"
|
|
" installation path.")
|
|
|
|
def __cleanMonitor(self):
|
|
"""
|
|
function: clean om_monitor process and delete cron
|
|
input : NA
|
|
output: NA
|
|
"""
|
|
self.logger.log("Deleting monitor.")
|
|
try:
|
|
# get all content by crontab command
|
|
(status, output) = CrontabUtil.getAllCrontab()
|
|
# overwrit crontabFile, make it empty.
|
|
crontabFile = "%s/gauss_crontab_file_%d" \
|
|
% (EnvUtil.getTmpDirFromEnv(), os.getpid())
|
|
FileUtil.createFile(crontabFile, True)
|
|
content_CronTabFile = [output]
|
|
FileUtil.writeFile(crontabFile, content_CronTabFile)
|
|
FileUtil.deleteLine(crontabFile, "\/bin\/om_monitor")
|
|
CrontabUtil.execCrontab(crontabFile)
|
|
FileUtil.removeFile(crontabFile)
|
|
|
|
# clean om_monitor,cm_agent,cm_server process
|
|
for progname in ["om_monitor", "cm_agent", "cm_server"]:
|
|
ProcessUtil.killallProcess(self.user, progname, '9')
|
|
except Exception as e:
|
|
if os.path.exists(crontabFile):
|
|
FileUtil.removeFile(crontabFile)
|
|
raise Exception(str(e))
|
|
self.logger.log("Successfully deleted OMMonitor.")
|
|
|
|
def checkParameters(self):
|
|
"""
|
|
function: Check input parameters
|
|
input : NA
|
|
output: NA
|
|
"""
|
|
try:
|
|
opts, args = getopt.getopt(sys.argv[1:], "t:U:R:l:X:M:T",
|
|
["help", "delete-data"])
|
|
except getopt.GetoptError as e:
|
|
GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50000"]
|
|
% str(e))
|
|
|
|
if (len(args) > 0):
|
|
GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50000"]
|
|
% str(args[0]))
|
|
|
|
for key, value in opts:
|
|
if (key == "-U"):
|
|
self.user = value
|
|
elif (key == "-R"):
|
|
self.installPath = value
|
|
elif (key == "-l"):
|
|
self.logFile = value
|
|
elif (key == "--help"):
|
|
self.usage()
|
|
sys.exit(0)
|
|
elif (key == "-T"):
|
|
self.installflag = True
|
|
elif key == "--delete-data":
|
|
self.keepData = False
|
|
elif key == "-M":
|
|
self.method = value
|
|
elif key == "-t":
|
|
self.action = value
|
|
else:
|
|
GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50000"]
|
|
% key)
|
|
|
|
Parameter.checkParaVaild(key, value)
|
|
|
|
if (self.user == ""):
|
|
GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"]
|
|
% 'U' + ".")
|
|
|
|
if (self.installPath == ""):
|
|
GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"]
|
|
% 'R' + ".")
|
|
|
|
self.mpprcFile = EnvUtil.getMpprcFile()
|
|
if (self.logFile == ""):
|
|
self.logFile = ClusterLog.getOMLogPath(
|
|
ClusterConstants.LOCAL_LOG_FILE, self.user, self.installPath)
|
|
|
|
def __initLogger(self):
|
|
"""
|
|
function: Init logger
|
|
input : NA
|
|
output: NA
|
|
"""
|
|
self.logger = GaussLog(self.logFile, "UninstallApp")
|
|
|
|
def _check_and_remove(self):
|
|
"""
|
|
Check app directory after clean app
|
|
"""
|
|
file_list = os.listdir(self.installPath)
|
|
if not file_list:
|
|
return
|
|
for base_name in file_list:
|
|
special_file = os.path.join(self.installPath, base_name)
|
|
if os.path.exists(special_file) and not os.path.isdir(special_file):
|
|
os.remove(special_file)
|
|
self.logger.log("Successfully cleaned {0} .".format(special_file))
|
|
self.logger.log("Check and clean finish.")
|
|
|
|
def __cleanInstallProgram(self):
|
|
"""
|
|
function: Clean install program
|
|
input : NA
|
|
output: NA
|
|
"""
|
|
if (not os.path.exists(self.installPath)):
|
|
self.logger.log("The installation directory does not exist. ")
|
|
return
|
|
|
|
realLink = self.installPath
|
|
if os.path.islink(self.installPath):
|
|
realLink = os.readlink(self.installPath)
|
|
|
|
# delete upgrade directory
|
|
self.logger.debug("Starting delete other installation directory.")
|
|
try:
|
|
recordVersionFile = os.path.realpath(
|
|
os.path.join(self.installPath, "record_app_directory"))
|
|
if os.path.isfile(recordVersionFile):
|
|
with open(recordVersionFile, 'r') as fp:
|
|
retLines = fp.readlines()
|
|
if len(retLines) != 2:
|
|
raise Exception(ErrorCode.GAUSS_502["GAUSS_50222"]
|
|
% recordVersionFile)
|
|
oldPath = retLines[0].strip()
|
|
newPath = retLines[1].strip()
|
|
if os.path.normcase(oldPath) == os.path.normcase(realLink):
|
|
FileUtil.removeDirectory(newPath)
|
|
else:
|
|
FileUtil.removeDirectory(oldPath)
|
|
self.logger.debug("Successfully deleted other installation"
|
|
" path need to delete.")
|
|
else:
|
|
self.logger.debug("No other installation path need"
|
|
" to delete.")
|
|
except Exception as e:
|
|
raise Exception(ErrorCode.GAUSS_502["GAUSS_50209"]
|
|
% "other installation"
|
|
+ " Can not delete other installation"
|
|
" directory: %s." % str(e))
|
|
|
|
self.logger.log("Removing the installation directory.")
|
|
try:
|
|
fileList = os.listdir(self.installPath)
|
|
for fileName in fileList:
|
|
fileName = fileName.replace("/", "").replace("..", "")
|
|
filePath = os.path.join(os.path.realpath(self.installPath),
|
|
fileName)
|
|
if os.path.isfile(filePath):
|
|
os.remove(filePath)
|
|
elif os.path.isdir(filePath):
|
|
if (fileName == "bin"):
|
|
binFileList = os.listdir(filePath)
|
|
for binFile in binFileList:
|
|
fileInBinPath = os.path.join(filePath, binFile)
|
|
if os.path.isfile(fileInBinPath) and \
|
|
binFile != "cluster_static_config":
|
|
os.remove(fileInBinPath)
|
|
elif os.path.islink(fileInBinPath):
|
|
os.remove(fileInBinPath)
|
|
elif os.path.isdir(fileInBinPath):
|
|
FileUtil.removeDirectory(fileInBinPath)
|
|
else:
|
|
FileUtil.removeDirectory(filePath)
|
|
|
|
self.logger.debug("Remove path:%s." % filePath)
|
|
self._check_and_remove()
|
|
self.logger.debug("Successfully deleted bin file"
|
|
" in installation path.")
|
|
|
|
except Exception as e:
|
|
raise Exception(ErrorCode.GAUSS_502["GAUSS_50209"]
|
|
% "installation"
|
|
+ " Can not delete installation directory: %s."
|
|
% str(e))
|
|
|
|
# regular match delete empty directory
|
|
self.logger.debug("Starting delete empty installation directory.")
|
|
try:
|
|
removeflag = False
|
|
namePrefix = os.path.basename(self.installPath)
|
|
gaussPath = os.path.realpath(os.path.dirname(self.installPath))
|
|
curInstallName = os.path.basename(realLink)
|
|
fileList = os.listdir(gaussPath)
|
|
for fileName in fileList:
|
|
if fileName.strip() != curInstallName.strip():
|
|
filePath = os.path.join(os.path.realpath(gaussPath),
|
|
fileName)
|
|
if os.path.isdir(filePath) \
|
|
and not os.listdir(filePath) and "_" in fileName:
|
|
fileNameElement = fileName.split("_", 1)
|
|
if namePrefix.strip() == fileNameElement[0].strip():
|
|
res = re.search(
|
|
'^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8}$',
|
|
fileNameElement[1].strip())
|
|
if res:
|
|
removeflag = True
|
|
FileUtil.removeDirectory(filePath)
|
|
if removeflag:
|
|
self.logger.debug("Successfully deleted empty"
|
|
" installation path.")
|
|
else:
|
|
self.logger.debug("No empty installation path need"
|
|
" to delete.")
|
|
except Exception as e:
|
|
raise Exception(ErrorCode.GAUSS_502["GAUSS_50209"]
|
|
% "other installation"
|
|
+ " Can not delete empty installation"
|
|
" directory: %s." % str(e))
|
|
|
|
self.logger.log("Successfully deleted installation directory.")
|
|
|
|
def init(self):
|
|
"""
|
|
function: constuctor
|
|
"""
|
|
self.__initLogger()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
"""
|
|
main function
|
|
"""
|
|
try:
|
|
uninstaller = Uninstall()
|
|
uninstaller.checkParameters()
|
|
uninstaller.init()
|
|
uninstaller.uninstall()
|
|
except Exception as e:
|
|
GaussLog.exitWithError(str(e))
|
|
|
|
sys.exit(0)
|