#!/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_om is a utility to manage a Gauss200 cluster.
#############################################################################

import subprocess
import os
import sys
import pwd
import math

from base_utils.security.security_checker import SecurityChecker
from gspylib.common.GaussLog import GaussLog
from gspylib.common.ErrorCode import ErrorCode
from gspylib.common.ParameterParsecheck import Parameter
from gspylib.common.Common import DefaultValue
from gspylib.common.ParallelBaseOM import ParallelBaseOM
from impl.om.OLAP.OmImplOLAP import OmImplOLAP
from domain_utils.cluster_file.cluster_log import ClusterLog
from base_utils.os.env_util import EnvUtil
from base_utils.os.file_util import FileUtil
from base_utils.os.user_util import UserUtil
from domain_utils.domain_common.cluster_constants import ClusterConstants
from domain_utils.cluster_os.cluster_user import ClusterUser

# action type
ACTION_START = "start"
ACTION_STOP = "stop"
ACTION_RESTART = "restart"
ACTION_STATUS = "status"
ACTION_REBUID = "generateconf"
ACTION_CERT = "cert"
STOP_MODE_FAST = "fast"
STOP_MODE_IMMEDIATE = "immediate"
ACTION_VIEW = "view"
ACTION_QUERY = "query"
ACTION_KERBEROS = "kerberos"
ACTION_REFRESHCONF = "refreshconf"
ACTION_KILLMONITOR = "killmonitor"
ACTION_GENERATE_XML = "generate_xml"
ACTION_QUERY_UPGRADE_RECORDS = "query_upgrade_records"

# postgis
ACTION_DEL_POSTGIs = "rmlib"


class CmdOptions():
    """
    define option
    """

    def __init__(self):
        self.action = ""
        # if action is "express", use this parameter to store the list of
        # cluster node names passed by the
        # command line option "-h".
        self.nodeName = ""
        self.time_out = None
        # if action is "express", use this parameter to store whether to
        # show the detail message of cluster
        # node state.
        self.show_detail = False
        self.showAll = False
        self.dataDir = ""
        self.outFile = ""
        self.logFile = ""
        self.localLog = ""
        self.reset = False
        self.distribute = False
        self.certFile = ""
        self.certRollback = False
        self.NormalCNNode = []
        self.mode = ""

        self.user = ""
        self.group = ""
        self.userInfo = ""
        self.mpprcFile = ""
        self.confFile = ""
        self.localMode = False
        self.instanceName = ""
        self.azName = ""
        self.nodeId = -1
        self.clusterInfo = None
        self.security_mode = "off"
        self.cluster_number = ""

        # kerberos
        self.kerberosMode = ""
        self.clusterUser = ""
        self.kerberosType = ""
        self.clusterToolPath = ""

        # change_static
        self.old_values = []
        self.new_values = []

        # view
        self.is_dynamic = False

        # generate_xml
        self.add_hostips = ""
        self.add_hostnames = ""
        
        # operate cm
        self.component = ""


