#!/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 '/^.*root * %s *%s .*$/d' %s &&
           echo "root       %s    %s  %s" >> %s ; """ \
          % (typename, item, limitfile, typename, item, value, limitfile)
    if clusterUser.strip() == "*":
        cmd += """sed -i '/^.*\%s * %s *%s .*$/d' %s &&
                echo "%s       %s    %s  %s" >> %s""" \
            % (clusterUser, typename, item, limitfile, clusterUser, typename, item, value, limitfile)
    else:
        cmd += """sed -i '/^.*%s * %s *%s .*$/d' %s &&
                    echo "%s       %s    %s  %s" >> %s""" \
            % (clusterUser, typename, item, limitfile, 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)
        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)
