#!/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 : ############################################################################# import os import sys import getopt import subprocess import glob import xml.etree.cElementTree as ETree sys.path.append(sys.path[0] + "/../") sys.path.append(os.path.realpath(os.path.dirname(__file__)) + "/../../lib") from gspylib.common.GaussLog import GaussLog from gspylib.common.DbClusterInfo import dbClusterInfo from gspylib.common.Common import DefaultValue from gspylib.common.ErrorCode import ErrorCode from gspylib.common.ParameterParsecheck import Parameter from domain_utils.cluster_file.config_param import ConfigParam from base_utils.os.env_util import EnvUtil from base_utils.os.file_util import FileUtil from domain_utils.cluster_file.version_info import VersionInfo from base_utils.os.net_util import NetUtil from base_utils.os.user_util import UserUtil from os_platform.linux_distro import LinuxDistro from domain_utils.cluster_os.cluster_user import ClusterUser actioItemMap = { "Check_SysCtl_Parameter": ['/etc/sysctl.conf', False], "Check_FileSystem_Configure": ['/etc/security/limits.conf', False], "osKernelParameterCheck": ['/etc/sysctl.conf', False], "Set_SysCtl_Parameter": ['/etc/sysctl.conf', True], "Set_FileSystem_Configure": ['/etc/security/limits.conf', True] } docker_no_need_check = ["net.core.wmem_max", "net.core.rmem_max", "net.core.wmem_default", "net.core.rmem_default", "net.core.netdev_max_backlog", "net.ipv4.tcp_max_tw_buckets", "net.ipv4.tcp_tw_reuse", "net.ipv4.tcp_tw_recycle", "net.ipv4.tcp_retries2", "net.ipv4.ip_local_reserved_ports", "net.ipv4.tcp_rmem", "net.ipv4.tcp_wmem", "net.ipv4.tcp_max_syn_backlog", "net.ipv4.tcp_syncookies", "net.ipv4.tcp_fin_timeout", "net.ipv4.tcp_sack", "net.ipv4.tcp_timestamps", "net.ipv4.tcp_retries1", "net.ipv4.tcp_syn_retries", "net.ipv4.tcp_synack_retries"] paraList = {} ############################################################################# # Global variables # g_opts: globle option # g_logger: globle logger # g_clusterInfo: global clueter information ############################################################################# g_logger = None g_opts = None g_clusterInfo = None g_check_os = False configFile = '' resultList = list() netWorkBondInfo = None netWorkLevel = 10000 class CmdOptions(): def __init__(self): """ function: constructor """ # initialize variable self.action = "" self.user = "" self.extrachecklist = [] self.logFile = "" self.confFile = "" self.mtuValue = "" self.hostname = "" class netWork: """ class: netWork """ def __init__(self): """ function : Init class netWork input : NA output : NA """ self.netLevel = "" self.netNum = "" self.variables = dict() self.modeType = False self.nums = 0 ############################################################################# # Parse and check parameters ############################################################################# def usage(): """ Usage: python3 --help | -? python3 LocalCheck -t action [-l logfile] [-U user] [--check-os] [-V] Common options: -t The type of action. -l --log-file=logfile The path of log file. -? --help Show this help screen. -U Cluster user with root permissions. --check-os Whether or not gs_checkos -V --version """ print(usage.__doc__) def checkSpecifiedItems(key, paralist, isSet=False): """ function: check specified item name input : key, paralist, isSet output: NA """ # checkItemMap[key][0] is the check function about the key func = checkItemMap[key][0] try: if (hasattr(func, "__name__")): func(paralist, isSet) else: g_logger.logExit(ErrorCode.GAUSS_530["GAUSS_53010"] % (func, "LocalCheck.py")) except Exception as e: g_logger.logExit(str(e)) def checkNetWorkMTU(): """ function: gs_check check NetWork card MTU parameters input: NA output: int """ try: # Init cluster info DbClusterInfo = dbClusterInfo() DbClusterInfo.initFromStaticConfig(g_opts.user) localHost = NetUtil.GetHostIpOrName() nodeIp = None for dbnode in DbClusterInfo.dbNodes: if (dbnode.name == localHost): nodeIp = dbnode.backIps[0] break networkCardNum = DefaultValue.CheckNetWorkBonding(nodeIp, False) # check NetWork card MTU parameters valueStr = DefaultValue.checkNetWorkMTU(nodeIp, False) if (not str(valueStr).isdigit()): g_logger.log("Abnormal reason: Failed to obtain network" " card MTU value." + " Error: \n%s" % valueStr) return 1 netParameter = ConfigParam.getConfigFilePara(configFile, '/sbin/ifconfig') if (int(valueStr) != int(g_opts.mtuValue)): g_logger.log(" Abnormal: network '%s' 'mtu' value[%s:%s]" " is different from the other node [%s:%s]" % (networkCardNum, localHost, valueStr, g_opts.hostname, g_opts.mtuValue)) return 1 elif (int(valueStr) != int(netParameter["mtu"])): g_logger.log(" Warning reason: variable 'MTU' RealValue " "'%s' ExpectedValue '%s'." % (valueStr, netParameter["mtu"])) return 2 else: return 0 except Exception as e: g_logger.log(" Abnormal reason: Failed to obtain the" " networkCard parameter [MTU]. Error: \n %s" % str(e)) return 1 def checkSysctlParameter(kernelParameter, isSet): """ function: check and set the OS parameters input: kernelParameter: OS parameters list will be check and set isSet: the flag, when it is only True then will set OS parameters output: NA """ setParameterList = {} patchlevel = "" # get the suggest parameters and updata kernelParameter suggestParameterList = ConfigParam.getConfigFilePara( configFile, 'SUGGEST:%s' % actioItemMap["Check_SysCtl_Parameter"][0]) kernelParameter.update(suggestParameterList) # check the OS parameters if ("fs.aio-max-nr" in kernelParameter): g_logger.log(" Warning reason: Checking or setting the" " parameter 'fs.aio-max-nr' should be use " "'gs_checkos -i A10' or 'gs_checkos -i B4'.") kernelParameter.pop("fs.aio-max-nr") # Get OS version distname, version = LinuxDistro.linux_distribution()[0:2] if (distname == "SuSE" and version == "11"): cmd = "grep -i 'PATCHLEVEL' /etc/SuSE-release |" \ " awk -F '=' '{print $2}'" (status, output) = subprocess.getstatusoutput(cmd) if (status == 0 and output != ""): patchlevel = output.strip() # Gs_check get NetWork card MTU if (g_opts.action == "osKernelParameterCheck"): checkrestult = checkNetWorkMTU() if checkrestult != 0: resultList.append(checkrestult) for key in kernelParameter: # The SuSE 11 SP1 operating system # does not have vm.extfrag_threshold parameter, skip check if (patchlevel == "1" and key == "vm.extfrag_threshold"): continue sysFile = "/proc/sys/%s" % key.replace('.', '/') # High version of linux no longer supports tcp_tw_recycle if not os.path.exists( sysFile) and key == "net.ipv4.tcp_tw_recycle": continue if (DefaultValue.checkDockerEnv() and key in docker_no_need_check): continue cmd = "cat %s" % ("/proc/sys/%s" % key.replace('.', '/')) (status, output) = subprocess.getstatusoutput(cmd) if (status == 0): if (key == "vm.min_free_kbytes" and output.split() != kernelParameter[key].split()): expected_min = float(kernelParameter[key].split()[0]) * 0.9 expected_max = float(kernelParameter[key].split()[0]) * 1.1 if (int(output.split()[0]) > expected_max or int(output.split()[0]) < expected_min): resultList.append(2) g_logger.log(" Warning reason: variable '%s'" " RealValue '%s' ExpectedValue '%s'." % (key, output, kernelParameter[key])) setParameterList[key] = kernelParameter[key] elif (key == "net.ipv4.ip_local_port_range" and output.split() != kernelParameter[key].split()): expected_min = int(kernelParameter[key].split()[0]) expected_max = int(kernelParameter[key].split()[1]) if (int(output.split()[0]) < expected_min or int(output.split()[1]) > expected_max): resultList.append(2) g_logger.log(" Warning reason: variable '%s'" " RealValue '%s' ExpectedValue '%s'." % (key, output, kernelParameter[key])) elif (output.split() != kernelParameter[key].split() and key not in list(suggestParameterList.keys())): resultList.append(1) g_logger.log(" Abnormal reason: variable '%s'" " RealValue '%s' ExpectedValue '%s'." % (key, output, kernelParameter[key])) setParameterList[key] = kernelParameter[key] elif output.split() != kernelParameter[key].split(): if (key == "vm.overcommit_ratio"): cmd = "cat /proc/sys/vm/overcommit_memory" (status, value) = subprocess.getstatusoutput(cmd) if (status == 0 and value == "0"): continue resultList.append(2) g_logger.log(" Warning reason: variable '%s' RealValue" " '%s' ExpectedValue '%s'." % (key, output, kernelParameter[key])) else: resultList.append(1) g_logger.log(" Abnormal reason: Failed to obtain the OS " "kernel parameter [%s]. Error: \n %s" % (key, output)) setParameterList[key] = kernelParameter[key] if (1 in resultList and 'Check' in g_opts.action): g_logger.log(" %s failed." % g_opts.action) elif (2 in resultList and 'Check' in g_opts.action): g_logger.log(" %s warning." % g_opts.action) else: g_logger.log(" All values about system control" " parameters are correct: Normal") # set the OS parameters if isSet: setOSParameter(setParameterList, patchlevel) def setOSParameter(setParameterList, patchlevel): """ function: set os parameter input : setParameterList, patchlevel output : NA """ # The SuSE 11 SP1 operating system does not have # vm.extfrag_threshold parameter, skip set if ("vm.extfrag_threshold" in setParameterList and patchlevel == "1"): setParameterList.pop("vm.extfrag_threshold") if (len(setParameterList) != 0): g_logger.debug("Setting sysctl parameter.") for key in setParameterList: SetSysctlForList(key, setParameterList[key]) g_logger.log(" Set variable '%s' to '%s'" % (key, setParameterList[key])) cmd = "sysctl -p" (status, _) = subprocess.getstatusoutput(cmd) if (status != 0): cmderrorinfo = "sysctl -p | grep 'No such file or directory'" (status, outputresult) = subprocess.getstatusoutput(cmderrorinfo) if (status != 0 and outputresult == ""): g_logger.logExit(ErrorCode.GAUSS_514["GAUSS_51400"] % cmderrorinfo) for key in setParameterList: tmp = "/proc/sys/%s" % key.replace('.', '/') if (tmp in outputresult or key in outputresult): # delete the record about key from the /etc/sysctl.conf delSysctlForList(key, setParameterList[key]) g_logger.log(" Failed to enforce sysctl kernel" " variable '%s'. Error: the variable name" " is incorrect." % key) def SetSysctlForList(key, value): """ function: Set sysctl parameter input : key, value output: NA """ kernelParameterFile = "/etc/sysctl.conf" cmd = """sed -i '/^\\s*%s *=.*$/d' %s && echo %s = %s >> %s 2>/dev/null""" % (key, kernelParameterFile, key, value, kernelParameterFile) (status, output) = subprocess.getstatusoutput(cmd) if (status != 0): g_logger.log(" Failed to set variable '%s %s'." % (key, value)) g_logger.debug("Command:\n %s\nOutput:\n %s" % (cmd, str(output))) def delSysctlForList(key, value): """ function: delete the record about key from the /etc/sysctl.conf input: key, value output: NA """ g_logger.debug("Deleting sysctl parameter.") kernelParameterFile = "/etc/sysctl.conf" cmd = """sed -i '/^\\s*%s *=.*$/d' %s """ % (key, kernelParameterFile) (status, output) = subprocess.getstatusoutput(cmd) if (status != 0): g_logger.log(" Failed to delete variable" " '%s %s' from /etc/sysctl.conf." % (key, value)) g_logger.debug("Command:\n %s\nOutput:\n %s" % (cmd, str(output))) def checkLimitsParameter(limitPara, isSet): """ function: check and set the limit parameter input: limitPara, isSet output: NA """ # utility class for this function only class limitsconf_data: """ Class: limitsconf_data """ def __init__(self, expected): """ function: constructor """ self.domain = None self.value_found = None self.value_expected = expected # check the limit parameter table = dict() for key in list(limitPara.keys()): cmd = "ulimit -a | grep -F '%s' 2>/dev/null" % key (status, output) = subprocess.getstatusoutput(cmd) if (status == 0): resLines = output.split('\n') resList = resLines[0].split(' ') limitValue = resList[-1].strip() if (limitPara[key] == 'unlimited'): resultList.append(2) if limitValue != 'unlimited': g_logger.log(" Warning reason: variable '%s'" " RealValue '%s' ExpectedValue '%s'" % (key, limitValue, limitPara[key])) if (key == 'virtual memory'): table[('soft', 'as')] = limitsconf_data(limitPara[key]) table[('hard', 'as')] = limitsconf_data(limitPara[key]) if (key == 'max user processes'): table[('soft', 'nproc')] = limitsconf_data(limitPara[key]) table[('hard', 'nproc')] = limitsconf_data(limitPara[key]) elif (limitPara[key] != 'unlimited'): if (limitValue == 'unlimited'): continue if (int(limitValue) < int(limitPara[key])): if (key == "stack size"): resultList.append(1) g_logger.log(" Abnormal reason: variable '%s'" " RealValue '%s' ExpectedValue '%s'" % (key, limitValue, limitPara[key])) else: resultList.append(2) g_logger.log(" Warning reason: variable '%s'" " RealValue '%s' ExpectedValue '%s'" % (key, limitValue, limitPara[key])) if (key == 'stack size'): table[('soft', 'stack')] = limitsconf_data(limitPara[key]) table[('hard', 'stack')] = limitsconf_data(limitPara[key]) if (key == 'open files'): table[('soft', 'nofile')] = limitsconf_data(limitPara[key]) table[('hard', 'nofile')] = limitsconf_data(limitPara[key]) else: resultList.append(1) g_logger.debug("The cmd is %s " % cmd) g_logger.log(" Failed to obtain '%s'. Error: \n%s" % (key, output)) # set the open file numbers if isSet and len(list(table.keys())): for key in list(table.keys()): if (key[1] == "nofile" or key[1] == "nproc"): limitPath = '/etc/security/limits.d/' nofiles = glob.glob("/etc/security/limits.d/*.conf") for conf in nofiles: FileUtil.changeMode(DefaultValue.HOSTS_FILE, conf) SetLimitsConf(key[0], key[1], table[key].value_expected, conf) if os.path.isfile(os.path.join(limitPath, '91-nofile.conf')): limitFile = '91-nofile.conf' else: limitFile = '90-nofile.conf' if (key[1] == "stack" or key[1] == "as" or key[1] == "nproc"): limitPath = '/etc/security/' limitFile = 'limits.conf' if (checkLimitFile(limitPath, limitFile) != 0): return SetLimitsConf(key[0], key[1], table[key].value_expected, limitPath + limitFile) g_logger.log(" Set variable '%s %s' to '%s'" % (key[0], key[1], table[key].value_expected)) def checkLimitFile(limitPath, limitFile): """ function: check limits file input : limitPath, limitFile output: status """ g_logger.debug("check limits configuration file.") pathCmd = "if [ ! -d '%s' ]; then mkdir '%s' -m %s;fi; cd '%s';" \ % (limitPath, limitPath, DefaultValue.MAX_DIRECTORY_MODE, limitPath) pathCmd += "if [ ! -f '%s' ]; then touch '%s';chmod %s '%s';fi" \ % (limitFile, limitFile, DefaultValue.FILE_MODE, limitFile) (status, output) = subprocess.getstatusoutput(pathCmd) if (status != 0): g_logger.debug("The cmd is %s " % pathCmd) g_logger.log(" Abnormal reason: Failed to create %s%s." " Error: \n%s" % (limitPath, limitFile, output)) return status def SetLimitsConf(typename, item, value, limitfile): """ function: write the /etc/security/limits.conf input: typename, item, value, limitfile output: NA """ g_logger.debug("Setting limits config.") clusterUser = getClusterUser() cmd = """sed -i '/^.* %s *%s .*$/d' %s && echo "root %s %s %s" >> %s && """ \ % (typename, item, limitfile, typename, item, value, limitfile) cmd += """echo "%s %s %s %s" >> %s""" \ % (clusterUser, typename, item, value, limitfile) (status, output) = subprocess.getstatusoutput(cmd) if (status != 0): g_logger.debug("The cmd is %s " % cmd) g_logger.log(" Abnormal reason: Failed to set variable" " '%s %s'. Error: \n%s" % (typename, item, output)) def getGphome(xmlFilePath): """ function: Get GPHOME path input : xmlFilePath output: str """ gphome = "" if os.path.exists(xmlFilePath): with open(xmlFilePath, 'r') as fp: xmlstr = fp.read() domTree = ETree.fromstring(xmlstr) rootNode = domTree if not rootNode.findall('CLUSTER'): raise Exception(ErrorCode.GAUSS_512["GAUSS_51200"] % 'CLUSTER') element = rootNode.findall('CLUSTER')[0] nodeArray = element.findall('PARAM') for node in nodeArray: name = node.attrib['name'] if (name == "gaussdbToolPath"): gphome = str(node.attrib['value']) return gphome def getClusterUser(): """ function: Check user information input : NA output: str """ # get user and group gphome = getGphome(g_opts.confFile) if not gphome or not os.path.exists(gphome): user = "*" return user user = UserUtil.getPathOwner(gphome)[0] return user def CheckSection(section, isSetting=False): """ function: check the section parameters status input: section, isSetting output: NA """ global configFile dirName = os.path.dirname(os.path.realpath(__file__)) configFile = "%s/../gspylib/etc/conf/check_list.conf" % dirName # get the parameter and value about section from configuration file if (section == '/etc/security/limits.conf'): checkList = ['open files', 'pipe size'] commParameterList = ConfigParam.getConfigFilePara(configFile, section, checkList) else: commParameterList = ConfigParam.getConfigFilePara(configFile, section) # checking or setting the parameter what in the commParameterList checkSpecifiedItems(section, commParameterList, isSetting) def parseCommandLine(): """ function: Parse command line and save to global variables input : NA output: NA """ try: # Resolves the command line opts, args = getopt.getopt(sys.argv[1:], "t:X:l:U:V?", ["help", "log-file=", "xmlfile=", "MTUvalue=", "hostname=", "check-os", "version"]) except Exception as e: usage() GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50000"] % str(e)) if (len(args) > 0): GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50000"] % str(args[0])) global g_opts global g_check_os g_opts = CmdOptions() # Output help information and exit for (key, value) in opts: if (key == "-?" or key == "--help"): usage() sys.exit(0) elif (key == "-V" or key == "--version"): print(("%s %s" % (sys.argv[0].split("/")[-1], VersionInfo.COMMON_VERSION))) sys.exit(0) elif (key == "-t"): g_opts.action = value elif (key == "-U"): g_opts.user = value elif (key == "--check-os"): g_check_os = True elif (key == "-l" or key == "--log-file"): g_opts.logFile = os.path.realpath(value) elif (key == "--MTUvalue"): g_opts.mtuValue = value elif (key == "--hostname"): g_opts.hostname = value elif (key == "-X"): g_opts.confFile = value # check para vaild Parameter.checkParaVaild(key, value) def checkParameter(): """ function: check parameter for different action input : NA output: NA """ # check if user exist and is the right user if (g_opts.user != ''): ClusterUser.checkUser(g_opts.user) tmpDir = EnvUtil.getTmpDirFromEnv(g_opts.user) if (not os.path.exists(tmpDir)): GaussLog.exitWithError(ErrorCode.GAUSS_502["GAUSS_50201"] % ("temporary directory[" + tmpDir + "]")) # check the -t parameter if (g_opts.action == ""): GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50001"] % 't' + '.') if (g_opts.action not in list(actioItemMap.keys())): GaussLog.exitWithError(ErrorCode.GAUSS_500["GAUSS_50004"] % "t") if (g_opts.logFile == ""): dirName = os.path.dirname(os.path.realpath(__file__)) g_opts.logFile = os.path.join(dirName, "gaussdb_localcheck.log") def initGlobals(): """ function: Init global log input : NA output: NA """ # state global variable global g_logger global g_clusterInfo # Init the log file g_logger = GaussLog(g_opts.logFile, "gaussdb_localcheck") if os.path.exists(g_opts.confFile): g_clusterInfo = dbClusterInfo() g_clusterInfo.initFromXml(g_opts.confFile) def setLocalReservedPort(): """ function: Set local reserved port in check_list.conf input : NA output: NA """ portList = [] rportList = [] portStr = "" checkListfile = "%s/../gspylib/etc/conf/check_list.conf" \ % os.path.dirname(os.path.realpath(__file__)) if g_clusterInfo is not None: for dbNode in g_clusterInfo.dbNodes: for cn in dbNode.coordinators: if cn.port not in portList: portList.append(cn.port) if cn.haPort != "" and cn.haPort != (int(cn.port) + 1): if cn.haPort not in portList: portList.append(cn.haPort) for dn in dbNode.datanodes: if dn.port not in portList: portList.append(dn.port) if dn.haPort != "" and dn.haPort != (int(dn.port) + 1): if dn.haPort not in portList: portList.append(dn.haPort) for cm in dbNode.cmservers: if cm.port not in portList: portList.append(cm.port) if cm.haPort != "" and cm.haPort != (int(cm.port) + 1): if cm.haPort not in portList: portList.append(cm.haPort) for gtm in dbNode.gtms: if gtm.port not in portList: portList.append(gtm.port) if gtm.haPort != "" and gtm.haPort != (int(gtm.port) + 1): if gtm.haPort not in portList: portList.append(gtm.haPort) for etcd in dbNode.etcds: if etcd.port not in portList: portList.append(etcd.port) if etcd.haPort != "" and etcd.haPort != (int(etcd.port) + 1): if etcd.haPort not in portList: portList.append(etcd.haPort) if 20050 not in portList: portList.append(20050) sortedPortList = sorted(portList) for port in sortedPortList: localPortList = [] nport = port while nport <= port + 7: if len(rportList) != 0 and port <= max(rportList[-1]) + 1: if nport not in rportList[-1]: rportList[-1].append(nport) else: if nport not in localPortList: localPortList.append(nport) nport += 1 if len(localPortList) != 0: rportList.append(localPortList) for rport in rportList: if rport == rportList[-1]: portStr += "%s-%s" % (min(rport), max(rport)) else: portStr += "%s-%s," % (min(rport), max(rport)) cmd = "sed -i '/%s/d' %s && sed -i '/%s/a\%s = %s' %s " % \ ("ipv4.ip_local_reserved_ports", checkListfile, "tcp_retries2", "net.ipv4.ip_local_reserved_ports", portStr, checkListfile) (status, output) = subprocess.getstatusoutput(cmd) if status != 0: raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + "Error:\n%s" % str(output)) def doLocalCheck(): """ function: check OS item on local node input : NA output: NA """ global resultList global netWorkBondInfo netWorkBondInfo = netWork() if (g_opts.action == "osKernelParameterCheck"): CheckSection(actioItemMap["Check_FileSystem_Configure"][0], actioItemMap["Check_FileSystem_Configure"][1]) CheckSection(actioItemMap["Check_SysCtl_Parameter"][0], actioItemMap["Check_SysCtl_Parameter"][1]) else: CheckSection(actioItemMap[g_opts.action][0], actioItemMap[g_opts.action][1]) # checkItemMap is a dictionary of global variable # checkItemMap.keys() is configuration file's section # checkItemMap[key][0] is the check function about the key # checkItemMap[key][1] is the parameter of the check function checkItemMap = {'/etc/sysctl.conf': [checkSysctlParameter, (paraList, g_check_os)], '/etc/security/limits.conf': [checkLimitsParameter, (paraList, g_check_os)] } if __name__ == '__main__': """ main function """ try: # parse cmd lines parseCommandLine() # check Parameter checkParameter() # init globals initGlobals() setLocalReservedPort() # check OS item on local node doLocalCheck() except Exception as e: GaussLog.exitWithError(str(e)) finally: # close log file g_logger.closeLog() sys.exit(0)