# -*- 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 os
import sys
import subprocess
import grp
import pwd
import getpass

from base_utils.os.user_util import UserUtil

sys.path.append(sys.path[0] + "/../")
from gspylib.threads.parallelTool import parallelTool
from gspylib.common.Common import DefaultValue, ClusterCommand
from gspylib.common.OMCommand import OMCommand
from gspylib.common.ErrorCode import ErrorCode
import impl.upgrade.UpgradeConst as Const
from base_utils.executor.cmd_executor import CmdExecutor
from domain_utils.cluster_file.cluster_config_file import ClusterConfigFile
from domain_utils.cluster_file.cluster_dir import ClusterDir
from base_utils.os.file_util import FileUtil
from domain_utils.cluster_file.profile_file import ProfileFile
from domain_utils.cluster_file.version_info import VersionInfo
from base_utils.os.net_util import NetUtil
from base_utils.os.env_util import EnvUtil
from domain_utils.domain_common.cluster_constants import ClusterConstants
from os_platform.linux_distro import LinuxDistro

sys.path.append(sys.path[0] + "/../../../lib/")
DefaultValue.doConfigForParamiko()
import paramiko

#############################################################################
# Global variables
#############################################################################
gphome = None
# system config file
PROFILE_FILE = '/etc/profile'
# pssh directory name
PSSHDIR = 'pssh-2.3.1'
# action name
ACTION_CLEAN_TOOL_ENV = "clean_tool_env"
ACTION_CHECK_UNPREINSTALL = "check_unpreinstall"
ACTION_CLEAN_GAUSS_ENV = "clean_gauss_env"
ACTION_DELETE_GROUP = "delete_group"
ACTION_CLEAN_SYSLOG_CONFIG = 'clean_syslog_config'
ACTION_CLEAN_DEPENDENCY = "clean_dependency"
ACTION_DELETE_CGROUP = "delete_cgroup"

