#!/usr/bin/env python3
# -*- coding:utf-8 -*-
#############################################################################
# Copyright (c): 2012-2017, Huawei Tech. Co., Ltd.
# Description  : ErrorCode.py is utility to register the error message
#############################################################################
try:
    import re
    import sys
except ImportError as ie:
    sys.exit("[GAUSS-52200] : Unable to import module: %s." % str(ie))


class ErrorCode(object):
    """
    Class to define output about the error message
    """

    def __init__(self):
        pass

    @staticmethod
    def getErrorCodeAsInt(ex, default_error_code):
        """
        Resolve the exit code from the exception instance or error message.

        In linux, the range of return values is between 0 and 255.
        So we can only use each type of error code as exit code.Such as:
            ErrorCode.GAUSS_500 : 10
            ErrorCode.GAUSS_501 : 11

        :param ex:                  Exception instance or error message
        :param default_error_code:  If the exception instance does not contain the exit code, use this parameter.

        :type ex:                   Exception | str
        :type default_error_code:   int

        :return:    Return the error code.
            9 represents undefined exit code.
            other number between 0 and 255 represent the specific gauss error.
        :type:      int
        """
        error_message = str(ex)
        pattern = r"^[\S\s]*\[GAUSS-(\d+)\][\S\s]+$"
        match = re.match(pattern, error_message)

        if match is not None and len(match.groups()) == 1:
            error_code = int(match.groups()[0])
        else:
            error_code = default_error_code

        if 50000 < error_code < 60000:
            return error_code // 100 - 500 + 10
        else:
            return 9

    ################################################################################################################
    # parameter
    ################################################################################################################
    GAUSS_500 = {
        'GAUSS_50000': "[GAUSS-50000] : Unrecognized parameter: %s.",
        'GAUSS_50001': "[GAUSS-50001] : Incorrect parameter. Parameter '-%s' is required",
        'GAUSS_50002': "[GAUSS-50002] : Incorrect parameter. Parameter '-%s' is not required",
        'GAUSS_50003': "[GAUSS-50003] : The parameter '-%s' type should be %s.",
        'GAUSS_50004': "[GAUSS-50004] : The parameter '-%s' value is incorrect.",
        'GAUSS_50005': "[GAUSS-50005] : The parameter '-%s' and '-%s' cannot be used together.",
        'GAUSS_50006': "[GAUSS-50006] : Too many command-line arguments (first is \"%s\").",
        'GAUSS_50007': "[GAUSS-50007] : Failed to set %s parameter.",
        'GAUSS_50008': "[GAUSS-50008] : Failed to reload parameter.",
        'GAUSS_50009': "[GAUSS-50009] : Parameter format error.",
        'GAUSS_50010': "[GAUSS-50010] : Failed to check %s parameter.",
        'GAUSS_50011': "[GAUSS-50011] : The parameter[%s] value[%s] is invalid.",
        'GAUSS_50012': "[GAUSS-50012] : The parameter '%s' value can't be empty.",
        'GAUSS_50013': "[GAUSS-50013] : The parameter '%s' have not been initialized.",
        'GAUSS_50014': "[GAUSS-50014] : Parameter of '%s' cannot be empty.",
        'GAUSS_50015': "[GAUSS-50015] : The command line parser error: %s.",
        'GAUSS_50016': "[GAUSS-50016] : The re-entrant parameter '-%s' is not same with the previous command.",
    }

    ################################################################################################################
    # permission
    ################################################################################################################
    GAUSS_501 = {
        'GAUSS_50100': "[GAUSS-50100] : The %s is not readable for %s.",
        'GAUSS_50101': "[GAUSS-50101] : The %s is not executable for %s.",
        'GAUSS_50102': "[GAUSS-50102] : The %s is not writable for %s.",
        'GAUSS_50104': "[GAUSS-50104] : Only a user with the root permission can run this script.",
        'GAUSS_50105': "[GAUSS-50105] : Cannot run this script as a user with the root permission.",
        'GAUSS_50106': "[GAUSS-50106] : Failed to change the owner of %s.",
        'GAUSS_50107': "[GAUSS-50107] : Failed to change the permission of %s.",
        'GAUSS_50109': "[GAUSS-50109] : Only a user with the root permission can check SSD information.",
        'GAUSS_50110': "[GAUSS-50110] : Cannot execute this script on %s."
    }

    ################################################################################################################
    # file or directory
    ################################################################################################################
    GAUSS_502 = {
        'GAUSS_50200': "[GAUSS-50200] : The %s exists.",
        'GAUSS_50201': "[GAUSS-50201] : The %s does not exist.",
        'GAUSS_50202': "[GAUSS-50202] : The %s must be empty.",
        'GAUSS_50203': "[GAUSS-50203] : The %s cannot be empty.",
        'GAUSS_50204': "[GAUSS-50204] : Failed to read %s.",
        'GAUSS_50205': "[GAUSS-50205] : Failed to write %s.",
        'GAUSS_50206': "[GAUSS-50206] : Failed to create %s.",
        'GAUSS_50207': "[GAUSS-50207] : Failed to delete %s.",
        'GAUSS_50208': "[GAUSS-50208] : Failed to create the %s directory.",
        'GAUSS_50209': "[GAUSS-50209] : Failed to delete the %s directory.",
        'GAUSS_50210': "[GAUSS-50210] : The %s must be a file.",
        'GAUSS_50211': "[GAUSS-50211] : The %s must be a directory.",
        'GAUSS_50212': "[GAUSS-50212] : The suffix of the file [%s] should be '%s'.",
        'GAUSS_50213': "[GAUSS-50213] : The %s path must be an absolute path.",
        'GAUSS_50214': "[GAUSS-50214] : Failed to copy %s.",
        'GAUSS_50216': "[GAUSS-50216] : Failed to remote copy %s.",
        'GAUSS_50217': "[GAUSS-50217] : Failed to decompress %s.",
        'GAUSS_50218': "[GAUSS-50218] : Failed to rename %s.",
        'GAUSS_50219': "[GAUSS-50219] : Failed to obtain %s.",
        'GAUSS_50220': "[GAUSS-50220] : Failed to restore %s.",
        'GAUSS_50221': "[GAUSS-50221] : Failed to obtain file type.",
        'GAUSS_50222': "[GAUSS-50222] : The content of file %s is not correct.",
        'GAUSS_50223': "[GAUSS-50223] : Failed to update %s files.",
        'GAUSS_50224': "[GAUSS-50224] : The file name is incorrect.",
        'GAUSS_50227': "[GAUSS-50227] : Failed to compress %s.",
        'GAUSS_50228': "[GAUSS-50228] : The %s does not exist or is empty.",
        'GAUSS_50229': "[GAUSS-50229] : Cannot specify the file [%s] to the cluster path %s.",
        'GAUSS_50230': "[GAUSS-50230] : Failed to read/write %s.",
        'GAUSS_50231': "[GAUSS-50231] : Failed to generate %s file."
    }

    ################################################################################################################
    # user and group
    ################################################################################################################
    GAUSS_503 = {
        'GAUSS_50300': "[GAUSS-50300] : User %s does not exist.",
        'GAUSS_50301': "[GAUSS-50301] : The cluster user/group cannot be a root user/group.",
        'GAUSS_50302': "[GAUSS-50302] : The cluster user cannot be a user with the root permission.",
        'GAUSS_50304': "[GAUSS-50304] : The new user [%s] is not the same as the old user [%s].",
        'GAUSS_50305': "[GAUSS-50305] : The user is not matched with the user group.",
        'GAUSS_50306': "[GAUSS-50306] : The password of %s is incorrect.",
        'GAUSS_50307': "[GAUSS-50307] : User password has expired.",
        'GAUSS_50308': "[GAUSS-50308] : Failed to obtain user information.",
        'GAUSS_50309': "[GAUSS-50309] : Failed to obtain password change times of data base super user",
        'GAUSS_50311': "[GAUSS-50311] : Failed to change password for %s.",
        'GAUSS_50313': "[GAUSS-50313] : Failed to delete %s group.",
        'GAUSS_50314': "[GAUSS-50314] : Failed to delete %s user.",
        'GAUSS_50315': "[GAUSS-50315] : The user %s is not matched with the owner of %s.",
        'GAUSS_50317': "[GAUSS-50317] : Failed to check user and password.",
        'GAUSS_50318': "[GAUSS-50318] : Failed to add %s user.",
        'GAUSS_50319': "[GAUSS-50319] : Failed to add %s group.",
        'GAUSS_50320': "[GAUSS-50320] : Failed to set '%s' to '%s' in /etc/ssh/sshd_config.",
        'GAUSS_50321': "[GAUSS-50321] : Failed to get configuration of '%s' from /etc/ssh/sshd_config."
    }

    ################################################################################################################
    # disk
    ################################################################################################################
    GAUSS_504 = {
        'GAUSS_50400': "[GAUSS-50400] : The remaining space of device [%s] cannot be less than %s.",
        'GAUSS_50401': "[GAUSS-50401] : The usage of the device [%s] space cannot be greater than %s.",
        'GAUSS_50406': "[GAUSS-50406] : Failed to obtain disk read and write rates.",
        'GAUSS_50407': "[GAUSS-50407] : Failed to clean shared semaphore.",
        'GAUSS_50408': "[GAUSS-50408] : Failed to obtain disk read-ahead memory block.",
        'GAUSS_50409': "[GAUSS-50409] : The remaining space of dns cannot support shrink.",
        'GAUSS_50410': "[GAUSS-50410] : Failed to check if remaining space of dns support shrink."
    }

    ################################################################################################################
    # memory
    ################################################################################################################
    GAUSS_505 = {
        'GAUSS_50501': "[GAUSS-50501] : Shared_buffers must be less than shmmax. Please check it.",
        'GAUSS_50502': "[GAUSS-50502] : Failed to obtain %s information."
    }

    ################################################################################################################
    # network
    ################################################################################################################
    GAUSS_506 = {
        'GAUSS_50600': "[GAUSS-50600] : The IP address cannot be pinged, which is caused by network faults.",
        'GAUSS_50601': "[GAUSS-50601] : The port [%s] is occupied.",
        'GAUSS_50603': "[GAUSS-50603] : The IP address is invalid.",
        'GAUSS_50604': "[GAUSS-50604] : Failed to obtain network interface card of back_ip(%s).",
        'GAUSS_50606': "[GAUSS-50606] : Back IP(s) do not have the same subnet mask.",
        'GAUSS_50611': "[GAUSS-50611] : Failed to obtain network card bonding information.",
        'GAUSS_50612': "[GAUSS-50612] : Failed to obtain network card %s value.",
        'GAUSS_50613': "[GAUSS-50613] : Failed to set network card %s value.",
        'GAUSS_50614': "[GAUSS-50614] : Failed to check network information.",
        'GAUSS_50615': "[GAUSS-50615] : IP %s and IP %s are not in the same network segment.",
        'GAUSS_50616': "[GAUSS-50616] : Failed to get network interface.",
        'GAUSS_50617': "[GAUSS-50617] : The node of XML configure file has the same virtual IP."
    }

    ################################################################################################################
    # crontab
    ################################################################################################################
    GAUSS_508 = {
        'GAUSS_50801': "[GAUSS-50801] : Failed to set up tasks.",
        'GAUSS_50802': "[GAUSS-50802] : Failed to %s service.",
        'GAUSS_50803': "[GAUSS-50803] : Failed to check user cron."
    }

    ################################################################################################################
    # THP
    ################################################################################################################
    GAUSS_510 = {
        'GAUSS_51001': "[GAUSS-51001] : Failed to obtain THP service.",
        'GAUSS_51002': "[GAUSS-51002] : Failed to close THP service."
    }

    ################################################################################################################
    # SSH trust
    ################################################################################################################
    GAUSS_511 = {
        'GAUSS_51100': "[GAUSS-51100] : Failed to verify SSH trust on these nodes: %s.",
        'GAUSS_51101': "[GAUSS-51101] : SSH exception: \n%s",
        'GAUSS_51107': "[GAUSS-51107] : Ssh Paramiko failed.",
        'GAUSS_51108': "[GAUSS-51108] : Ssh-keygen failed.",
        'GAUSS_51111': "[GAUSS-51111] : Failed to append local ID to authorized_keys on remote node.",
        'GAUSS_51112': "[GAUSS-51112] : Failed to exchange SSH keys for user[%s] using hostname."
    }

    ################################################################################################################
    # cluster/XML configruation
    ################################################################################################################
    GAUSS_512 = {
        'GAUSS_51200': "[GAUSS-51200] : The parameter [%s] in the XML file does not exist.",
        'GAUSS_51201': "[GAUSS-51201] : Node names must be configured.",
        'GAUSS_51203': "[GAUSS-51203] : Failed to obtain the %s information from static configuration files.",
        'GAUSS_51204': "[GAUSS-51204] : Invalid %s instance type: %d.",
        'GAUSS_51205': "[GAUSS-51205] : Failed to refresh the %s instance ID.",
        'GAUSS_51206': "[GAUSS-51206] : The MPPRC file path must be an absolute path: %s.",
        'GAUSS_51207': "[GAUSS-51207] : Failed to obtain back_ip from node [%s].",
        'GAUSS_51208': "[GAUSS-51208] : Invalid %s number [%d].",
        'GAUSS_51209': "[GAUSS-51209] : Failed to obtain %s configuration on the host [%s].",
        'GAUSS_51212': "[GAUSS-51212] : There is no information about %s.",
        'GAUSS_51213': "[GAUSS-51213] : The port number of XML [%s] conflicted.",
        'GAUSS_51214': "[GAUSS-51214] : The number of capacity expansion nodes cannot be less than three.",
        'GAUSS_51215': "[GAUSS-51215] : The capacity expansion node [%s] cannot contain GTM/CM/ETCD.",
        'GAUSS_51216': "[GAUSS-51216] : The capacity expansion node [%s] must contain CN or DN.",
        'GAUSS_51217': "[GAUSS-51217] : The cluster's static configuration does not match the new configuration file.",
        'GAUSS_51219': "[GAUSS-51219] : There is no CN in cluster.",
        'GAUSS_51220': "[GAUSS-51220] : The IP address %s is incorrect.",
        'GAUSS_51221': "[GAUSS-51221] : Failed to configure hosts mapping information.",
        'GAUSS_51222': "[GAUSS-51222] : Failed to check hostname mapping.",
        'GAUSS_51224': "[GAUSS-51224] : The ip(%s) has been used on other nodes.",
        'GAUSS_51226': "[GAUSS-51226] : Virtual IP(s) and Back IP(s) do not have the same network segment.",
        'GAUSS_51227': "[GAUSS-51227] : The number of %s on all nodes are different.",
        'GAUSS_51229': "[GAUSS-51229] : The DN listen_ip(%s) is not in the virtual_ip or back_ip on the node(%s).",
        'GAUSS_51230': "[GAUSS-51230] : The number of %s must %s.",
        'GAUSS_51231': "[GAUSS-51231] : Old nodes are less than 2.",
        'GAUSS_51232': "[GAUSS-51232] : XML configuration and static configuration are the same.",
        'GAUSS_51233': "[GAUSS-51233] : The Port(%s) is invalid on the node(%s).",
        'GAUSS_51234': "[GAUSS-51234] : The configuration file [%s] contains parsing errors.",
        'GAUSS_51235': "[GAUSS-51235] : Invalid directory [%s].",
        'GAUSS_51236': "[GAUSS-51236] : Failed to parsing xml.",
        'GAUSS_51239': "[GAUSS-51239] : These virtual IP(%s) are not accessible after configuring."
    }

    ################################################################################################################
    # SQL exception
    ################################################################################################################
    GAUSS_513 = {
        'GAUSS_51300': "[GAUSS-51300] : Failed to execute SQL: %s."
    }

    ################################################################################################################
    # Shell exception
    ################################################################################################################
    GAUSS_514 = {
        'GAUSS_51400': "[GAUSS-51400] : Failed to execute the command: %s.",
        'GAUSS_51401': "[GAUSS-51401] : Failed to do %s.sh."
    }

    ################################################################################################################
    # interface calls exception
    ################################################################################################################
    GAUSS_515 = {
        'GAUSS_51500': "[GAUSS-51500] : Failed to call the interface %s. Exception: %s."
    }

    ################################################################################################################
    # cluster/instance status
    ################################################################################################################
    GAUSS_516 = {
        'GAUSS_51600': "[GAUSS-51600] : Failed to obtain the cluster status.",
        'GAUSS_51601': "[GAUSS-51601] : Failed to check %s status.",
        'GAUSS_51602': "[GAUSS-51602] : The cluster status is Abnormal.",
        'GAUSS_51603': "[GAUSS-51603] : Failed to obtain peer %s instance.",
        'GAUSS_51605': "[GAUSS-51605] : Failed to check whether the %s process exists.",
        'GAUSS_51606': "[GAUSS-51606] : Failed to kill the %s process.",
        'GAUSS_51607': "[GAUSS-51607] : Failed to start %s.",
        'GAUSS_51608': "[GAUSS-51608] : Failed to lock cluster",
        'GAUSS_51609': "[GAUSS-51609] : Failed to unlock cluster",
        'GAUSS_51610': "[GAUSS-51610] : Failed to stop %s.",
        'GAUSS_51612': "[GAUSS-51612] : The instance IDs [%s] are not found in %s.",
        'GAUSS_51613': "[GAUSS-51613] : There is no instance in %s to be built.",
        'GAUSS_51614': "[GAUSS-51614] : Received signal[%d].",
        'GAUSS_51615': "[GAUSS-51615] : Failed to initialize instance.",
        'GAUSS_51616': "[GAUSS-51616] : Failed to dump %s schema.",
        'GAUSS_51617': "[GAUSS-51617] : Failed to rebuild %s.",
        'GAUSS_51618': "[GAUSS-51618] : Failed to get all hostname.",
        'GAUSS_51619': "[GAUSS-51619] : The host name [%s] is not in the cluster.",
        'GAUSS_51620': "[GAUSS-51620] : Failed to obtain %s instance information.",
        'GAUSS_51621': "[GAUSS-51621] : HA IP is empty.",
        'GAUSS_51622': "[GAUSS-51622] : There is no %s on %s node.",
        'GAUSS_51623': "[GAUSS-51623] : Failed to obtain version.",
        'GAUSS_51624': "[GAUSS-51624] : Failed to get CN connections.",
        'GAUSS_51625': "[GAUSS-51625] : Cluster is running.",
        'GAUSS_51626': "[GAUSS-51626] : Failed to roll back.",
        'GAUSS_51627': "[GAUSS-51627] : Configuration failed.",
        'GAUSS_51628': "[GAUSS-51628] : The version number of new cluster is [%s]. It should be float.",
        'GAUSS_51629': "[GAUSS-51629] : The version number of new cluster is [%s]. "
                       "It should be greater than or equal to the old version.",
        'GAUSS_51630': "[GAUSS-51630] : No node named %s.",
        'GAUSS_51631': "[GAUSS-51631] : Failed to delete the %s instance.",
        'GAUSS_51632': "[GAUSS-51632] : Failed to do %s.",
        'GAUSS_51633': "[GAUSS-51633] : The %s must be a digit.",
        'GAUSS_51635': "[GAUSS-51635] : Failed to check SHA256.",
        'GAUSS_51636': "[GAUSS-51636] : Failed to obtain %s node information.",
        'GAUSS_51637': "[GAUSS-51637] : The %s does not match with %s.",
        'GAUSS_51638': "[GAUSS-51638] : Failed to append instance on host [%s].",
        'GAUSS_51640': "[GAUSS-51640] : Can't connect to cm_server, cluster is not running possibly.",
        'GAUSS_51641': "[GAUSS-51641] : Cluster redistributing status is not accord with expectation.",
        'GAUSS_51642': "[GAUSS-51642] : Failed to promote peer instances.",
        'GAUSS_51643': "[GAUSS-51643] : Cluster is in read-only mode.",
        'GAUSS_51644': "[GAUSS-51644] : Failed to set resource control for the cluster.",
        'GAUSS_51645': "[GAUSS-51645] : Failed to restart %s.",
        'GAUSS_51646': "[GAUSS-51646] : The other OM operation is currently being performed in the cluster node:"
                       " '%s'.",
        'GAUSS_51647': "[GAUSS-51647] : The operation step of OM components in current cluster nodes does not match"
                       " with each other: %s.",
        'GAUSS_51648': "[GAUSS-51648] : Waiting for redistribution process to end timeout.",
        'GAUSS_51649': "[GAUSS-51649] : Capture exceptions '%s' : %s.",
        'GAUSS_51650': "[GAUSS-51650] : Unclassified exceptions: %s.",
    }

    ################################################################################################################
    # Check system table
    ################################################################################################################
    GAUSS_517 = {
        'GAUSS_51700': "[GAUSS-51700] : There must be only one record in the pgxc_group table.",
        'GAUSS_51701': "[GAUSS-51701] : The current node group is incorrect.",
        'GAUSS_51702': "[GAUSS-51702] : Failed to obtain node group information.",
        'GAUSS_51705': "[GAUSS-51705] : Failed to update PGXC_NODE.",
        'GAUSS_51706': "[GAUSS-51706] : Failed to check CGroup."
    }

    ################################################################################################################
    # environmental variable
    ################################################################################################################
    GAUSS_518 = {
        'GAUSS_51800': "[GAUSS-51800] : The environmental variable %s is empty. "
                       "or variable has exceeded maximum length",
        'GAUSS_51802': "[GAUSS-51802] : Failed to obtain the environment variable %s.",
        'GAUSS_51805': "[GAUSS-51805] : The environmental variable [%s]'s value is invalid.",
        'GAUSS_51806': "[GAUSS-51806] : The cluster has been installed.",
        'GAUSS_51807': "[GAUSS-51807] : $GAUSSHOME of user is not equal to installation path.",
        'GAUSS_51808': "[GAUSS-51808] : The env file contains errmsg: %s."
    }

    ################################################################################################################
    # OS version
    ################################################################################################################
    GAUSS_519 = {
        'GAUSS_51900': "[GAUSS-51900] : The current OS is not supported."
    }

    ################################################################################################################
    # OS time zone
    ################################################################################################################
    GAUSS_521 = {
        'GAUSS_52102': "[GAUSS-52102] : The parameter [%s] value is not equal to the expected value.",
        'GAUSS_52103': "[GAUSS-52103] : Failed to forcibly make the character sets to take effect."
    }

    ################################################################################################################
    # OS character set
    ################################################################################################################
    GAUSS_522 = {
        'GAUSS_52200': "[GAUSS-52200] : Unable to import module: %s.",
        'GAUSS_52201': "[GAUSS-52201] : The current python version %s is not supported."
    }

    ################################################################################################################
    # Operating system parameters
    ################################################################################################################
    GAUSS_523 = {
        'GAUSS_52301': "[GAUSS-52301] : Failed to check OS parameters."
    }

    ################################################################################################################
    # preinsatll install
    ################################################################################################################
    GAUSS_524 = {
        'GAUSS_52400': "[GAUSS-52400] : Installation environment does not meet the desired result.",
        'GAUSS_52401': "[GAUSS-52401] : On system wide basis, the maximum number of %s is not correct. "
                       "the current %s value is:",
        'GAUSS_52402': "[GAUSS-52402] : IP [%s] is not matched with hostname [%s]. \n",
        'GAUSS_52403': "[GAUSS-52403] : Command \"%s\" does not exist or the user has no execute permission on %s."
    }

    ################################################################################################################
    # uninsatll postuninstall
    ################################################################################################################
    GAUSS_525 = {
        'GAUSS_52501': "[GAUSS-52501] : Run %s script before executing this script."
    }

    ################################################################################################################
    # expand and shrik
    ################################################################################################################
    GAUSS_526 = {
        'GAUSS_52600': "[GAUSS-52600] : Cannot obtain any cluster ring.",
        'GAUSS_52601': "[GAUSS-52601] : Redistribution failed due to user request.",
        'GAUSS_52602': "[GAUSS-52602] : There is no CN in old nodes.",
        'GAUSS_52603': "[GAUSS-52603] : There is no CN on the contraction of the remaining nodes.",
        'GAUSS_52605': "[GAUSS-52605] : Cannot contract local node(%s).",
        'GAUSS_52606': "[GAUSS-52606] : Contract too many nodes. "
                       "It should left three nodes to format a cluster at least.",
        'GAUSS_52607': "[GAUSS-52607] : [%s] does not at the end of instance list.",
        'GAUSS_52608': "[GAUSS-52608] : [%s] contains %s instance.",
        'GAUSS_52609': "[GAUSS-52609] : All contracted nodes do not contain DN instance.",
        'GAUSS_52610': "[GAUSS-52610] : The current node group are node group after contraction.",
        'GAUSS_52611': "[GAUSS-52611] : There must be only one record in the current node group.",
        'GAUSS_52612': "[GAUSS-52612] : All dilatation nodes do not contain the DN instance.",
        'GAUSS_52613': "[GAUSS-52613] : Static configuration is not matched on some nodes. Please handle it first.",
        'GAUSS_52614': "[GAUSS-52614] : Timeout. The current cluster status is %s.",
        'GAUSS_52615': "[GAUSS-52615] : Cluster lock unlocked due to timeout.",
        'GAUSS_52616': "[GAUSS-52616] : Cannot find a similar instance for [%s %s].",
        'GAUSS_52617': "[GAUSS-52617] : Invalid check type.",
        'GAUSS_52618': "[GAUSS-52618] : Failed to delete etcd from node.",
        'GAUSS_52620': "[GAUSS-52620] : Not all nodes found. The following is what we found: %s.",
        'GAUSS_52623': "[GAUSS-52623] : Failed to check node group numbers: Node group numbers is [%d].",
        'GAUSS_52624': "[GAUSS-52624] : Failed to check %s node group members: Invalid group name or nodes.",
        'GAUSS_52626': "[GAUSS-52626] : The CN connection on the old nodes is abnormal.",
        'GAUSS_52627': "[GAUSS-52627] : The current cluster is locked.",
        'GAUSS_52628': "[GAUSS-52628] : Static configuration has already been updated on all nodes, "
                       "expansion has been completed possibly.",
        'GAUSS_52629': "[GAUSS-52629] : Cluster ring(%s) cannot obtain fewer than three nodes.",
        'GAUSS_52630': "[GAUSS-52630] : Failed to set the read-only mode parameter for all CN and DN instances.",
        'GAUSS_52631': "[GAUSS-52631] : Invalid value for GUC parameter comm_max_datanode: %s.",
        'GAUSS_52632': "[GAUSS-52632] : Cluster breakdown or abnormal operation during expanding online, "
                       "lock process for expansion is lost.",
        'GAUSS_52633': "[GAUSS-52633] : There is no primary data_node.",
        'GAUSS_52634': "[GAUSS-52634] : There is no normal CN and primary DN on local node."
    }

    ################################################################################################################
    # replace
    ################################################################################################################
    GAUSS_527 = {
        'GAUSS_52700': "[GAUSS-52700] : Failed to update ETCD.",
        'GAUSS_52701': "[GAUSS-52701] : All the CMAgents instances are abnormal. Cannot fix the cluster.",
        'GAUSS_52703': "[GAUSS-52703] : The number of normal ETCD must be greater than half.",
        'GAUSS_52704': "[GAUSS-52704] : Failed to check the %s condition.",
        'GAUSS_52706': "[GAUSS-52706] : Failed to clean ETCD and touch flag file on %s.",
        'GAUSS_52707': "[GAUSS-52707] : Failed to install on %s.",
        'GAUSS_52709': "[GAUSS-52709] : Failed to check the cluster configuration differences:",
        'GAUSS_52710': "[GAUSS-52710] : Replacement failed.",
        'GAUSS_52711': "[GAUSS-52711] : Failed to set Cm_agent start mode."
    }

    ################################################################################################################
    # manageCN and changeIP
    ################################################################################################################
    GAUSS_528 = {
        'GAUSS_52800': "[GAUSS-52800] : Cluster is %s(%s) now.",
        'GAUSS_52801': "[GAUSS-52801] : Only allow to %s one CN. The %s is not matched.",
        'GAUSS_52802': "[GAUSS-52802] : Only allow to add one CN at the end.",
        'GAUSS_52803': "[GAUSS-52803] : There is at least one Normal CN after delete CN.",
        'GAUSS_52805': "[GAUSS-52805] : Failed to find another instance as model for instance(%s).",
        'GAUSS_52807': "[GAUSS-52807] : There is no IP changed.",
        'GAUSS_52808': "[GAUSS-52808] : Detected CN %s, but the action is %s.",
        'GAUSS_52809': "[GAUSS-52809] : Only allow to delete one CN.",
        'GAUSS_52810': "[GAUSS-52810] : There is Abnormal coordinator(s) in cluster, please delete it firstly."
    }

    ################################################################################################################
    # upgrade
    ################################################################################################################
    GAUSS_529 = {
        'GAUSS_52900': "[GAUSS-52900] : Failed to upgrade strategy: %s.",
        'GAUSS_52902': "[GAUSS-52902] : Cannot support upgrade from %s to %s",
        'GAUSS_52904': "[GAUSS-52904] : Please choose right upgrade strategy.",
        'GAUSS_52905': "[GAUSS-52905] : Failed to obtain old cluster version.",
        'GAUSS_52908': "[GAUSS-52908] : Failed to set cluster read-only mode.",
        'GAUSS_52929': "[GAUSS-52929] : Failed to check application version. Output: \n%s.",
        'GAUSS_52930': "[GAUSS-52930] : Forbid installing etcd in master-standby cluster after 8.1.0, "
                       "will auto delete etcd when upgrade to 8.1.0 if old cluster contains etcd.",
        'GAUSS_52931': "[GAUSS-52931] : Forbid installing etcd in master-standby cluster after 8.1.0.",
        'GAUSS_52935': "[GAUSS-52935] : Current upgrade version is not same with unfinished upgrade version record.",
        'GAUSS_52937': "[GAUSS-52937] : Invalid upgrade version with %s.",
        'GAUSS_52938': "[GAUSS-52938] : oid is wraparound in node %s."
    }

    ################################################################################################################
    # check
    ################################################################################################################
    GAUSS_530 = {
        'GAUSS_53005': "[GAUSS-53005] : Unable to obtain SSD disk on current node.",
        'GAUSS_53006': "[GAUSS-53006] : No DN instance uses data directory %s on %s.",
        'GAUSS_53007': "[GAUSS-53007] : Failed to switch %s.",
        'GAUSS_53008': "[GAUSS-53008] : The current node does not install SSD. Cannot check SSD performance.",
        'GAUSS_53009': "[GAUSS-53009] : Failed to format cu of directory: %s.",
        'GAUSS_53010': "[GAUSS-53010] : The function name of %s is not exist in the %s.",
        'GAUSS_53011': "[GAUSS-53011] : Failed to check %s.",
        'GAUSS_53012': "[GAUSS-53012] : Failed to insert pmk data to database.",
        'GAUSS_53013': "[GAUSS-53013] : the cmserver is not primary."
    }

    ################################################################################################################
    # check interface
    ################################################################################################################
    GAUSS_531 = {
        'GAUSS_53100': "[GAUSS-53100] : [%s] is not supported in single cluster.",
        'GAUSS_53101': "[GAUSS-53101] : This interface is not supported in %s cluster.",
        'GAUSS_53102': "[GAUSS-53102] : [%s] is not supported in express cluster.",
        'GAUSS_53103': "[GAUSS-53103] : The single primary multi standby cluster does not support the product"
                       " version '%s'.",
        'GAUSS_53104': "[GAUSS-53104] : [%s] is not supported in single instance cluster."
    }
    ################################################################################################################
    # Single Primary MultiStandby cluster
    ################################################################################################################
    GAUSS_532 = {
        'GAUSS_53200': "[GAUSS-53200] : The number of standbys for each DN instance must be the same. Please set it.",
        'GAUSS_53201': "[GAUSS-53201] : The number of DN standbys and the AZ settings are incorrect. Please set it.",
        'GAUSS_53202': "[GAUSS-53202] : The AZ information is incorrect. Please set it.",
        'GAUSS_53203': "[GAUSS-53203] : The number of ETCD in %s. Please set it.",
        'GAUSS_53204': "[GAUSS-53204] : [%s] is not supported in single primary multi_standby cluster.",
        'GAUSS_53205': "[GAUSS-53205] : The priority of %s must be higher than %s. Please set it.",
        'GAUSS_53206': "[GAUSS-53206] : The value of %s must be greater than 0 and less than 11. Please set it."
    }
    ################################################################################################################
    # License
    ################################################################################################################
    GAUSS_533 = {
        'GAUSS_53300': "[GAUSS-53300] : The current product version '%s' does not support the license "
                       "register/unregister operation.",
        'GAUSS_53301': "[GAUSS-53301] : The license control files are not consistent on the cluster.",
        'GAUSS_53302': "[GAUSS-53302] : The current cluster does not apply the license control, please upgrade it"
                       " first.",
        'GAUSS_53303': "[GAUSS-53303] : The DWS cluster does not support the license register/unregister operation.",
        'GAUSS_53304': "[GAUSS-53304] : Cannot register the enabled features.",
        'GAUSS_53305': "[GAUSS-53304] : Cannot Un-register the disabled features.",
        'GAUSS_53306': "[GAUSS-53306] : Cannot register the unsupported features of the product version '%s'.",
        'GAUSS_53307': "[GAUSS-53307] : No need to Un-register the unsupported features of the product version '%s'.",
    }

    ################################################################################################################
    # Scheduler
    ################################################################################################################
    GAUSS_534 = {
        'GAUSS_53400': "[GAUSS-53400] : Scheduler is running tasks. New redis work is NOT allowed.",
        'GAUSS_53401': "[GAUSS-53401] : Scheduler Error. %s",
        'GAUSS_53402': "[GAUSS-53402] : Input Error: %s.",
        'GAUSS_53403': "[GAUSS-53403] : Start %s failed.",
        'GAUSS_53404': "[GAUSS-53404] : Init %s failed.",
        'GAUSS_53405': "[GAUSS-53405] : Redis Status Error: %s.",
        'GAUSS_53406': "[GAUSS-53406] : Template Error: %s.",
        'GAUSS_53407': "[GAUSS-53407] : Task Run Exception: %s.",
        'GAUSS_53408': "[GAUSS-53408] : Time Error: %s.",
        'GAUSS_53409': "[GAUSS-53409] : Algorithm Exception: %s.",
        'GAUSS_53410': "[GAUSS-53410] : Unexpected query result: %s.",
        'GAUSS_53411': "[GAUSS-53411] : Unclassified exceptions: %s."
    }

    ################################################################################################################
    # GDS Tools
    ################################################################################################################
    GAUSS_535 = {
        'GAUSS_53500': "[GAUSS-53500] : Failed to connect to %s.",
        'GAUSS_53501': "[GAUSS-53501] : Connection timeout.",
        'GAUSS_53502': "[GAUSS-53502] : Undefined action.",
        'GAUSS_53503': "[GAUSS-53503] : Failed to parse host IP from %s.",
        'GAUSS_53504': "[GAUSS-53504] : Bad response %s.",
        'GAUSS_53505': "[GAUSS-53505] : Installation directory does not exist, "
                       "                please check whether the installation is OK.",
        'GAUSS_53506': "[GAUSS-53506] : Failed to check whether a process on this port exists with exception: %s.",
        'GAUSS_53507': "[GAUSS-53507] : OS environments not set, please check install log.",
        'GAUSS_53508': "[GAUSS-53508] : Failed to add watch dog for %s.",
        'GAUSS_53509': "[GAUSS-53509] : Failed to delete watch dog for %s.",
        'GAUSS_53510': "[GAUSS-53510] : Failed to save start command for %s.",
        'GAUSS_53511': "[GAUSS-53511] : Failed to get start command for %s.",
        'GAUSS_53512': "[GAUSS-53512] : Retry to dispatch package 3 times, with error: %s.",
        'GAUSS_53513': "[GAUSS-53513] : Failed to load environment parameters.",
        'GAUSS_53514': "[GAUSS-53514] : Unclassified exceptions: %s.",
        'GAUSS_53515': "[GAUSS-53515] : Cannot read check result. Please try again.",
        'GAUSS_53516': "[GAUSS-53516] : Check result shows unqualified items. Installation stop.",
        'GAUSS_53517': "[GAUSS-53517] : The user %s does not have the permission to access the directory %s.",
        'GAUSS_53518': "[GAUSS-53518] : Dispatch package failed, with error: %s.",
    }


