#!/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 : gs_postuninstall is a utility to clean up the environment # after uninstalling a Gauss200 server. ############################################################################# import os, sys import subprocess import grp import pwd package_path = os.path.dirname(os.path.realpath(__file__)) ld_path = package_path + "/gspylib/clib" if 'LD_LIBRARY_PATH' not in os.environ: os.environ['LD_LIBRARY_PATH'] = ld_path os.execve(os.path.realpath(__file__), sys.argv, os.environ) if not os.environ.get('LD_LIBRARY_PATH').startswith(ld_path): os.environ['LD_LIBRARY_PATH'] = \ ld_path + ":" + os.environ['LD_LIBRARY_PATH'] os.execve(os.path.realpath(__file__), sys.argv, os.environ) from gspylib.common.GaussLog import GaussLog from gspylib.common.Common import DefaultValue from gspylib.common.ErrorCode import ErrorCode from gspylib.common.ParallelBaseOM import ParallelBaseOM from gspylib.common.ParameterParsecheck import Parameter from impl.postuninstall.OLAP.PostUninstallImplOLAP import \ PostUninstallImplOLAP from domain_utils.cluster_file.cluster_config_file import ClusterConfigFile from domain_utils.cluster_file.cluster_dir import ClusterDir from domain_utils.cluster_file.cluster_log import ClusterLog from base_utils.os.env_util import EnvUtil from base_utils.os.net_util import NetUtil from domain_utils.domain_common.cluster_constants import ClusterConstants from os_platform.linux_distro import LinuxDistro from domain_utils.cluster_os.cluster_user import ClusterUser from domain_utils.cluster_file.profile_file import ProfileFile class Postuninstall(ParallelBaseOM): """ init the command options input : NA output: NA """ def __init__(self): """ function: init parameters input : NA output: NA """ ParallelBaseOM.__init__(self) self.deleteUser = False self.deleteGroup = False self.clean_gphome = False self.clean_host = [] self.sshpwd = "" self.nodeList = [] self.clusterToolPath = "" self.userHome = "" self.rootPasswd = "" self.ips = [] self.root_ssh_agent_flag = False self.gauss_om_path = "" def usage(self): """ gs_postuninstall is a utility to clean up the environment after uninstalling the cluster. Usage: gs_postuninstall -? |--help gs_postuninstall -V |--version gs_postuninstall -U USER -X XMLFILE [-L] [--delete-user] [--delete-group] [-l LOGFILE] General options: -U Cluster user. -X Path of the XML configuration file. -L Only clean up local nodes. --delete-user Delete the OS user. --delete-group Delete the group of the OS user. -l Path of log file. -?, --help Show help information for this utility, and exit the command line mode. -V, --version Show version information. """ print(self.usage.__doc__) def parseCommandLine(self): """ function: Parse command line and save to global variable input : NA output: NA """ ParaObj = Parameter() ParaDict = ParaObj.ParameterCommandLine("postuninstall") # check if has '--help' parameter if (ParaDict.__contains__("helpFlag")): self.usage() sys.exit(0) # check the parameters of postuninstall command if (ParaDict.__contains__("user")): self.user = ParaDict.get("user") if (ParaDict.__contains__("confFile")): self.xmlFile = ParaDict.get("confFile") if (ParaDict.__contains__("logFile")): self.logFile = ParaDict.get("logFile") if (ParaDict.__contains__("delete-user")): self.deleteUser = ParaDict.get("delete-user") if (ParaDict.__contains__("delete-group")): self.deleteGroup = ParaDict.get("delete-group") if (ParaDict.__contains__("clean-gphome")): self.clean_gphome = ParaDict.get("clean-gphome") if (ParaDict.__contains__("nodename")): if not "HOST_IP" in os.environ.keys(): GaussLog.exitWithError( ErrorCode.GAUSS_518["GAUSS_51801"] % "HOST_IP doesn't" + " so -h parameter is not needed.") self.clean_host = ParaDict.get("nodename") if len(self.clean_host) == 0: raise Exception(ErrorCode.GAUSS_500["GAUSS_50004"] % 'h') if (ParaDict.__contains__("localMode")): self.localMode = ParaDict.get("localMode") if "HOST_IP" in os.environ.keys(): if not ParaDict.__contains__("localMode"): if not (ParaDict.__contains__("clean-gphome") and ParaDict.__contains__("nodename")): GaussLog.exitWithError( ErrorCode.GAUSS_518["GAUSS_51801"] % "HOST_IP" + " so you must specify the -L parameter or (-h and " "--clean-gphome) parameters.") if ParaDict.__contains__("clean-gphome"): if ParaDict.__contains__("localMode") and\ ParaDict.__contains__("nodename"): GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50005"] % ("-L", "-h")) if (self.deleteGroup == True and self.deleteUser != True): GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % "-delete-user" + ".") def checkParameter(self): """ function: check parameter input : NA output: NA """ # check user self.checkUser() # check config file ClusterConfigFile.checkConfigFile(self.xmlFile) # check log file self.logFile = ClusterLog.checkLogFile(self.logFile, self.user, self.xmlFile, ClusterConstants.UNPREINSTALL_LOG_FILE) # check mpprc file if needed, should be done # before check preinstall step self.checkMpprcFile() # check preInstall self.checkPreInstall() # check group for redhat self.checkGroup() def checkUser(self): """ function: check the user input : NA output: NA """ # check if no user if (self.user == ""): GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % "U" + ".") # check if is root user if (self.user == "root"): GaussLog.exitWithError(ErrorCode.GAUSS_503["GAUSS_50301"]) try: ClusterUser.checkUser(self.user, False) except Exception as e: GaussLog.exitWithError(str(e)) if (pwd.getpwnam(self.user).pw_uid == 0): GaussLog.exitWithError(ErrorCode.GAUSS_503["GAUSS_50302"]) def checkMpprcFile(self): """ function: check MpprcFile input : NA output: NA """ # get path of MpprcFile self.mpprcFile = EnvUtil.getEnv(DefaultValue.MPPRC_FILE_ENV) try: # get tool path self.clusterToolPath = ClusterDir.getPreClusterToolPath(self.xmlFile) except Exception as e: GaussLog.exitWithError(str(e)) # if MpprcFile is null if (self.mpprcFile == None): self.mpprcFile = "" # if MpprcFile is not null if (self.mpprcFile != ""): # if no MpprcFile, It has no environment separation, the environment variables are in the.bashrc. if (not os.path.exists(self.mpprcFile)): GaussLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50201"] % "MPPRC file" + " %s." % self.mpprcFile) # if is not absolute path if (not os.path.isabs(self.mpprcFile)): GaussLog.exitWithError(ErrorCode.GAUSS_512["GAUSS_51206"] % self.mpprcFile) def checkPreInstall(self): """ function: check preInstall input : NA output: NA """ # check if agent-mode if "HOST_IP" in os.environ.keys(): # get om_agent path agent_path_cmd = "ps aux | grep 'om_agent.py' | grep %s | grep " \ "-v grep | head -n 1 | awk '{print $NF}'" % \ self.user (status, output) = subprocess.getstatusoutput(agent_path_cmd) if (status != 0): raise Exception(ErrorCode.GAUSS_535["GAUSS_53507"] % agent_path_cmd) agent_path = os.path.dirname(output.strip()) agent_conf_file = os.path.join(agent_path, 'om_agent.conf') if not os.path.exists(agent_conf_file): raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % agent_conf_file) # get agent sep_env_file with open(agent_conf_file) as fp: recordLines = fp.readlines() sep_env_file = "" for tmp in recordLines: if 'sep_env_file' in tmp: sep_env_file = tmp.split("=")[-1].strip() if not os.path.exists(sep_env_file): raise Exception( ErrorCode.GAUSS_502["GAUSS_50201"] % sep_env_file) cmd = "su - %s -c 'source %s && echo $GAUSS_ENV' 2>/dev/null"\ % (self.user, sep_env_file) (status, output) = subprocess.getstatusoutput(cmd) if (status != 0): GaussLog.exitWithError(ErrorCode.GAUSS_518["GAUSS_51802"] % "$GAUSS_ENV" + "Error: \n%s." % output + "The cmd is %s" % cmd) gaussEnv = output.strip() else: # check if has mpprcFile if (self.mpprcFile != "" and os.path.exists(self.mpprcFile)): userprofile = self.mpprcFile else: userprofile = ProfileFile.get_user_bashrc(self.user) cmd = "su - %s -c 'source %s && echo $GAUSS_ENV' 2>/dev/null"\ % (self.user, userprofile) (status, output) = subprocess.getstatusoutput(cmd) if (status != 0): GaussLog.exitWithError(ErrorCode.GAUSS_518["GAUSS_51802"] % "$GAUSS_ENV" + "Error: \n%s." % output + "The cmd is %s" % cmd) gaussEnv = output.strip() # if gaussEnv is 2, user do not do uninstall before if (str(gaussEnv) == "2"): GaussLog.exitWithError(ErrorCode.GAUSS_525["GAUSS_52501"] % "gs_uninstall") # if gaussEnv is not 1, user do not do preinstall before elif (str(gaussEnv) != "1" and not self.clean_gphome): GaussLog.exitWithError( ErrorCode.GAUSS_525["GAUSS_52501"] % "gs_preinstall" + "If you do preinstall with seperate file mode, please input " "sep-env-file before postuninstall. ") elif (str(gaussEnv) == "1" or str(gaussEnv) == "2")\ and self.clean_gphome: GaussLog.exitWithError(ErrorCode.GAUSS_525["GAUSS_52501"] % "'gs_uninstall' or 'gs_postuninstall" " no clean gphome'") def checkGroup(self): """ function: check user group input : NA output: NA """ try: # get user group group = grp.getgrgid(pwd.getpwnam(self.user).pw_gid).gr_name distname, version, idnum = LinuxDistro.linux_distribution() # check if OS version is redhat or Euler if (distname in ("redhat", "euleros", "centos", "openEuler", "FusionOS", "H3Linux", "NingOS")): if (self.deleteGroup != True and self.deleteUser == True and self.user == group): GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % "-delete-group" + ". You must " "delete the " "group when you " "delete the " "user which has " "the same name " "with the group " "in redhat.") except Exception as e: GaussLog.exitWithError(ErrorCode.GAUSS_503["GAUSS_50308"] + "Failed to obtain the group for %s" % self.user + "Error:\n%s" % str(e)) def initGlobals(self): """ function: init Logg file input : NA output: NA """ self.initLogger("gs_postuninstall") self.logger.ignoreErr = True try: self.logger.log("Parsing the configuration file.", "addStep") # get cluster info from xml file # Initialize the self.clusterInfo variable self.initClusterInfo() os.environ[ClusterConstants.TOOL_PATH_ENV] = self.clusterToolPath # Initialize the self.sshTool variable self.initSshTool(self.clusterInfo.getClusterNodeNames(), DefaultValue.TIMEOUT_PSSH_POSTPREINSTALL) self.logger.debug("The cluster's information:\n%s." % str(self.clusterInfo)) self.logger.log("Successfully parsed the configuration file.", "constant") except Exception as e: self.logger.logExit(str(e)) dirName = os.path.dirname(self.logFile) self.localLog = os.path.join(dirName, ClusterConstants.LOCAL_LOG_FILE) self.userHome = DefaultValue.getUserHome(self.user) self.gauss_om_path = "/home/%s/gauss_om" % self.user if __name__ == '__main__': """ main function input : NA output: NA """ if (os.getuid() != 0): GaussLog.exitWithError(ErrorCode.GAUSS_501["GAUSS_50104"]) try: postuninstall = Postuninstall() postuninstall.parseCommandLine() postuninstall.checkParameter() postuninstall.initGlobals() if len(postuninstall.clusterInfo.getClusterNodeNames()) == 1 and \ postuninstall.clusterInfo.getClusterNodeNames()[ 0] == NetUtil.GetHostIpOrName(): postuninstall.localMode = True impl = PostUninstallImplOLAP(postuninstall) # Perform the whole extand process impl.run() except Exception as e: GaussLog.exitWithError(str(e))