# -*- 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.
# ----------------------------------------------------------------------------

import psutil
from gspylib.common.ErrorCode import ErrorCode
from gspylib.inspection.common import SharedFuncs
from gspylib.inspection.common.CheckItem import BaseItem
from gspylib.inspection.common.CheckResult import ResultStatus
from base_utils.os.disk_util import DiskUtil
from base_utils.os.env_util import EnvUtil


class CheckSpaceUsage(BaseItem):
    def __init__(self):
        super(CheckSpaceUsage, self).__init__(self.__class__.__name__)
        self.diskVailPGHOST = None
        self.diskVailGPHOME = None
        self.diskVailGAUSSHOME = None
        self.diskVailGAUSSLOG = None
        self.diskVailOS_TMP = None
        self.diskVailDATA = None
        self.Threshold_NG = None
        self.Threshold_Warning = None

    def preCheck(self):
        # check current node contains cn instances if not raise  exception
        super(CheckSpaceUsage, self).preCheck()
        # check the threshold was set correctly
        if (not self.threshold.__contains__('DiskVailPGHOST')):
            raise Exception(ErrorCode.GAUSS_530["GAUSS_53013"]
                            % "threshold  DiskVailPGHOST")
        if (not self.threshold.__contains__('DiskVailGPHOME')):
            raise Exception(ErrorCode.GAUSS_530["GAUSS_53013"]
                            % "threshold DiskVailGPHOME")
        if (not self.threshold.__contains__('DiskVailGAUSSHOME')):
            raise Exception(ErrorCode.GAUSS_530["GAUSS_53013"]
                            % "threshold DiskVailGAUSSHOME")
        if (not self.threshold.__contains__('DiskVailGAUSSLOG')):
            raise Exception(ErrorCode.GAUSS_530["GAUSS_53013"]
                            % "threshold DiskVailGAUSSLOG")
        if (not self.threshold.__contains__('DiskVailOS_TMP')):
            raise Exception(ErrorCode.GAUSS_530["GAUSS_53013"]
                            % "threshold DiskVailOS_TMP")
        if (not self.threshold.__contains__('DiskVailDATA')):
            raise Exception(ErrorCode.GAUSS_530["GAUSS_53013"]
                            % "threshold DiskVailDATA")

        if (not (self.threshold.__contains__('Threshold_NG') and
                 self.threshold.__contains__('Threshold_Warning'))):
            raise Exception(ErrorCode.GAUSS_530["GAUSS_53013"] %
                            "The threshold Threshold_NG and Threshold_Warning")
        if (not self.threshold['Threshold_NG'].isdigit() or
                not self.threshold['Threshold_Warning'].isdigit()):
            raise Exception(ErrorCode.GAUSS_530["GAUSS_53013"] %
                            "The threshold Threshold_NG and Threshold_Warning")
        self.Threshold_NG = int(self.threshold['Threshold_NG'])
        self.Threshold_Warning = int(self.threshold['Threshold_Warning'])
        if (self.Threshold_NG < self.Threshold_Warning):
            raise Exception(ErrorCode.GAUSS_530["GAUSS_53015"]
                            % (self.Threshold_NG, self.Threshold_Warning))
        if (self.Threshold_NG > 99 or self.Threshold_Warning < 1):
            raise Exception(ErrorCode.GAUSS_530["GAUSS_53016"]
                            % (self.Threshold_NG, self.Threshold_Warning))

        self.diskVailPGHOST = self.threshold['DiskVailPGHOST']
        self.diskVailGPHOME = self.threshold['DiskVailGPHOME']
        self.diskVailGAUSSHOME = self.threshold['DiskVailGAUSSHOME']
        self.diskVailGAUSSLOG = self.threshold['DiskVailGAUSSLOG']
        self.diskVailOS_TMP = self.threshold['DiskVailOS_TMP']
        self.diskVailDATA = self.threshold['DiskVailDATA']

    def obtainDataDir(self, nodeInfo):
        dataDirList = {}
        dataDirList[EnvUtil.getEnv("PGHOST")] = ["PGHOST",
                                                      self.diskVailPGHOST]
        dataDirList[EnvUtil.getEnv("GPHOME")] = ["GPHOME",
                                                      self.diskVailGPHOME]
        dataDirList[EnvUtil.getEnv("GAUSSHOME")] = \
            ["GAUSSHOME", self.diskVailGAUSSHOME]
        dataDirList[EnvUtil.getEnv("GAUSSLOG")] = ["GAUSSLOG",
                                                        self.diskVailGAUSSLOG]
        dataDirList["/tmp"] = ["OS_TMP", self.diskVailOS_TMP]
        for inst in nodeInfo.datanodes:
            dataDirList[inst.datadir] = ["DN", self.diskVailDATA]

        return dataDirList

    def obtainDiskDir(self):
        cmd = "df -h -P | awk '{print $NF}'"
        output = SharedFuncs.runShellCmd(cmd)
        allDiskPath = output.split('\n')[1:]
        return allDiskPath

    def doCheck(self):
        flag = "Normal"
        resultStr = ""
        DiskList = []
        DiskInfoDict = {}
        pathDisk = {}
        if (self.cluster):
            pathDisk = self.obtainDataDir(
                self.cluster.getDbNodeByName(self.host))
            pathList = pathDisk.keys()
        else:
            pathList = self.obtainDiskDir()
        for path in pathList:
            diskName = DiskUtil.getMountPathByDataDir(path)
            usageInfo = DiskUtil.getDiskSpaceUsage(path)
            diskInfo = "%s %s%%" % (diskName, usageInfo)
            if (diskName in DiskList):
                continue
            else:
                DiskList.append(diskName)
            DiskInfoDict[usageInfo] = diskInfo
            rateNum = usageInfo
            if (rateNum > self.Threshold_NG):
                resultStr += \
                    "The usage of the device disk space[%s:%d%%] " \
                    "cannot be greater than %d%%.\n" % (
                        diskName, rateNum, self.Threshold_NG)
                flag = "Error"
            elif (rateNum > self.Threshold_Warning):
                resultStr += \
                    "The usage of the device disk space[%s:%d%%] " \
                    "cannot be greater than %d%%.\n" % (
                        diskName, rateNum, self.Threshold_Warning)
                if (flag == "Normal"):
                    flag = "Warning"

            if (pathDisk):
                if (diskInfo):
                    AvailableSpace = psutil.disk_usage(
                        path).free // 1024 // 1024 // 1024
                    minSpace_KB = float(pathDisk[path][1])
                    if (AvailableSpace < minSpace_KB):
                        resultStr += \
                            "The %s path [%s] where" \
                            " the disk available space[%.1fGB] is less than" \
                            " %.1fGB.\n" % (
                                pathDisk[path][0], path, AvailableSpace,
                                minSpace_KB)
                        flag = "Error"
                else:
                    raise Exception(ErrorCode.GAUSS_504["GAUSS_50413"]
                                    + "Error:\n%s" % diskInfo)
        self.result.val = resultStr
        if (flag == "Normal"):
            self.result.rst = ResultStatus.OK
            self.result.val = "All disk space are sufficient.\n"
        elif (flag == "Warning"):
            self.result.rst = ResultStatus.WARNING
        else:
            self.result.rst = ResultStatus.NG

        keys = DiskInfoDict.keys()
        sortedKeys = sorted(keys)
        MaxDisk = list(map(DiskInfoDict.get, sortedKeys))[-1]
        MinDisk = list(map(DiskInfoDict.get, sortedKeys))[0]
        self.result.val += "\nDisk     Filesystem spaceUsage\nMax " \
                           "free %s\nMin free %s" % (MaxDisk, MinDisk)
        for diskInfo in list(map(DiskInfoDict.get, sortedKeys)):
            self.result.raw += "\n%s" % diskInfo