class OmError(BaseException):
    """
    Used to record OM exception information and support ErrorCode keywords as message information.
    """

    def __init__(self, _message, *args, **kwargs):
        """
        Initialize the OmError instance.

        :param _message:    The input error message, it can be the error message string, or the ErrorCode keywords,
                             or the Exception instance.
        :param args:        The additional unnamed parameters that use to format the error message.
        :param kwargs:      The additional named parameters that use to format the error message or extend to other
                             functions.

        :type _message:     str | BaseException
        :type args:         str | int
        :type kwargs:       str | int
        """
        super().__init__(*args, **kwargs)
        # If we catch an unhandled exception.
        if isinstance(_message, Exception):
            # Store the error code.
            self._errorCode = ""
            # Store the error message.
            self._message = self.__getErrorMessage(str(_message), args, kwargs)
            # If can not parse the error code.
            if not self._errorCode:
                # Store the error code.
                self._errorCode = "GAUSS_51649"
                # Store the error message.
                self._message = ErrorCode.GAUSS_516[self._errorCode] % (type(_message).__name__, repr(_message))
        else:
            # Store the error code.
            self._errorCode = ""
            # Store the error message.
            self._message = self.__getErrorMessage(_message, args, kwargs)

        # Store the stack information.
        self._stackInfo = sys.exc_info()[2]

    @property
    def message(self):
        """
        Getter, get the error message.

        :return:    Return the error message.
        :rtype:     str
        """
        return self._message

    @property
    def errorCode(self):
        """
        Getter, get the error code.

        :return:    Return the error code.
        :rtype:     str
        """
        return self._errorCode

    def __getErrorMessage(self, _errorCode, args, kwargs):
        """
        Get error information through error code.

        :param _errorCode:  Error code.
        :param args:        Additional parameters.
        :param kwargs:      Additional parameters.

        :type _errorCode:   str
        :type args:         tuple
        :type kwargs:       dict | None

        :return:    Return the error message.
        :rtype:     str
        """
        # Get base error information through error code.
        pattern = r"^[\S\s]*\[(GAUSS-\d+)\][\S\s]+$"
        match = re.match(pattern, str(_errorCode))
        if match and len(match.groups()) == 1:
            self._errorCode = match.groups()[0]
            message = _errorCode
        else:
            self._errorCode = "GAUSS_51650"
            message = ErrorCode.GAUSS_516[self._errorCode] % _errorCode

        # Format parameter which type is "%(param)s".
        if kwargs:
            for key, value in kwargs.items():
                if value is not None:
                    message = message.replace("%(" + key + ")s", str(value))
                else:
                    message = message.replace("%(" + key + ")s", "'None'")

        # Format standard type parameters.
        if args:
            # Convert tuple to list.
            args = list(args)
            # Travel the list.
            for i, arg in enumerate(args):
                if arg is None:
                    args[i] = "'None'"
                else:
                    args[i] = str(arg)

            # Format the message.
            message %= tuple(args)

        return message

    def __str__(self):
        """
        Show this instance as a string.

        :return:    Return this instance as a string.
        :rtype:     str
        """
        return self.message

    def __repr__(self):
        """
        Show this instance as a string.

        :return:    Return this instance as a string.
        :rtype:     str
        """
        return self.__str__()
