#!/usr/bin/env python3
# -*- coding:utf-8 -*-
try:
    import sys
    import importlib

    importlib.reload(sys)
    import os
    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))

DIRECTORY_MODE = 750
g_result = []
g_chList = []


class CheckDirPermissions(BaseItem):
    def __init__(self):
        super(CheckDirPermissions, 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
        dataDirList = []
        # Get the DN instance and the longest DN path
        for inst in nodeInfo.datanodes:
            dataDirList.append(inst.datadir)
            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:
            dataDirList.append(inst.datadir)
            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:
            dataDirList.append(inst.datadir)
            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:
            dataDirList.append(inst.datadir)
            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:
            dataDirList.append(inst.datadir)
            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:
                dataDirList.append(inst.datadir)
                if (len(inst.datadir) > DirLength):
                    DirLength = len(inst.datadir)

        return (DirLength, dataDirList)

    def checkDirWriteable(self, dirPath, user, flag=""):
        """
        function : Check if target directory is writeable for user.
        input : String,String
        output : boolean
        """
        return os.access(dirPath, os.W_OK)

    def checkSingleDirectoryPermission(self, singledir, desc, INDENTATION_VALUE_INT):
        """
        function: Check Directory Permissions
        input: String, String, int
        output: int
        """
        # The directory must be a folder
        if (not os.path.isdir(singledir)):
            g_result.append(
                "%s: Abnormal reason: Directory does not exist." % ("%s directory(%s)" % (desc, singledir)).ljust(
                    INDENTATION_VALUE_INT))
            return -1
        # Gets the folder permissions
        currentPremission = int(g_file.getPermission(singledir))
        # Gets the standard folder permissions
        normalPremission = DIRECTORY_MODE
        # Check the write access and compare the permission size
        if (self.checkDirWriteable(singledir, self.user) and currentPremission <= normalPremission):

            g_result.append(
                "%s: Normal" % ("%s directory(%s) permissions %s" % (desc, singledir, str(currentPremission))).ljust(
                    INDENTATION_VALUE_INT))
            return 0
        elif (currentPremission > normalPremission):
            g_result.append("%s: Abnormal reason: Directory permission can not exceed 750." % (
                ("%s directory(%s) permissions %s" % (desc, singledir, str(currentPremission))).ljust(
                    INDENTATION_VALUE_INT)))
            return -1
        else:
            g_result.append("%s: Abnormal reason: Directory is not writable for users." % (
                    "%s directory(%s) permissions %s" % (desc, singledir, str(currentPremission))).ljust(
                INDENTATION_VALUE_INT))
            return -1

    def doCheck(self):
        global g_chList
        global g_result
        resultList = []
        g_result = []
        nodeInfo = self.cluster.getDbNodeByName(self.host)
        tmpDir = os.getenv("PGHOST")
        logDir = os.getenv("GAUSSLOG")
        toolDir = os.getenv("GPHOME")
        (intervalLen, _) = self.obtainDataDirLength(nodeInfo)
        if intervalLen < len(self.cluster.appPath):
            intervalLen = len(self.cluster.appPath)
        if intervalLen < len(logDir):
            intervalLen = len(logDir)
        INDENTATION_VALUE_INT = intervalLen + 44
        # Check the permission for app path/temp path/log path/tool path
        path_dict = {"AppPath": self.cluster.appPath, "Tmp": tmpDir, "Log": logDir, "ToolPath": toolDir}
        for path in path_dict:
            resultList.append(self.checkSingleDirectoryPermission(path_dict.get(path), path, INDENTATION_VALUE_INT))
            g_chList.append(path_dict.get(path))
        # Check the permissions for all CMserver
        for inst in nodeInfo.cmservers:
            resultList.append(self.checkSingleDirectoryPermission(inst.datadir, "CM server", INDENTATION_VALUE_INT))
            g_chList.append(inst.datadir)
        # Check the permissions for all CMagent
        for inst in nodeInfo.cmagents:
            resultList.append(self.checkSingleDirectoryPermission(inst.datadir, "CM agent", INDENTATION_VALUE_INT))
            g_chList.append(inst.datadir)
        # Check the permissions for all CN instance
        for inst in nodeInfo.coordinators:
            resultList.append(self.checkSingleDirectoryPermission(inst.datadir, "CN", INDENTATION_VALUE_INT))
            # Check the xlog permissions for all CN instance
            xlogDir = "%s/pg_xlog" % inst.datadir
            resultList.append(self.checkSingleDirectoryPermission(xlogDir, "CN Xlog", INDENTATION_VALUE_INT))
            g_chList.append(inst.datadir)
            g_chList.append(xlogDir)
        # Check the permissions for all DN instance
        for inst in nodeInfo.datanodes:
            resultList.append(self.checkSingleDirectoryPermission(inst.datadir, "DN", INDENTATION_VALUE_INT))
            # Check the xlog permissions for all DN instance
            xlogDir = "%s/pg_xlog" % inst.datadir
            resultList.append(self.checkSingleDirectoryPermission(xlogDir, "DN Xlog", INDENTATION_VALUE_INT))
            g_chList.append(inst.datadir)
            g_chList.append(xlogDir)
        # Check the permissions for all GTM instance
        for inst in nodeInfo.gtms:
            resultList.append(self.checkSingleDirectoryPermission(inst.datadir, "GTM", INDENTATION_VALUE_INT))
            g_chList.append(inst.datadir)
        # Check the permissions for all ETCD instance
        if hasattr(nodeInfo, 'etcds'):
            for inst in nodeInfo.etcds:
                resultList.append(self.checkSingleDirectoryPermission(inst.datadir, "ETCD", INDENTATION_VALUE_INT))
                g_chList.append(inst.datadir)
        if -1 in resultList:
            self.result.rst = ResultStatus.NG
        else:
            self.result.rst = ResultStatus.OK
        self.result.val = "\n".join(g_result) + "\n"

    def doSet(self):
        for dirName in g_chList:
            g_file.changeOwner(self.user, dirName, True)
            g_file.changeMode(DIRECTORY_MODE, dirName)
        self.result.val = "Set DirPermissions completely."