class PostUninstallImpl:
    """
    init the command options
    input : NA
    output: NA
    """

    def __init__(self, GaussPost):
        """
        function: constructor
        """
        pass

    def checkLogFilePath(self):
        """
        function: Check log file path
        input : NA
        output: NA
        """
        clusterPath = []

        try:
            self.logger.log("Check log file path.", "addStep")
            # get tool path
            clusterPath.append(ClusterDir.getClusterToolPath(self.user))

            # get tmp path
            tmpDir = DefaultValue.getTmpDir(self.user, self.xmlFile)
            clusterPath.append(tmpDir)

            # get cluster  path
            hostName = NetUtil.GetHostIpOrName()
            dirs = self.clusterInfo.getClusterDirectorys(hostName, False)
            for checkdir in dirs.values():
                clusterPath.extend(checkdir)

            self.logger.debug("Cluster paths %s." % clusterPath)
            # check directory
            FileUtil.checkIsInDirectory(self.logFile, clusterPath)
            self.logger.log("Successfully checked log file path.", "constant")
        except Exception as e:
            self.logger.logExit(str(e))

    ##########################################################################
    # Uninstall functions
    ##########################################################################
    def doCleanEnvironment(self):
        """
        function: Clean Environment
        input : NA
        output: NA
        """
        self.logger.debug("Do clean Environment.", "addStep")
        try:
            # check uninstall
            self.checkUnPreInstall()
            # clean cgroup
            self.clean_cgroup()
            # clean app/log/data/temp dirs
            self.cleanDirectory()
            # clean other user
            self.cleanRemoteOsUser()
            # clean other nodes log
            self.cleanOtherNodesLog()
            # clean other nodes environment software and variable
            self.cleanOtherNodesEnvSoftware()
            # clean local node environment software and variable
            self.cleanLocalNodeEnvSoftware()
            # clean local user
            self.cleanLocalOsUser()
        except Exception as e:
            self.logger.logExit(str(e))
        self.logger.debug("Do clean Environment succeeded.", "constant")

    def setOrCleanGphomeEnv(self, setGphomeenv=True):
        osProfile = ClusterConstants.ETC_PROFILE
        if setGphomeenv:
            GphomePath = ClusterDir.getPreClusterToolPath(self.xmlFile)
            # set GPHOME
            FileUtil.writeFile(osProfile, ["export GPHOME=%s" % GphomePath])
        else:
            FileUtil.deleteLine(osProfile, "^\\s*export\\s*GPHOME=.*$")
            FileUtil.deleteLine(osProfile, "^\\s*export\\s*UNPACKPATH=.*$")
            self.logger.debug(
                "Deleting crash GPHOME in user environment variables.")

    def checkUnPreInstall(self):
        """
        function: check whether do uninstall before unpreinstall
        input : NA
        output: NA
        """
        self.logger.log("Checking unpreinstallation.")
        if not self.localMode:
            ProfileFile.checkAllNodesMpprcFile(
                self.clusterInfo.getClusterNodeNames(), self.mpprcFile)

        cmd = "%s -t %s -u %s -l '%s' -X '%s'" % (
            OMCommand.getLocalScript("Local_UnPreInstall"),
            ACTION_CHECK_UNPREINSTALL,
            self.user,
            self.localLog,
            self.xmlFile)
        self.logger.debug("Command for checking unpreinstall: %s" % cmd)
        # check if do postuninstall in all nodes
        CmdExecutor.execCommandWithMode(cmd,
                                        self.sshTool, self.localMode,
                                        self.mpprcFile)
        self.logger.log("Successfully checked unpreinstallation.")

    def clean_cgroup(self):
        """
        function: clean cgroup
        input : NA
        output: NA
        """
        self.logger.log("check and clean cgroup")
        cmd = "%s -t %s -u %s -l '%s' -X '%s'" % (
            OMCommand.getLocalScript("Local_UnPreInstall"),
            ACTION_DELETE_CGROUP,
            self.user,
            self.localLog,
            self.xmlFile)
        self.logger.debug("Command for clean cgroup: %s" % cmd)
        # check if do postuninstall in all nodes
        CmdExecutor.execCommandWithMode(cmd,
                                        self.sshTool, self.localMode,
                                        self.mpprcFile)
        self.logger.log("Successfully clean cgroup.")

    def cleanDirectory(self):
        """
        function: clean install/instance/temp dirs
        input : NA
        output: NA
        """
        # clean instance path
        hostName = NetUtil.GetHostIpOrName()
        dbNodeInfo = self.clusterInfo.getDbNodeByName(hostName)
        instanceDirs = []
        # get DB instance
        for dbInst in dbNodeInfo.datanodes:
            instanceDirs.append(dbInst.datadir)
            if (len(dbInst.ssdDir) != 0):
                instanceDirs.append(dbInst.ssdDir)
        # clean all instances
        if (len(instanceDirs) > 0):
            if (os.path.exists(instanceDirs[0]) and len(
                    os.listdir(instanceDirs[0])) == 0):
                self.CleanInstanceDir()
            else:
                self.logger.debug(
                    "Instance directory [%s] is not empty. "
                    "Skip to delete instance's directory." %
                    instanceDirs[0])
        else:
            self.logger.debug(
                "Instance's directory is not been found. "
                "Skip to delete instance's directory.")

        # clean install path
        if (os.path.exists(self.clusterInfo.appPath)):
            self.logger.log("Deleting the installation directory.")
            cmd = "rm -rf '%s'" % self.clusterInfo.appPath
            self.logger.debug(
                "Command for deleting the installation path: %s" % cmd)
            CmdExecutor.execCommandWithMode(cmd,
                                            self.sshTool, self.localMode,
                                            self.mpprcFile)
            self.logger.log("Successfully deleted the installation directory.")

        # clean tmp dir
        self.logger.log("Deleting the temporary directory.")
        tmpDir = DefaultValue.getTmpDir(self.user, self.xmlFile)
        cmd = "rm -rf '%s'; rm -rf /tmp/gs_checkos; rm -rf /tmp/gs_virtualip" \
              % tmpDir
        self.logger.debug(
            "Command for deleting the temporary directory: %s" % cmd)
        CmdExecutor.execCommandWithMode(cmd,
                                        self.sshTool, self.localMode,
                                        self.mpprcFile)
        self.logger.log("Successfully deleted the temporary directory.")

        path = '/etc/udev/rules.d/zz-dss_{}.rules'.format(self.user)
        if self.clusterInfo.enable_dss == 'on' or os.path.isfile(path):
            self.logger.log("Deleting the udev rule file.")
            cmd = "if [ -f '{0}' ]; then rm -rf '{0}'; fi;".format(path)
            self.logger.debug("Command for deleting the udev rule file: %s" % cmd)
            CmdExecutor.execCommandWithMode(cmd, self.sshTool, self.localMode,
                                            self.mpprcFile)
            self.logger.log("Successfully deleted the udev rule file.")

    def CleanInstanceDir(self):
        """
        function: Clean instance directory
        input : NA
        output: NA
        """
        self.logger.log("Deleting the instance's directory.")
        cmd = "%s -U %s -l '%s' -X '%s'" % (
            OMCommand.getLocalScript("Local_Clean_Instance"), self.user,
            self.localLog, self.xmlFile)
        self.logger.debug("Command for deleting the instance: %s" % cmd)
        CmdExecutor.execCommandWithMode(cmd,
                                        self.sshTool, self.localMode,
                                        self.mpprcFile)

        # clean upgrade temp backup path
        cmd = "rm -rf '%s'" % ClusterDir.getBackupDir("upgrade", self.user)
        self.logger.debug(
            "Command for deleting the upgrade temp backup path: %s" % cmd)
        CmdExecutor.execCommandWithMode(cmd,
                                        self.sshTool, self.localMode,
                                        self.mpprcFile)

        self.logger.log("Successfully deleted the instance's directory.")

    def cleanRemoteOsUser(self):
        """
        function: Clean remote os user
        input : NA
        output: NA
        """
        # check if local mode
        if (self.localMode):
            return

        if (not self.deleteUser):
            # clean static config file
            if os.stat(os.path.dirname(self.clusterInfo.appPath)).st_uid != 0:
                cmd = "rm -rf '%s'" % self.clusterInfo.appPath
                CmdExecutor.execCommandWithMode(cmd,
                                            self.sshTool, self.localMode,
                                            self.mpprcFile)
            return

        group = grp.getgrgid(pwd.getpwnam(self.user).pw_gid).gr_name

        # get other nodes
        hostName = NetUtil.GetHostIpOrName()
        otherNodes = self.clusterInfo.getClusterNodeNames()
        for otherNode in otherNodes:
            if (otherNode == hostName):
                otherNodes.remove(otherNode)

        # clean remote user
        self.logger.log("Deleting remote OS user.")
        cmd = "%s -U %s -l %s" % (
            OMCommand.getLocalScript("Local_Clean_OsUser"), self.user,
            self.localLog)
        self.logger.debug("Command for deleting remote OS user: %s" % cmd)
        CmdExecutor.execCommandWithMode(cmd, self.sshTool,
                                        self.localMode, self.mpprcFile,
                                        otherNodes)
        self.logger.log("Successfully deleted remote OS user.")

        if (self.deleteGroup):
            # clean remote group
            self.logger.debug("Deleting remote OS group.")
            cmd = "%s -t %s -u %s -l '%s' -X '%s'" % (
                OMCommand.getLocalScript("Local_UnPreInstall"),
                ACTION_DELETE_GROUP, group, self.localLog, self.xmlFile)
            self.logger.debug("Command for deleting remote OS group: %s" % cmd)
            status = self.sshTool.getSshStatusOutput(cmd, otherNodes,
                                                               self.mpprcFile)[0]
            outputMap = self.sshTool.parseSshOutput(otherNodes)
            for node in status.keys():
                if (status[node] != DefaultValue.SUCCESS):
                    self.logger.log((outputMap[node]).strip("\n"))
            self.logger.debug("Deleting remote group is completed.")

    def cleanOtherNodesEnvSoftware(self):
        """
        function: clean other nodes environment software and variable
        input : NA
        output: NA
        """
        # check if local mode
        if self.localMode:
            return
        self.logger.log(
            "Deleting software packages "
            "and environmental variables of other nodes.")
        try:
            # get other nodes
            hostName = NetUtil.GetHostIpOrName()
            otherNodes = self.clusterInfo.getClusterNodeNames()
            for otherNode in otherNodes:
                if (otherNode == hostName):
                    otherNodes.remove(otherNode)
            self.logger.debug(
                "Deleting environmental variables of nodes: %s." % otherNodes)

            # clean $GAUSS_ENV
            if (not self.deleteUser):
                cmd = "%s -t %s -u %s -l '%s' -X '%s'" % (
                    OMCommand.getLocalScript("Local_UnPreInstall"),
                    ACTION_CLEAN_GAUSS_ENV,
                    self.user,
                    self.localLog,
                    self.xmlFile)
                self.logger.debug("Command for deleting $GAUSS_ENV: %s" % cmd)
                CmdExecutor.execCommandWithMode(cmd,
                                                self.sshTool, self.localMode,
                                                self.mpprcFile, otherNodes)
            cmd = "%s -t %s -u %s -l '%s' -X '%s'" % (
                OMCommand.getLocalScript("Local_UnPreInstall"),
                ACTION_CLEAN_TOOL_ENV,
                self.user,
                self.localLog,
                self.xmlFile)
            self.logger.debug(
                "Command for deleting environmental variables: %s" % cmd)
            CmdExecutor.execCommandWithMode(cmd,
                                            self.sshTool,
                                            self.localMode,
                                            self.mpprcFile,
                                            otherNodes.append(hostName))
        except Exception as e:
            self.logger.logExit(str(e))
        self.logger.log(
            "Successfully deleted software packages "
            "and environmental variables of other nodes.")

    def cleanOtherNodesLog(self):
        """
        function: clean other nodes log
        input : NA
        output: NA
        """
        # check if local mode
        if self.localMode:
            return
        self.logger.log("Deleting logs of other nodes.")
        try:
            # get other nodes
            hostName = NetUtil.GetHostIpOrName()
            otherNodes = self.clusterInfo.getClusterNodeNames()
            for otherNode in otherNodes:
                if (otherNode == hostName):
                    otherNodes.remove(otherNode)

            # clean log
            if os.stat(ClusterDir.getClusterToolPath(self.user)).st_uid != 0 or \
                    os.stat(self.clusterInfo.logPath).st_uid != 0:
                cmd = "rm -rf '%s/%s'; rm -rf /tmp/gauss_*;" % (self.clusterInfo.logPath, self.user)
                python_path = "%s/Python-2.7.9" % ClusterDir.getClusterToolPath(self.user)
                if DefaultValue.non_root_owner(python_path):
                    cmd += "rm -rf '%s/Python-2.7.9'" % ClusterDir.getClusterToolPath(self.user)
                self.logger.debug("Command for deleting logs of other nodes: %s" % cmd)
                CmdExecutor.execCommandWithMode(cmd,
                                                self.sshTool,
                                                self.localMode,
                                                self.mpprcFile,
                                                otherNodes)
                self.logger.debug(
                    "Successfully deleted logs of the nodes: %s." % otherNodes)
        except Exception as e:
            self.logger.logExit(
                ErrorCode.GAUSS_502["GAUSS_50207"] % "other nodes log"
                + " Error: \n%s." % str(e))
        self.logger.log("Successfully deleted logs of other nodes.")

    def cleanOthernodesBackupScript(self):
        """
        function: clean othernodes gauss_om script
        """
        # check if local mode
        if self.localMode:
            return
        self.logger.log("Deleting gauss_om of other nodes.")
        try:
            # get other nodes
            hostName = NetUtil.GetHostIpOrName()
            otherNodes = self.clusterInfo.getClusterNodeNames()
            for otherNode in otherNodes:
                if (otherNode == hostName):
                    continue
                cmd = f"ssh root@%s 'rm -rf %s'" % (otherNode, self.gauss_om_path)
                (status, output) = subprocess.getstatusoutput(cmd)
                if status != 0:
                    self.logger.logExit(
                        ErrorCode.GAUSS_514["GAUSS_51400"] % cmd
                        + " Error:\n%s" % output)
                self.logger.debug(
                    "Successfully deleted gauss_om of the nodes: %s." % otherNodes)
        except Exception as e:
            self.logger.logExit(
                ErrorCode.GAUSS_502["GAUSS_50207"] % "other nodes gauss_om"
                + " Error: \n%s." % str(e))
        self.logger.log("Successfully deleted gauss_om of other nodes.")

    def cleanLocalNodeEnvSoftware(self):
        """
        function: clean local node environment software and variable
        input : NA
        output: NA
        in this function, Gauss-MPPDB* & sctp_patch is came from R5 upgrade R7
        """
        self.logger.log(
            "Deleting software packages "
            "and environmental variables of the local node.")
        try:
            self.clusterToolPath = ClusterDir.getClusterToolPath(self.user)

            # clean local node environment software
            path = "%s/%s" % (self.clusterToolPath, PSSHDIR)
            FileUtil.removeDirectory(path)
            path = "%s/upgrade.sh" % self.clusterToolPath
            FileUtil.removeFile(path)
            path = "%s/version.cfg" % self.clusterToolPath
            FileUtil.removeFile(path)
            path = "%s/GaussDB.py" % self.clusterToolPath
            FileUtil.removeFile(path)
            path = "%s/libcgroup" % self.clusterToolPath
            FileUtil.removeDirectory(path)
            path = "%s/unixodbc" % self.clusterToolPath
            FileUtil.removeDirectory(path)
            path = "%s/server.key.cipher" % self.clusterToolPath
            FileUtil.removeFile(path)
            path = "%s/server.key.rand" % self.clusterToolPath
            FileUtil.removeFile(path)
            path = "%s/%s*" % (self.clusterToolPath, VersionInfo.PRODUCT_NAME)
            FileUtil.removeDirectory(path)
            path = "%s/server.key.rand" % self.clusterToolPath
            FileUtil.removeFile(path)
            path = "%s/Gauss*" % (self.clusterToolPath)
            FileUtil.removeDirectory(path)
            path = "%s/sctp_patch" % (self.clusterToolPath)
            FileUtil.removeDirectory(path)
            path = "%s/%s" % (self.clusterToolPath, Const.UPGRADE_SQL_FILE)
            FileUtil.removeFile(path)
            path = "%s/%s" % (self.clusterToolPath, Const.UPGRADE_SQL_SHA)
            FileUtil.removeFile(path)
            self.logger.debug(
                "Deleting environmental software of local nodes.")

            hostName = NetUtil.GetHostIpOrName()
            node_info = self.clusterInfo.getDbNodeByName(hostName)
            datadir = node_info.datanodes[0].datadir
            datadir_escaped = datadir.replace("/", "\\/")
            basePort = node_info.datanodes[0].port
            userprofile = ProfileFile.get_user_bashrc(self.user)
            # clean local node environment variable
            cmd = "(if [ -s '%s' ]; then " % userprofile
            cmd += "sed -i -e '/^export PATH=\/home\/%s\/gauss_om\/" \
                   "script:\$PATH/d' %s " % (self.user, userprofile)
            cmd += "-e '/^export PATH=\$GPHOME\/script\/gspylib\/pssh\/bin:" \
                   "\$GPHOME\/script:\$PATH/d' %s " % PROFILE_FILE
            cmd += "-e '/^export LD_LIBRARY_PATH=\$GPHOME\/script\/gspylib\/clib:" \
                   "\$LD_LIBRARY_PATH$/d' %s " % userprofile
            cmd += "-e '/^export LD_LIBRARY_PATH=\$GPHOME\/lib:" \
                   "\$LD_LIBRARY_PATH$/d' %s " % userprofile
            cmd += "-e '/^export PGDATABASE=postgres/d' %s " % userprofile
            cmd += "-e '/^export PGPORT=%d/d' %s " % (basePort, userprofile)
            cmd += "-e '/^export UNPACKPATH=/d' %s " % userprofile
            cmd += "-e '/^export COREPATH=/d' %s " % userprofile
            cmd += "-e '/^export GPHOME=/d' %s " % userprofile
            cmd += "-e '/^export PGDATA=%s/d' %s " % (datadir_escaped, userprofile)
            cmd += "-e '/^export PYTHONPATH=\$GPHOME\/lib$/d' %s; fi) " % userprofile

            self.logger.debug(
                "Command for deleting environment variable: %s" % cmd)
            (status, output) = subprocess.getstatusoutput(cmd)
            if (status != 0):
                self.logger.logExit(ErrorCode.GAUSS_502["GAUSS_50207"] %
                                    "environment variables of the local node"
                                    + " Error: \n%s" % output)
            # check if user profile exist
            user_bashrc = ProfileFile.get_user_bashrc(self.user)
            if (self.mpprcFile is not None and self.mpprcFile != "" and os.path.exists(self.mpprcFile)):
                userProfile = self.mpprcFile
            else:
                userProfile = user_bashrc
            if (not os.path.exists(userProfile)):
                self.logger.debug(
                    "The %s does not exist. "
                    "Please skip to clean $GAUSS_ENV." % userProfile)
                return
            # clean user's environmental variable
            DefaultValue.cleanUserEnvVariable(userProfile,
                                              cleanGAUSS_WARNING_TYPE=True)
            if os.path.exists(user_bashrc):
                FileUtil.deleteLine(user_bashrc,
                                    "^\\s*export\\s*%s=.*$" % DefaultValue.MPPRC_FILE_ENV)

            # clean $GAUSS_ENV
            if (not self.deleteUser):
                envContent = "^\\s*export\\s*GAUSS_ENV=.*$"
                FileUtil.deleteLine(userProfile, envContent)
                self.logger.debug("Command for deleting $GAUSS_ENV: %s" % cmd,
                                  "constant")

        except Exception as e:
            self.logger.logExit(str(e))
        self.logger.log(
            "Successfully deleted software packages "
            "and environmental variables of the local nodes.")

    def cleanLocalOsUser(self):
        """
        function: Clean local os user
        input : NA
        output: NA
        """
        if (not self.deleteUser):
            if (self.localMode):
                if os.stat(os.path.dirname(self.clusterInfo.appPath)).st_uid != 0:
                    cmd = "rm -rf '%s'" % self.clusterInfo.appPath
                    CmdExecutor.execCommandWithMode(cmd,
                                                    self.sshTool, self.localMode,
                                                    self.mpprcFile)
            return

        group = grp.getgrgid(pwd.getpwnam(self.user).pw_gid).gr_name

        # clean local user
        self.logger.log("Deleting local OS user.")
        cmd = "%s -U %s -l %s" % (
            OMCommand.getLocalScript("Local_Clean_OsUser"), self.user,
            self.localLog)
        self.logger.debug("Command for deleting local OS user: %s" % cmd)
        (status, output) = subprocess.getstatusoutput(cmd)
        if (status != 0):
            self.logger.logExit(output)
        self.logger.log("Successfully deleted local OS user.")

        if (self.deleteGroup):
            # clean local user group
            self.logger.debug("Deleting local OS group.")
            cmd = "%s -t %s -u %s -l '%s' -X '%s'" % (
                OMCommand.getLocalScript("Local_UnPreInstall"),
                ACTION_DELETE_GROUP,
                group,
                self.localLog,
                self.xmlFile)
            self.logger.debug("Command for deleting local OS group: %s" % cmd)
            (status, output) = subprocess.getstatusoutput(cmd)
            if (status != 0):
                self.logger.log(output.strip())
            self.logger.debug("Deleting local group is completed.")

    def cleanLocalLog(self):
        """
        function: Clean default log
        input : NA
        output: NA
        """
        self.logger.log("Deleting local node's logs.", "addStep")
        try:
            # clean log
            path = "%s/%s" % (self.clusterInfo.logPath, self.user)
            FileUtil.removeDirectory(path)
        except Exception as e:
            self.logger.logExit(
                ErrorCode.GAUSS_502["GAUSS_50207"]
                % "logs" + " Error: \n%s." % str(e))
        self.logger.log("Successfully deleted local node's logs.", "constant")

    def cleanMpprcFile(self):
        """
        function: clean mpprc file if we are using environment seperate
        version.
        input : NA
        output: NA
        """
        self.logger.debug("Clean mpprc file.", "addStep")
        # check if mpprcfile is null
        if (self.mpprcFile != ""):
            try:
                UserUtil.check_user_exist(self.user)
                baseCmd = 'su - %s -c "rm -rf %s"' % (self.user, self.mpprcFile)
            except Exception as exp:
                self.logger.debug("Check user [%s] not exist. Error: %s" % (self.user, str(exp)))
                baseCmd = "if [ -f %s ]; then rm -rf %s; fi" % (self.mpprcFile, self.mpprcFile)
            # check if local mode
            if os.stat(self.mpprcFile).st_uid != 0:
                if (self.localMode):
                    (status, output) = subprocess.getstatusoutput(baseCmd)
                    if (status != 0):
                        self.logger.logExit(
                            ErrorCode.GAUSS_502["GAUSS_50207"]
                            % "MPPRC file"
                            + " Command: %s. Error: \n%s" % (baseCmd, output))
                else:
                    dbNodeNames = self.clusterInfo.getClusterNodeNames()
                    for dbNodeName in dbNodeNames:
                        cmd = "pssh -s -H %s '%s'" % (dbNodeName, baseCmd)
                        (status, output) = subprocess.getstatusoutput(cmd)
                        if (status != 0):
                            message = output.strip()
                            err_message = ErrorCode.GAUSS_502["GAUSS_50207"] % "MPPRC file" + \
                                          " Command: %s. Error: \n%s" % (cmd, output)
                            if "Permission denied" in message:
                                self.logger.debug(err_message)
                            else:
                                self.logger.logExit(err_message)
        self.logger.debug("Successfully cleaned mpprc file.", "constant")

    def cleanScript(self):
        """
        clean script directory
        """
        self.logger.debug("Clean script path")
        cmd = "%s -t %s -u %s -Q %s" % (
            OMCommand.getLocalScript("Local_UnPreInstall"),
            ACTION_CLEAN_DEPENDENCY, self.user,
            self.clusterToolPath)
        if self.deleteUser:
            cmd += " -P %s" % self.userHome
        CmdExecutor.execCommandWithMode(cmd,
                                        self.sshTool, self.localMode,
                                        self.mpprcFile)
        self.logger.debug("Clean script path successfully.")

    def cleanSyslogConfig(self):
        """
        function: clean syslog config
        input : NA
        output: NA
        """
        try:
            # only suse11/suse12 can support it
            distname = LinuxDistro.linux_distribution()[0]
            if (distname.upper() != "SUSE"):
                return

            # clean syslog-ng/rsyslog config
            cmd = "%s -t %s -u %s -l '%s' -X '%s'" % (
                OMCommand.getLocalScript("Local_UnPreInstall"),
                ACTION_CLEAN_SYSLOG_CONFIG,
                self.user,
                self.localLog,
                self.xmlFile)
            self.logger.debug(
                "Command for clean syslog-ng/rsyslog config: %s" % cmd)
            CmdExecutor.execCommandWithMode(
                cmd,
                self.sshTool,
                self.localMode,
                self.mpprcFile,
                self.clusterInfo.getClusterNodeNames())
        except Exception as e:
            self.logger.logExit(str(e))

    def sshExecWithPwd(self, host):
        """
        function: execute command with root password
        input : host
        output: NA
        """
        cmd = "if [ $(stat -c \"%s\" %s) == 0 ];then echo 'OKOKOK';" \
              "else rm -rf %s/* && echo 'OKOKOK';fi" % ("%u", gphome, gphome)
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(host, 22, "root", self.sshpwd)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        output = stdout.read()
        self.logger.debug("%s: %s" % (str(host), str(output)))
        if output.find('OKOKOK') < 0:
            raise Exception(
                ErrorCode.GAUSS_514["GAUSS_51400"]
                % cmd + "host: %s. Error:\n%s"
                % (host, output))

    def verifyCleanGphome(self, localMode=True):
        """
        function: verify clean gphome and get root password
        input : localMode
        output: str
        """
        sshpwd = ""
        flag = input(
            "Are you sure you want to clean gphome[%s] (yes/no)? " % gphome)
        while (True):
            if (
                    flag.upper() != "YES"
                    and flag.upper() != "NO"
                    and flag.upper() != "Y" and flag.upper() != "N"):
                flag = input("Please type 'yes' or 'no': ")
                continue
            break
        if (flag.upper() == "NO" or flag.upper() == "N"):
            sys.exit(0)
        if "HOST_IP" in os.environ.keys() and not localMode:
            sshpwd = getpass.getpass("Please enter password for root:")
            sshpwd_check = getpass.getpass("Please repeat password for root:")
            if sshpwd_check != sshpwd:
                sshpwd_check = ""
                sshpwd = ""
                raise Exception(ErrorCode.GAUSS_503["GAUSS_50306"] % "root")
            sshpwd_check = ""
        return sshpwd

    def checkAuthentication(self, hostname):
        """
        function: Ensure the proper password-less access to the remote host.
        input : hostname
        output: True/False, hostname
        """
        cmd = 'ssh -n %s %s true' % (DefaultValue.SSH_OPTION, hostname)
        (status, output) = subprocess.getstatusoutput(cmd)
        if (status != 0):
            self.logger.debug("The cmd is %s " % cmd)
            self.logger.debug(
                "Failed to check authentication. Hostname:%s. Error: \n%s" % (
                    hostname, output))
            return (False, hostname)
        return (True, hostname)

    def getItemValueFromXml(self, itemName):
        """
        function: Get item from xml tag CLUSTER.
        input : hostname
        output: True/False, hostname
        """
        (retStatus, retValue) = ClusterConfigFile.readOneClusterConfigItem(
            ClusterConfigFile.initParserXMLFile(self.xmlFile), itemName, "cluster")
        if (retStatus != 0):
            raise Exception(
                ErrorCode.GAUSS_502["GAUSS_50204"]
                % itemName + " Error: \n%s" % retValue)
        return retValue

    def cleanGphomeScript(self):
        """
        function: clean gphome script
        input : NA
        output: NA
        """
        try:
            if not self.clean_gphome:
                return
            global gphome
            gphome = os.path.normpath(
                self.getItemValueFromXml("gaussdbToolPath"))
            cmd = "rm -rf %s/*" % gphome
            if "HOST_IP" in os.environ.keys():
                # Agent Mode
                if self.localMode:
                    # clean gphome in local mode
                    self.verifyCleanGphome()
                    (status, output) = subprocess.getstatusoutput(cmd)
                    if status != 0:
                        raise Exception(
                            ErrorCode.GAUSS_514["GAUSS_51400"]
                            % cmd + " Error:\n%s" % output)
                    self.logger.logExit("Successfully clean gphome locally.")
                else:
                    # clean gphome with specified node
                    self.sshpwd = self.verifyCleanGphome(self.localMode)
                    parallelTool.parallelExecute(self.sshExecWithPwd,
                                                 self.clean_host)
                    self.logger.logExit(
                        "Successfully clean gphome on node %s."
                        % self.clean_host)

            else:
                # SSH Mode
                SSH_TRUST = True
                self.nodeList = self.getItemValueFromXml("nodeNames").split(
                    ",")
                if len(self.nodeList) == 0:
                    raise Exception(
                        ErrorCode.GAUSS_502["GAUSS_50203"] % "nodeList")
                results = parallelTool.parallelExecute(
                    self.checkAuthentication, self.nodeList)
                for (key, value) in results:
                    if (not key):
                        self.logger.log("SSH trust has not been created. \
                        \nFor node : %s. Only clean local node." % value,
                                        "constant")
                        SSH_TRUST = False
                        break
                if SSH_TRUST and not self.localMode:
                    # SSH trust has been created
                    self.verifyCleanGphome()
                    parallelTool.parallelExecute(self.sshExecWithPwd,
                                                 self.nodeList)
                if not SSH_TRUST or self.localMode:
                    # SSH trust has not been created
                    # which means clean gphome locally
                    self.verifyCleanGphome()
                    if os.stat(gphome).st_uid != 0:
                        (status, output) = subprocess.getstatusoutput(cmd)
                        if status != 0:
                            raise Exception(
                                ErrorCode.GAUSS_514["GAUSS_51400"]
                                % cmd + " Error:\n%s" % output)
                self.logger.logExit("Successfully clean gphome.")

        except Exception as e:
            self.logger.logExit(str(e))

    def createTrustForRoot(self):
        """
        :return:
        """
        if self.localMode or self.isSingle:
            return
        try:
            # save the sshIps
            Ips = []
            # create trust for root
            # get the user name
            username = pwd.getpwuid(os.getuid()).pw_name
            # get the user sshIps
            sshIps = self.clusterInfo.getClusterSshIps()
            # save the sshIps to Ips
            for ips in sshIps:
                Ips.extend(ips)

            self.logger.log("Creating SSH trust for the root permission user.")
            # Ask to create trust for root
            flag = input("Are you sure you want to create trust for root (yes/no)?")
            while True:
                # If it is not yes or no, it has been imported
                # if it is yes or no, it has been break
                if flag.upper() not in ("YES", "NO", "Y", "N"):
                    flag = input("Please type 'yes' or 'no': ")
                    continue
                break

            # Receives the entered password
            if flag.upper() in ("NO", "N"):
                return

            self.logger.log("Please enter password for root.")
            retry_times = 0
            while True:
                try:
                    self.sshTool.createTrust(username,
                                             Ips,
                                             action='gs_postuninstall')
                    break
                except Exception as err_msg:
                    if retry_times == 2:
                        raise Exception(str(err_msg))
                    if "Authentication failed" in str(err_msg):
                        self.logger.log("Password authentication failed, please try again.")
                        retry_times += 1
                    else:
                        raise Exception(str(err_msg))
            FileUtil.changeMode(DefaultValue.HOSTS_FILE, "/etc/hosts", False,
                              "shell", retry_flag=True)
            self.logger.log("Successfully created SSH trust for the root permission user.")
            self.root_ssh_agent_flag = True
        except Exception as e:
            raise Exception(str(e))

    def delet_root_mutual_trust(self, local_host, path):
        """
        :return:
        """
        if self.localMode or self.isSingle:
            return
        if not self.root_ssh_agent_flag:
            return
        self.logger.debug("Start Delete root mutual trust")

        username = pwd.getpwuid(os.getuid()).pw_name
        # get dir path
        homeDir = os.path.expanduser("~" + username)
        tmp_path = "%s/gaussdb_tmp" % homeDir

        # get cmd
        bashrc_file = ProfileFile.get_user_bashrc(self.user)
        kill_ssh_agent_cmd = "ps ux | grep 'ssh-agent' | grep -v grep | awk '{print $2}' | " \
                             "xargs kill -9"
        delete_line_cmd = ""
        if os.path.exists(bashrc_file):
            delete_line_cmd += " && sed -i '/^\\s*export\\s*SSH_AUTH_SOCK=.*$/d' %s" % bashrc_file
            delete_line_cmd += " && sed -i '/^\\s*export\\s*SSH_AGENT_PID=.*$/d' %s" % bashrc_file
        delete_line_cmd += " && sed -i '/#OM$/d' %s" % DefaultValue.SSH_AUTHORIZED_KEYS
        delete_line_cmd += " && sed -i '/#OM$/d' %s" % DefaultValue.SSH_KNOWN_HOSTS
        delete_shell_cmd = " && rm -rf %s" % tmp_path
        delete_shell_cmd += " && rm -rf %s" % DefaultValue.SSH_PRIVATE_KEY
        delete_shell_cmd += " && rm -rf %s" % DefaultValue.SSH_PUBLIC_KEY
        cmd = "%s" + delete_line_cmd + delete_shell_cmd

        # get remote node and local node
        host_list = self.clusterInfo.getClusterNodeNames()
        host_list.remove(local_host)

        # delete remote root mutual trust
        kill_remote_ssh_agent_cmd = DefaultValue.killInstProcessCmd("ssh-agent", True)
        self.sshTool.getSshStatusOutput(cmd % kill_remote_ssh_agent_cmd, host_list, gp_path=path)
        # delete local root mutual trust
        CmdExecutor.execCommandLocally(cmd % kill_ssh_agent_cmd)
        self.logger.debug("Delete root mutual trust successfully.")

    def cleanLocalBackupScript(self):
        """
        function: clean gauss_om script
        """
        # clean root script path
        if os.path.exists(self.gauss_om_path):
            FileUtil.removeDirectory(self.gauss_om_path)
            self.logger.log("Successfully cleaned local gauss_om.")
            self.logger.log("clean over.")
            return
        # if /root/gauss_om has no files, delete it.
        if not os.listdir(self.gauss_om_path):
            FileUtil.removeDirectory(self.gauss_om_path)
            self.logger.log("Successfully cleaned local gauss_om.")
            self.logger.log("clean over.")
            return
        self.logger.log("clean over.")

    def run(self):
        try:
            self.logger.debug(
                "gs_postuninstall execution takes %s steps in total"
                % ClusterCommand.countTotalSteps("gs_postuninstall"))
            local_host = NetUtil.GetHostIpOrName()
            if (self.mpprcFile is not None and self.mpprcFile != "" and os.path.exists(self.mpprcFile)):
                os_profile = self.mpprcFile
            else:
                os_profile = ClusterConstants.ETC_PROFILE
            path = EnvUtil.get_env_param(source_file=os_profile,
                                         env_param="UNPACKPATH")
            self.createTrustForRoot()
            self.cleanGphomeScript()
            self.checkLogFilePath()
            self.cleanSyslogConfig()
            self.doCleanEnvironment()
            self.logger.closeLog()
            self.cleanLocalLog()
            self.cleanMpprcFile()
            self.cleanScript()
            self.setOrCleanGphomeEnv(setGphomeenv=False)
            self.logger.log("Successfully cleaned environment.")
            if os.path.exists(self.gauss_om_path):
                self.cleanOthernodesBackupScript()
                self.delet_root_mutual_trust(local_host, path)
                self.cleanLocalBackupScript()
            else:
                self.delet_root_mutual_trust(local_host, path)
                self.logger.log("clean over.")
        except Exception as e:
            self.logger.logExit(str(e))
        sys.exit(0)