###########################################
class OperationManager(ParallelBaseOM):

    def __init__(self):
        """
        init the command options
        save command line parameter values
        """
        ParallelBaseOM.__init__(self)
        # command line parameter collection
        self.g_opts = CmdOptions()
        self.OM_PARAMETER_DIR = ""

    def usage(self):
        """
gs_om is a utility to manage a cluster.

Usage:
  gs_om -? | --help
  gs_om -V | --version
  OLAP scene:
    gs_om -t start [-h HOSTNAME] [-D dataDir] [--time-out=SECS]
                   [--security-mode=MODE] [--cluster-number=None] 
                   [--component=CM] [-l LOGFILE]
    gs_om -t stop [-h HOSTNAME] [-D dataDir]  [--time-out=SECS] [-m MODE]
                  [-l LOGFILE]  [--component=CM]
    gs_om -t restart [-h HOSTNAME] [-D dataDir] [--time-out=SECS]
                   [--security-mode=MODE]  [--component=CM] [-l LOGFILE] [-m MODE]
    gs_om -t status [-h HOSTNAME] [-o OUTPUT] [--detail] [--all] [--az=AZ] [-l LOGFILE]
                    [--time-out=SECS]
    gs_om -t generateconf -X XMLFILE [--distribute] [-l LOGFILE]
    gs_om -t generateconf --old-values=old --new-values=new [--distribute] [-l LOGFILE]
    gs_om -t cert [--cert-file=CERTFILE | --rollback] [-L] [-l LOGFILE]
    gs_om -t kerberos -m [install|uninstall] -U USER [-l LOGFILE]
                         [--krb-server|--krb-client]
    gs_om -t view [-o OUTPUT]
    gs_om -t query [-o OUTPUT] [--time-out=SECS]
    gs_om -t refreshconf
    gs_om -t killmonitor
    gs_om -t generate_xml [--add-hostname=hostname1,hostname2] [--add-hostip=hostip1,hostip2]
    gs_om -t query_upgrade_records

General options:
  -t                              Type of the OM command.
  -l                              Path of log file.
  -?, --help                      Show help information for this utility,
  and exit the command line mode.
  -V, --version                   Show version information.

Options for start
  -h                              Name of the host to be started.
  -D                              Path of dn
      --time-out=SECS              Maximum waiting time when start the
                                   cluster or node.
      --security-mode=MODE        database start with security mode: on or off
                                        on: start with security mode
                                        off: start without security mode
      --cluster-number            database start with kernel version corresponding
                                  to version.cfg

Options for stop
  -h                              Name of the host to be shut down.
  -m, --mode=MODE                 Shutdown mode. It can be f (fast),
                                  or i (immediate).
  -D                              Path of dn
      --time-out=SECS             Maximum waiting time when start the cluster
                                 or node.

Options for restart
  -h                              Name of the host to be started.
  -m, --mode=MODE                 Shutdown mode. It can be f (fast),
                                  or i (immediate).
  -D                              Path of dn
      --time-out=SECS             Maximum waiting time when start the
                                  cluster or node.
      --security-mode=MODE        database start with security mode: on or off
                                        on: start with security mode
                                        off: start without security mode

Options for status
  -h                              Name of the host whose status is to be
                                  queried.
  --az=AZ                         Name of the single az whose status is to
                                  be queried.
  -o                              Save the result to the specified file.
      --detail                    Show detailed status information.
      --all                       Show all database node status information.
      --time-out=SECS             Maximum waiting time when query cluster status.

Options for generating configuration files
  -X                              Path of the XML configuration file.
  --old-values                    IP or hostname or port like "host1,ip1,port1"
  --new-values                    IP or hostname or port like "host1,ip1,port1"
      --distribute                Distribute the static configuration file
                                  to installation directory of cluster nodes.

Options for cert
      --cert-file                 Path of cert file.
      --rollback                  Perform rollback SSL cert files.
      -L                          local mode.

Options for kerberos
  -m                              Kerberos management mode. It can be
                                  install or uninstall.
  -U                              %s cluster user.
Install options:
  --krb-server                    Execute install for server. This parameter
  only work for install
  --krb-client                    Execute install for client. This parameter
  only work for install

        """

        print(self.usage.__doc__)

    def initGlobal(self):
        """
        function:Init logger
        input:NA
        output:NA
        """
        try:
            # Init logger
            self.xmlFile = self.g_opts.confFile
            self.logFile = self.g_opts.logFile
            self.initLogger(self.g_opts.action)
            if (os.getuid() != 0):
                FileUtil.modifyFileOwnerFromGPHOME(self.logger.logFile)

            dirName = os.path.dirname(self.g_opts.logFile)
            self.g_opts.localLog = os.path.join(dirName,
                                                ClusterConstants.LOCAL_LOG_FILE)

            if self.g_opts.action == ACTION_REBUID and self.g_opts.confFile:
                self.initClusterInfo()
            else:
                # Initialize the self.clusterInfo variable
                if (self.g_opts.action == ACTION_STATUS):
                    self.initClusterInfoFromStaticFile(self.g_opts.user, False)
                elif self.g_opts.action == ACTION_VIEW and self.g_opts.is_dynamic:
                    self.initClusterInfoFromDynamicFile(self.g_opts.user)
                else:
                    self.initClusterInfoFromStaticFile(self.g_opts.user)

            # Obtain the owner and group of the cluster installation directory
            if self.g_opts.action != ACTION_KERBEROS:
                (self.g_opts.user, self.g_opts.group) = UserUtil.getPathOwner(
                    self.clusterInfo.appPath)
                if self.g_opts.user == "" or self.g_opts.group == "":
                    raise Exception(ErrorCode.GAUSS_503["GAUSS_50308"])
            # Init base member
            self.user = self.g_opts.user
            self.group = self.g_opts.group

            # init components
            if self.g_opts.action != ACTION_STATUS:
                self.initComponent()
        except Exception as e:
            GaussLog.exitWithError(str(e))

    def checkAction(self, ParaDict):
        """
        """
        if (ParaDict.__contains__("action")):
            self.g_opts.action = ParaDict.get("action")
            if (len(self.g_opts.action) == 0):
                GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"]
                                       % "t" + ".")

    def parseNode(self, ParaDict):
        """
        """
        if (self.g_opts.action == ACTION_START or
                self.g_opts.action == ACTION_STOP or
                self.g_opts.action == ACTION_STATUS or
                self.g_opts.action == ACTION_RESTART or
                self.g_opts.action == ACTION_QUERY_UPGRADE_RECORDS):
            if (ParaDict.__contains__("nodename")):
                nodename = ParaDict.get("nodename")
                self.g_opts.estimateNodeName = nodename
                # Only one -h parameter can be entered
                if (len(nodename) != 1):
                    GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50006"]
                                           % nodename[0] + " Please check it.")
                self.g_opts.nodeName = nodename[0]

            if "nodeId" in ParaDict.keys():
                nodeId = int(ParaDict.get("nodeId"))
                if nodeId < 1:
                    GaussLog.exitWithError(
                        ErrorCode.GAUSS_500["GAUSS_50004"] %
                        ParaDict.get("nodeId") + " Please check it.")
                self.g_opts.nodeId = nodeId

            if ("dataDir" in ParaDict.keys()):
                self.g_opts.dataDir = ParaDict.get("dataDir")
    
    def parseAZ(self, ParaDict):
        """
        
        """
        if self.g_opts.action == ACTION_STATUS:
            if (ParaDict.__contains__("az_name")):
                azname = ParaDict.get("az_name")
                self.g_opts.azName = azname
        

    def parseTimeOut(self, ParaDict):
        """
        """
        if self.g_opts.action == ACTION_START or self.g_opts.action == \
                ACTION_STOP or self.g_opts.action == ACTION_RESTART \
                    or self.g_opts.action == ACTION_STATUS or self.g_opts.action == ACTION_QUERY:
            if (ParaDict.__contains__("time_out")):
                self.g_opts.time_out = ParaDict.get("time_out")

    def parseMode(self, ParaDict):
        """
        """
        if (self.g_opts.action == ACTION_STOP):
            if (ParaDict.__contains__("Mode")):
                self.g_opts.mode = ParaDict.get("Mode")

    def parseKerberosMode(self, ParaDict):
        """
        """
        if (self.g_opts.action == ACTION_KERBEROS):
            if ("Mode" in ParaDict):
                self.g_opts.kerberosMode = ParaDict.get("Mode")

    def parseStatus(self, ParaDict):
        """
        """
        if (self.g_opts.action == ACTION_STATUS):
            # A status query can specify an out file
            if (ParaDict.__contains__("outFile")):
                self.g_opts.outFile = ParaDict.get("outFile")
            # The status query can display detailed information
            if (ParaDict.__contains__("show_detail")):
                self.g_opts.show_detail = ParaDict.get("show_detail")
            if (ParaDict.__contains__("all")):
                self.g_opts.showAll = ParaDict.get("all")

    def parseView(self, ParaDict):
        """
        """
        if (self.g_opts.action == ACTION_VIEW):
            # A view can specify an out file
            if ("outFile" in ParaDict.keys()):
                self.g_opts.outFile = ParaDict.get("outFile")
            if "dynamic" in ParaDict.keys():
                self.g_opts.is_dynamic = True

    def parseQuery(self, ParaDict):
        """
        """
        if (self.g_opts.action == ACTION_QUERY):
            # A view can specify an out file
            if ("outFile" in ParaDict.keys()):
                self.g_opts.outFile = ParaDict.get("outFile")

    def parseStart(self, ParaDict):
        """
        """
        if (self.g_opts.action == ACTION_START) \
            or self.g_opts.action == ACTION_RESTART:
            # The start query can specify az name
            if ParaDict.__contains__("az_name"):
                self.g_opts.azName = ParaDict.get("az_name")
            if ParaDict.__contains__("security_mode"):
                self.g_opts.security_mode = ParaDict.get("security_mode")
            if ParaDict.__contains__("cluster_number"):
                cluster_number = ParaDict.get("cluster_number")
                SecurityChecker.check_injection_char(cluster_number)
                try:
                    cluster_num = float(cluster_number)
                    # extra check: must be a finite number , exclude nan/inf
                    if not isinstance(cluster_num, float) or not math.isfinite(cluster_num):
                        raise ValueError
                except ValueError:
                    GaussLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50219"] %
                        cluster_number + " must be a numeric value (e.g., 93.090).")
                self.g_opts.cluster_number = cluster_number

    def parseStop(self, ParaDict):
        """
        """
        if (self.g_opts.action == ACTION_STOP) \
            or self.g_opts.action == ACTION_RESTART:
            # The start query can specify az name for OLAP
            if (ParaDict.__contains__("az_name")):
                self.g_opts.azName = ParaDict.get("az_name")

    def parseConFile(self, ParaDict):
        """
        """
        if (self.g_opts.action == ACTION_REBUID):
            # Changeip, managecn, and generateconf require the -X parameter
            if (ParaDict.__contains__("confFile")):
                self.g_opts.confFile = ParaDict.get("confFile")
            if ParaDict.__contains__("old_values"):
                self.g_opts.old_values = ParaDict.get("old_values")
            if ParaDict.__contains__("new_values"):
                self.g_opts.new_values = ParaDict.get("new_values")

    def parseGenerateconf(self, ParaDict):
        """
        """
        if (self.g_opts.action == ACTION_REBUID):
            # Generateconf can specify the distribution file
            if (ParaDict.__contains__("distribute")):
                self.g_opts.distribute = ParaDict.get("distribute")

    def parseCert(self, ParaDict):
        """
        """
        if (self.g_opts.action == ACTION_CERT):
            # cert can change cert file
            if (ParaDict.__contains__("cert-file")):
                self.g_opts.certFile = ParaDict.get("cert-file")
            if (ParaDict.__contains__("rollback")):
                self.g_opts.certRollback = ParaDict.get("rollback")
            if (ParaDict.__contains__("localMode")):
                self.g_opts.localMode = ParaDict.get("localMode")
            if (ParaDict.__contains__("cert-file") and ParaDict.__contains__(
                    "rollback")):
                GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50005"]
                                       % ("-cert-file", "-rollback"))

    def parseKerberos(self, ParaDict):
        """
        """
        if self.g_opts.action == ACTION_KERBEROS:
            if "user" in ParaDict:
                self.g_opts.clusterUser = ParaDict.get("user")
            if self.g_opts.kerberosMode == "install":
                if "krb-server" in ParaDict and "krb-client" in ParaDict:
                    GaussLog.exitWithError(
                        ErrorCode.GAUSS_500["GAUSS_50005"]
                        % ("-krb-server", "-krb-client"))
                if (("krb-server" not in ParaDict) and (
                        "krb-client" not in ParaDict)):
                    GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"]
                                           % "-krb-server' or '--krb-client")
                if "krb-server" in ParaDict:
                    self.g_opts.kerberosType = "krb-server"
                if "krb-client" in ParaDict:
                    self.g_opts.kerberosType = "krb-client"
            if self.g_opts.kerberosMode == "uninstall":
                if "krb-server" in ParaDict:
                    GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50002"]
                                           % "-krb-server")
                if "krb-client" in ParaDict:
                    GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50002"]
                                           % "-krb-client")


    def parseLog(self, ParaDict):
        """
        """
        if (ParaDict.__contains__("logFile")):
            self.g_opts.logFile = ParaDict.get("logFile")

    def parse_generate_xml(self, ParaDict):
        if (ParaDict.__contains__("add_hostname")):
            self.g_opts.add_hostnames = ParaDict.get("add_hostname")
        if (ParaDict.__contains__("add_hostip")):
            self.g_opts.add_hostips = ParaDict.get("add_hostip")
            
    def parse_component(self, ParaDict):
        support_comp_list = [ "CM", "DN" ]
        if (ParaDict.__contains__("component")):
            self.g_opts.component = ParaDict.get("component")
            if self.g_opts.component not in support_comp_list:
                GaussLog.exitWithError(f"--component only support {support_comp_list}")

    def parseCommandLine(self):
        """
        function:Parse command line and save to global variable
        input:NA
        output:NA
        """
        # Parse command line
        ParaObj = Parameter()
        ParaDict = ParaObj.ParameterCommandLine("gs_om")
        # If help is included in the parameter,
        # the help message is printed and exited
        if (ParaDict.__contains__("helpFlag")):
            self.usage()
            sys.exit(0)
        # The -t parameter is required
        self.checkAction(ParaDict)
        # Starting a cluster, stopping a cluster, querying a state,
        # and switching between active and standby devices require obtaining
        # node information
        self.parseNode(ParaDict)
        # Starting a Cluster and Stopping a Cluster
        # can specify a timeout period
        self.parseTimeOut(ParaDict)
        # Stop the cluster and managecn to specify the mode
        self.parseMode(ParaDict)
        # Kerberos to specify the mode
        self.parseKerberosMode(ParaDict)
        # Parse start parameter
        self.parseStart(ParaDict)
        # Parse stop parameter
        self.parseStop(ParaDict)
        # Parse status parameter
        self.parseStatus(ParaDict)
        # Parse view parameter
        self.parseView(ParaDict)
        # Parse query parameter
        self.parseQuery(ParaDict)
        # Parse -X parameter
        self.parseConFile(ParaDict)
        # Parse generateconf parameter
        self.parseGenerateconf(ParaDict)
        # Parse cert parameter
        self.parseCert(ParaDict)
        # Parse kerberos parameter
        self.parseKerberos(ParaDict)
        # Parse log parameter
        self.parseLog(ParaDict)
        # Parse Az info
        self.parseAZ(ParaDict)
        # Parse generate xml parameter
        self.parse_generate_xml(ParaDict)
        # Parse operation component
        self.parse_component(ParaDict)

    ###########################################################################
    # Check parameters for all operations
    ###########################################################################
    def checkParameter(self):
        """
        function:Check parameter from command line
        input:NA
        output:NA
        """
        if (os.getuid() == 0):
            GaussLog.exitWithError(ErrorCode.GAUSS_501["GAUSS_50105"] + \
                                   " When the parameter '-t' value is not "
                                   "dailyAlarm or not estimate install "
                                   "consume or not extension connector with "
                                   "add, delete, restart, upgrade in -m "
                                   "parameter.")

        if (self.g_opts.action == ACTION_START):
            self.checkStartParameter()
        elif (self.g_opts.action == ACTION_STOP):
            self.checkStopParameter()
        elif (self.g_opts.action == ACTION_RESTART):
            self.checkRestartParameter()
        elif (self.g_opts.action == ACTION_STATUS):
            self.checkOutFileParameter()
            self.checkTimeOutParam()
        elif (self.g_opts.action == ACTION_REBUID):
            self.checkGenerateConfParameter()
        elif (self.g_opts.action == ACTION_CERT):
            self.checkCertParameter()
        elif (self.g_opts.action == ACTION_KERBEROS):
            self.checkKerberosParameter()
        elif (self.g_opts.action == ACTION_VIEW):
            self.checkOutFileParameter()
        elif (self.g_opts.action == ACTION_QUERY):
            self.checkOutFileParameter()
            self.checkTimeOutParam()
        elif (self.g_opts.action == ACTION_REFRESHCONF):
            pass
        elif (self.g_opts.action == ACTION_KILLMONITOR):
            pass
        elif (self.g_opts.action == ACTION_GENERATE_XML):
            self.check_generate_xml_parameter()
        elif (self.g_opts.action == ACTION_QUERY_UPGRADE_RECORDS):
            pass
        else:
            GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50004"] % "t")

        # check mpprc file path
        self.g_opts.mpprcFile = EnvUtil.getMpprcFile()

        # check if user exist and is the right user
        if (self.g_opts.user == ""):
            self.g_opts.user = pwd.getpwuid(os.getuid()).pw_name
            if (self.g_opts.user == ""):
                GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] %
                                       "U" + ".")

        # Check user on installed cluster
        ClusterUser.checkUser(self.g_opts.user)
        # Check whether the current user is consistent with -U if no root
        if (os.getuid() != 0):
            cmd = "id -un"
            (status, output) = subprocess.getstatusoutput(cmd)
            if (output != self.g_opts.user):
                GaussLog.exitWithError(
                    ErrorCode.GAUSS_530["GAUSS_53033"] % self.g_opts.user)

        self.OM_PARAMETER_DIR = "%s/om_parameter_dir" % \
                                EnvUtil.getTmpDirFromEnv(self.g_opts.user)

        # check log file
        if (self.g_opts.logFile == ""):
            self.g_opts.logFile = ClusterLog.getOMLogPath(
                ClusterConstants.OM_LOG_FILE, self.g_opts.user, "",
                action=self.g_opts.action)
        if (not os.path.isabs(self.g_opts.logFile)):
            GaussLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50213"] % "log")

    def checkStartParameter(self):
        """
        Check parameter for start the cluster and node
        input : NA
        output: NA
        """
        # if the parameter -I is exits, then the -h parameter is required.
        if (self.g_opts.instanceName and (not self.g_opts.nodeName)):
            GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % "h")
        
        # check timeout
        self.checkTimeOutParam()
        if self.g_opts.security_mode != "off" and self.g_opts.security_mode \
                != "on":
            GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50004"]
                                   % "-security-mode")
    def checkTimeOutParam(self):
        # If the cluster does not specify a time-out period, the default is
        # 300 seconds
        if (self.g_opts.time_out is None):
            if self.g_opts.action == ACTION_STATUS or self.g_opts.action == ACTION_QUERY:
                self.g_opts.time_out = DefaultValue.TIMEOUT_CLUSTER_QUERY
            else:
                self.g_opts.time_out = DefaultValue.TIMEOUT_CLUSTER_START
        else:
            # The timeout parameter must be a pure number
            if (not str(self.g_opts.time_out).isdigit()):
                GaussLog.exitWithError(
                    ErrorCode.GAUSS_500["GAUSS_50003"] %
                    ("-time-out", "a nonnegative integer"))
            self.g_opts.time_out = int(self.g_opts.time_out)
            # The timeout parameter must be greater than 0
            # The timeout parameter must be less than the integer maximum
            if (self.g_opts.time_out <= 0 or self.g_opts.time_out
                    >= 2147483647):
                GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50004"]
                                       % "-time-out")

    def checkStopParameter(self):
        """
        Check parameter for stop cluster and node
        input : NA
        output: NA
        """
        # if the parameter -I is exits, then the -h parameter is required.
        if (self.g_opts.instanceName and (not self.g_opts.nodeName)):
            GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % "h")
            # If no stop type is specified, the default is fast
        # check timeout
        self.checkTimeOutParam()
        if (self.g_opts.mode == ""):
            self.g_opts.mode = STOP_MODE_FAST
        # Specifies that the stop type must be f, i or s
        if (self.g_opts.mode not in [STOP_MODE_FAST, STOP_MODE_IMMEDIATE,
                                     "f", "i"]):
            GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50004"] % "m")
    
    def checkRestartParameter(self):
        """
        Check parameter for restart cluster and node.
        Restart parameters are same with start and stop.
        input : NA
        output: NA
        """
        self.checkStartParameter()

        if (self.g_opts.mode == ""):
            self.g_opts.mode = STOP_MODE_FAST
        # Specifies that the stop type must be f, i or s
        if (self.g_opts.mode not in [STOP_MODE_FAST, STOP_MODE_IMMEDIATE,
                                     "f", "i"]):
            GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50004"] % "m")


    def checkOutFileParameter(self):
        """
        Check parameter for status
        input : NA
        output: NA
        """
        # Check the status query for the specified output file
        if (self.g_opts.outFile != ''):
            DefaultValue.checkOutputFile(self.g_opts.outFile)

    def checkGenerateConfParameter(self):
        """
        Check parameter for generate config
        input : NA
        output: NA
        """
        if self.g_opts.old_values.__len__() == 0:
            # check xml file
            if self.g_opts.confFile == "":
                GaussLog.exitWithError(
                    ErrorCode.GAUSS_500["GAUSS_50001"] % 'X' + ".")
            if not os.path.isfile(self.g_opts.confFile):
                GaussLog.exitWithError(
                    ErrorCode.GAUSS_502["GAUSS_50210"] % self.g_opts.confFile)
        else:
            if self.g_opts.old_values.__len__() != self.g_opts.new_values.__len__():
                GaussLog.exitWithError(
                    ErrorCode.GAUSS_512["GAUSS_51230"] % ("old-values", "equal to new-values"))

    def checkCertParameter(self):
        """
        Check parameter for cert
        input : NA
        output: NA
        """
        # add cert must specify the --cert-file parameter
        if (self.g_opts.certFile == "" and not self.g_opts.certRollback):
            GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] %
                                   '-cert-file or --rollback')
        # certFile must be exist
        if (self.g_opts.certFile != "" and self.g_opts.certFile[-4:]
                != ".zip"):
            GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"]
                                   % "-cert-file type is not 'zip'")
        if (not os.path.isfile(self.g_opts.certFile)
                and not self.g_opts.certRollback):
            GaussLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50210"]
                                   % self.g_opts.certFile)

    def checkKerberosParameter(self):
        """
        Check parameter for kerberos
        input : NA
        output: NA
        """
        if (self.g_opts.kerberosMode != "install" and
                self.g_opts.kerberosMode != "uninstall"):
            GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50004"]
                                   % 'm' + "Value: %s"
                                   % self.g_opts.kerberosMode)

        # get user info
        self.user = UserUtil.getUserInfo()['name']
        if (self.g_opts.clusterUser == ""):
            GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % 'U')
        if self.g_opts.clusterUser != self.user:
            GaussLog.exitWithError(ErrorCode.GAUSS_503["GAUSS_50323"]
                                   % self.g_opts.clusterUser)

        if (self.g_opts.kerberosMode == "install" and
                self.g_opts.kerberosType == ""):
            GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"]
                                   % "-krb-server' or '--krb-client")

    def checkDSN(self, dsnName):
        """
        function: Check the path:
                  the path must be composed of letters, numbers,
                  underscores, slashes, hyphen, and spaces
        input : path_type_in
        output: NA
        """
        nameLen = len(dsnName)
        if (nameLen > 64):
            GaussLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50219"]
                                   % dsnName
                                   + "Error:\nThe DSN name is too long.")
        wrongChar = None
        i = 0
        a_ascii = ord('a')
        z_ascii = ord('z')
        A_ascii = ord('A')
        Z_ascii = ord('Z')
        num0_ascii = ord('0')
        num9_ascii = ord('9')
        sep_ascii = ord('_')
        for i in range(0, nameLen):
            char_check = ord(dsnName[i])
            if (not (a_ascii <= char_check <= z_ascii or A_ascii <=
                    char_check <= Z_ascii or num0_ascii <= char_check <=
                    num9_ascii or char_check == sep_ascii)):
                wrongChar = dsnName[i]
                break
        if (wrongChar != None):
            return wrongChar
        else:
            return True
        
    def check_generate_xml_parameter(self):
        add_hostnames = self.g_opts.add_hostnames.split(',')
        add_hostips = self.g_opts.add_hostips.split(',')

        if (len(add_hostnames) != len(add_hostips)):
            GaussLog.exitWithError(ErrorCode.GAUSS_357["GAUSS_35713"] %
                                    (len(add_hostnames), len(add_hostips)))


