#!/usr/bin/env python3
#-*- coding:utf-8 -*-
try:
    import sys
    import importlib
    importlib.reload(sys)
    import subprocess
    from gspylib.inspection.common import SharedFuncs
    from gspylib.inspection.common.CheckItem import BaseItem
    from gspylib.inspection.common.CheckResult import ResultStatus
except ImportError as ie:
    raise Exception("[GAUSS-52200] : Unable to import module: %s." % str(ie))

# master
MASTER_INSTANCE = 0
# standby
STANDBY_INSTANCE = 1
# dummy standby
DUMMY_STANDBY_INSTANCE = 2

# cn
INSTANCE_ROLE_COODINATOR = 3
# dn
INSTANCE_ROLE_DATANODE = 4

g_gucDist = {}
RecommendedMaxMem = 0


class CheckMaxProcMemory(BaseItem):
    def __init__(self):
        super(CheckMaxProcMemory, self).__init__(self.__class__.__name__)
        self.Threshold_NG = None

    def preCheck(self):
        super(CheckMaxProcMemory, self).preCheck()
        # check the threshold was set correctly
        if (not self.threshold.__contains__('Threshold_NG')):
            raise Exception("The threshold Threshold_NG can not be empty.")
        if (not self.threshold['Threshold_NG'].isdigit()):
            raise Exception("The threshold Threshold_NG  must be integer.")
        self.Threshold_NG = int(self.threshold['Threshold_NG'])

    def checkInstanceGucValue(self, Instance):
        """
        get CN/DN instance guc parameters
        """
        global g_gucDist
        Role = ""
        needm = False
        if (Instance.instanceRole == INSTANCE_ROLE_COODINATOR):
            needm = False
        elif(self.checkMaster(Instance.instanceId)):
            needm = False
        else:
            needm = True
        sqlcmd = "select setting from pg_catalog.pg_settings where name='max_process_memory';"
        output = SharedFuncs.runSqlCmd(sqlcmd, self.user, "", Instance.port, self.tmpPath, "postgres", self.mpprcFile,
                                       needm)
        if (Instance.instanceRole == INSTANCE_ROLE_COODINATOR):
            Role = "CN"
        elif (Instance.instanceRole == INSTANCE_ROLE_DATANODE):
            Role = "DN"
        instanceName = "%s_%s" % (Role, Instance.instanceId)
        g_gucDist[instanceName] = output

    def checkMaster(self, instanceId):
        cmd = "cm_ctl query -Cv |grep %s" % (instanceId)
        output = SharedFuncs.runShellCmd(cmd, self.user, self.mpprcFile)
        line = output.splitlines()[0]
        instanceinfo = line.split()
        for idx in range(len(instanceinfo)):
            if(instanceinfo[idx] == str(instanceId)):
                if(instanceinfo[idx + 2] == "Primary"):
                    return True
                else:
                    return False
        return False

    def doCheck(self):
        """

        """
        global g_gucDist
        global RecommendedMaxMem
        DNidList = []
        nodeInfo = self.cluster.getDbNodeByName(self.host)
        CN = nodeInfo.coordinators
        for DnInstance in nodeInfo.datanodes:
            if (self.checkMaster(DnInstance.instanceId)):
                DNidList.append(DnInstance)
        if (len(CN) < 1 and len(DNidList) < 1):
            self.result.rst = ResultStatus.NA
            self.result.val = "NA"
            return

        # test database Connection
        for Instance in (CN + DNidList):
            if not Instance:
                continue
            sqlcmd = "select pg_catalog.pg_sleep(1);"
            SharedFuncs.runSqlCmd(sqlcmd, self.user, "", Instance.port, self.tmpPath, 'postgres',
                                           self.mpprcFile)
            self.checkInstanceGucValue(Instance)
        cmd = "/sbin/sysctl -a |grep vm.min_free_kbytes|awk '{print $3}'"
        min_free_kbytes = int(SharedFuncs.runShellCmd(cmd).splitlines()[-1])
        cmd = "free -k | grep 'Mem'| grep -v 'grep'|awk '{print $2}'"
        raw = int(SharedFuncs.runShellCmd(cmd))
        if(min_free_kbytes * 100 > raw * 5):
            RecommendedMaxMem = int((raw * 0.7) // (len(DNidList) + 1))
        else:
            RecommendedMaxMem = int((raw * 0.8) // (len(DNidList) + 1))
        self.result.rst = ResultStatus.OK
        result = "RecommendedMaxMem is %s\n" % RecommendedMaxMem
        for key, value in g_gucDist.items():
            if(int(value) > RecommendedMaxMem):
                self.result.rst = ResultStatus.NG
                result += "%s : %s\n" % (key, value)
        if(self.result.rst == ResultStatus.OK):
            self.result.val = "parameter max_process_memory setting is ok"
        else:
            self.result.val = "parameter max_process_memory setting should not be bigger than recommended(kb):%s:\n%s"\
                              % (RecommendedMaxMem, result)

    def doSet(self):
        resultStr = ""
        cmd = "su - %s -c \"source %s;gs_guc set -Z coordinator -N all -I all -c 'max_process_memory=%s'\""\
              % (self.user, self.mpprcFile, RecommendedMaxMem)
        (status, output) = subprocess.getstatusoutput(cmd)
        if (status != 0):
            resultStr += "Set CN instance Filed.\n Error : %s." % output
        cmd = "su - %s -c \"source %s;gs_guc set -Z datanode -N all -I all -c 'max_process_memory=%s'\""\
              % (self.user, self.mpprcFile, RecommendedMaxMem)
        (status, output) = subprocess.getstatusoutput(cmd)
        if (status != 0):
            resultStr += "Set DN instance Filed.\n Error : %s." % output
        if len(resultStr) > 0:
            self.result.val = resultStr
        else:
            self.result.val = "Set max_process_memory successfully."
