#!/usr/bin/env python3
# -*- coding:utf-8 -*-

try:
    import sys
    import importlib

    importlib.reload(sys)
    import os
    import subprocess
    from gspylib.inspection.common.CheckItem import BaseItem
    from gspylib.inspection.common.CheckResult import ResultStatus
    from gspylib.os.gsfile import g_file
except ImportError as ie:
    raise Exception("[GAUSS-52200] : Unable to import module: %s." % str(ie))

# Conf file name constant
GTM_CONF = "gtm.conf"
POSTGRESQL_CONF = "postgresql.conf"
CM_CONF = "cm.conf"
INSTANCE_ROLE_CMSERVER = 0
INSTANCE_ROLE_CMAGENT = 5
INSTANCE_ROLE_GTM = 1
INSTANCE_ROLE_COODINATOR = 3
INSTANCE_ROLE_DATANODE = 4
g_result = []


class CheckDebugSwitch(BaseItem):
    def __init__(self):
        super(CheckDebugSwitch, self).__init__(self.__class__.__name__)

    def obtainDataDirLength(self, nodeInfo):
        """
        function: Obtain data dir length
        input: NA
        output: int, list
        """
        # Get the longest path
        DirLength = 0
        # Get the DN instance and the longest DN path
        for inst in nodeInfo.datanodes:
            if len(inst.datadir) > DirLength:
                DirLength = len(inst.datadir)
        # Get the CMserver instance and longest path in the CMserver, DN
        for inst in nodeInfo.cmservers:
            if len(inst.datadir) > DirLength:
                DirLength = len(inst.datadir)
        # Get the CMagent instance and longest path in the CM, DN
        for inst in nodeInfo.cmagents:
            if len(inst.datadir) > DirLength:
                DirLength = len(inst.datadir)
        # Get the CN instance and longest path in the CM, DN, CN
        for inst in nodeInfo.coordinators:
            if len(inst.datadir) > DirLength:
                DirLength = len(inst.datadir)
        # Get the GTM instance and longest path in the CM, DN, CN, GTM
        for inst in nodeInfo.gtms:
            if len(inst.datadir) > DirLength:
                DirLength = len(inst.datadir)
        # Get the ETCD instance and longest path in the all instance
        if hasattr(nodeInfo, 'etcds'):
            for inst in nodeInfo.etcds:
                if len(inst.datadir) > DirLength:
                    DirLength = len(inst.datadir)

        return DirLength

    def checkSingleParaFile(self, inst, desc, INDENTATION_VALUE_INT):
        """
        function: Check the log_min_messages parameter for each instance
        input: String, String, int
        output: int
        """
        # The instance directory must exist
        if not os.path.exists(inst.datadir) or len(os.listdir(inst.datadir)) == 0:
            g_result.append("%s: Abnormal reason: The directory doesn't exist or is empty." % (
                    "%s(%s) log_min_messages parameter" % (desc, inst.datadir)).ljust(INDENTATION_VALUE_INT))
            return -1
        # Gets the CMserver configuration file
        if inst.instanceRole == INSTANCE_ROLE_CMSERVER:
            dataPath = inst.datadir
            if dataPath != "" and dataPath.endswith('/'):
                dataPath = dataPath[:-1]
            paraPath = os.path.join(os.path.dirname(dataPath), "cm_agent/cm.conf")
        # Gets the CMagent configuration file
        elif inst.instanceRole == INSTANCE_ROLE_CMAGENT:
            paraPath = os.path.join(inst.datadir, CM_CONF)
        # Gets the GTM configuration file
        elif inst.instanceRole == INSTANCE_ROLE_GTM:
            paraPath = os.path.join(inst.datadir, GTM_CONF)
        # Gets the CN configuration file
        elif inst.instanceRole == INSTANCE_ROLE_COODINATOR:
            paraPath = os.path.join(inst.datadir, POSTGRESQL_CONF)
        # Gets the DN configuration file
        elif inst.instanceRole == INSTANCE_ROLE_DATANODE:
            paraPath = os.path.join(inst.datadir, POSTGRESQL_CONF)
        else:
            g_result.append("%s: Abnormal reason: Invalid instance type: %s." % (
                ("%s(%s) log_min_messages parameter " % (desc, inst.datadir)).ljust(INDENTATION_VALUE_INT),
                inst.instanceRole))
            return - 1
        # The instance configuration file must exist
        if not os.path.exists(paraPath):
            g_result.append("%s: Abnormal reason: %s does not exist." % (
                ("%s(%s) log_min_messages parameter " % (desc, inst.datadir)).ljust(INDENTATION_VALUE_INT), paraPath))
            return -1
        # Gets the log_min_messages parameter in the configuration file
        output = g_file.readFile(paraPath, "log_min_messages")
        value = None
        for line in output:
            line = line.split('#')[0].strip()
            if line.find('log_min_messages') >= 0 and line.find('=') > 0:
                value = line.split('=')[1].strip()
                break
        if not value:
            value = "warning"
        # Determines whether the log_min_messages parameter is valid
        if value.lower() != "warning":
            g_result.append(
                "%s: Warning reason: The parameter 'log_min_messages(%s)' value is incorrect. "
                "It should be 'warning'." % (("%s(%s) log_min_messages parameter(%s)"
                                              % (desc, paraPath, value)).ljust(INDENTATION_VALUE_INT), value))
            return -1
        g_result.append("%s: Normal" % ("%s(%s) log_min_messages parameter(%s)" % (desc, paraPath, value)).ljust(
            INDENTATION_VALUE_INT))
        return 0

    def doCheck(self):
        global g_result
        g_result = []
        nodeInfo = self.cluster.getDbNodeByName(self.host)
        intervalLen = self.obtainDataDirLength(nodeInfo)
        resultList = []
        self.result.val = ""
        INDENTATION_VALUE_INT = intervalLen + 64
        # Check all CMserver debug switch
        for inst in nodeInfo.cmservers:
            resultList.append(self.checkSingleParaFile(inst, "CM server", INDENTATION_VALUE_INT))
        # Check all CMagent debug switch
        for inst in nodeInfo.cmagents:
            resultList.append(self.checkSingleParaFile(inst, "CM agent", INDENTATION_VALUE_INT))
            # Check all CN instance debug switch
        for inst in nodeInfo.coordinators:
            resultList.append(self.checkSingleParaFile(inst, "CN", INDENTATION_VALUE_INT))
            # Check all DN instance debug switch
        for inst in nodeInfo.datanodes:
            resultList.append(self.checkSingleParaFile(inst, "DN", INDENTATION_VALUE_INT))
            # Check all GTM instance debug switch
        for inst in nodeInfo.gtms:
            resultList.append(self.checkSingleParaFile(inst, "GTM", INDENTATION_VALUE_INT))
        if -1 in resultList:
            self.result.rst = ResultStatus.WARNING
        else:
            self.result.rst = ResultStatus.OK
        for detail in g_result:
            self.result.val = '%s%s\n' % (self.result.val, detail)

    def doSet(self):
        nodeInfo = self.cluster.getDbNodeByName(self.host)
        intervalLen = self.obtainDataDirLength(nodeInfo)
        resultStr = ""
        INDENTATION_VALUE_INT = intervalLen + 64
        for inst in nodeInfo.coordinators:
            flag = self.checkSingleParaFile(inst, "CN", INDENTATION_VALUE_INT)
            if flag == -1:
                cmd = "gs_guc set -N all -I all -Z coordinator -c 'log_min_messages = warning'"
                (status, output) = subprocess.getstatusoutput(cmd)
                if status != 0:
                    resultStr += "Falied to set cn log_min_massages.\n Error : %s" % output
        for inst in nodeInfo.datanodes:
            flag = self.checkSingleParaFile(inst, "DN", INDENTATION_VALUE_INT)
            if flag == -1:
                cmd = "gs_guc set -N all -I all -Z datanode -c 'log_min_messages = warning'"
                (status, output) = subprocess.getstatusoutput(cmd)
                if (status != 0):
                    resultStr += "Falied to set dn log_min_massages.\n Error : %s" % output
        if len(resultStr) > 0:
            self.result.val = resultStr
        else:
            self.result.val = "Set log_min_messages successfully."