def main():
    """
    main function
    """
    try:
        # Objectize class
        manager = OperationManager()
        # parse cmd lines
        manager.parseCommandLine()
        # check parameters
        manager.checkParameter()

        # init global variables
        manager.initGlobal()
        # set action flag file
        DefaultValue.setActionFlagFile(manager.g_opts.action)
    except Exception as e:
        GaussLog.exitWithError(str(e))

    try:
        impl = OmImplOLAP(manager)

        if (manager.g_opts.action not in [ACTION_START,
                                          ACTION_STOP,
                                          ACTION_RESTART,
                                          ACTION_STATUS,
                                          ACTION_REBUID,
                                          ACTION_CERT,
                                          ACTION_KERBEROS,
                                          ACTION_VIEW,
                                          ACTION_QUERY,
                                          ACTION_REFRESHCONF,
                                          ACTION_KILLMONITOR,
                                          ACTION_GENERATE_XML,
                                          ACTION_QUERY_UPGRADE_RECORDS
                                          ]):
            raise Exception(ErrorCode.GAUSS_531['GAUSS_53104']
                            % ("gs_om -t " + manager.g_opts.action))
        elif (manager.g_opts.action == ACTION_CERT and
              manager.g_opts.certRollback):
            impl.doDNSSLCertRollback()

        # Depending on the function, different operations are performed
        if (manager.g_opts.action == ACTION_START):
            impl.doStart()
        elif (manager.g_opts.action == ACTION_STOP):
            impl.doStop()
        elif (manager.g_opts.action == ACTION_RESTART):
            impl.doStop(), impl.doStart()
        elif (manager.g_opts.action == ACTION_STATUS):
            impl.doStatus()
        elif (manager.g_opts.action == ACTION_REBUID):
            impl.doRebuildConf()
        elif (manager.g_opts.action == ACTION_KERBEROS):
            if DefaultValue.isUnderUpgrade(manager.user):
                raise Exception(ErrorCode.GAUSS_529["GAUSS_52936"])
            impl.doKerberos()
        elif (manager.g_opts.action == ACTION_CERT
              and not manager.g_opts.certRollback):
            impl.doReplaceSSLCert()
        elif (manager.g_opts.action == ACTION_VIEW):
            impl.doView()
        elif (manager.g_opts.action == ACTION_QUERY):
            impl.doQuery()
        elif (manager.g_opts.action == ACTION_REFRESHCONF):
            impl.doRefreshConf()
        elif (manager.g_opts.action == ACTION_KILLMONITOR):
            impl.kill_om_monitor()
        elif (manager.g_opts.action == ACTION_GENERATE_XML):
            impl.do_generate_xml()
        elif (manager.g_opts.action == ACTION_QUERY_UPGRADE_RECORDS):
            impl.do_query_upgrade_records()
        manager.logger.closeLog()
    except Exception as e:
        manager.logger.logExit(str(e))
    finally:
        DefaultValue.setActionFlagFile("gs_om", False)


if __name__ == '__main__':
    main()