Skip to content

Latest commit

 

History

History
823 lines (722 loc) · 33.6 KB

Dump-Utility.md

File metadata and controls

823 lines (722 loc) · 33.6 KB

Dump Utility for Easy Debugging

Rev 1.0

Table of Contents

Revision

Rev Date Author Change Description
1.0 05/28/2021 Vivek Reddy Karri Initial version

About this Manual

This document describes the details of a dump cli utility which collects and dumps the redis state for a given feature/module.

Definitions/Abbreviations

Table 1: Abbreviations
Abbreviation Description
APP DB Application Database
ASIC DB ASIC Database
CONF DB Configuration Database

In this document, the term 'redis state' refers to the intermediate state of a given feature present across all the Redis DB's

Overview

In SONiC, there usually exists a set of tables related/relevant to a particular module. All of these have to be looked at to confirm whether any configuration update is properly applied and propagated.

The task of debugging quickly becomes tedious because currently, there is no utility which does print a unified view of the redis-state. This is the problem which is addressed by this dump utility.

This utility provides the base infrastructure and guidelines to make is easy for the developers to extend and support the utility for different modules.

1 Requirements

1.1 Intended Usage

Note: Currently, state is the only subcommand under dump.

dump state <feature/module> <arg | all>

Example usage for Port feature which accepts an argument port_name
dump state port <port_name>
dump state port Ethernet4
dump state port Ethernet4,Ethernet8,Ethernet12
dump state port all

1.1 Intended Usage

  1. The dump state subcommand will take a feature/module or any logical top-level name as the first argument.
  2. A Second Argument should also be defined for a feature.
  3. This argument could either be a table-key or a unique-field-value present in either Conf DB or Appl DB.
    • Eg: For PORT, the second argument will be an interface name i.e 'Ethernet128' which is a table-key. On the other hand, the secondary argument for COPP will be a trap_id such as 'arp_req', which is a field-value and not a key of any table.
  4. The decision of what to pass as a secondary argument lies with the discretion of the one who is writing the module.
  5. The Command should also take a list of comma seperated inputs for the secondary argument
  6. The Command should also accept an "all" value and which means it should print the unified view for every entry related to that feature.
root@sonic# dump state --help
Usage: main.py state [OPTIONS] MODULE IDENTIFIER

  Dump the redis-state of the identifier for the module specified

Options:
  -s, --show            Display Modules Available
  -d, --db TEXT         Only dump from these Databases
  -t, --table           Print in tabular format  [default: False]
  -k, --key-map         Only fetch the keys matched, don't extract field-value dumps  [default: False]
  -v, --verbose         Prints any intermediate output to stdout useful for dev & troubleshooting  [default: False]
  -n, --namespace TEXT  Dump the redis-state for this namespace.  [default: DEFAULT_NAMESPACE]
  --help                Show this message and exit.

1.2 Customization Options

  1. The unified view printed can be filtered per db using -d option
  2. Output is displayed in JSON format by default. Use -t to print in tabular format.
  3. All the available modules should be displayed using a -s option
  4. If Field-Value Tuples are not required, use -k option to specify that
  5. Use -v option to specify the intermediate output
  6. Namsepace can be changed using -n option
root@sonic# dump state --show
Module    Identifier
--------  ------------
port      port_name
copp      trap_id


root@sonic# dump state port Ethernet0
{
    "Ethernet0": {
        "CONFIG_DB": {
            "keys": [
                {
                    "PORT|Ethernet0": {
                        "admin_status": "up",
                        "alias": "etp1",
                        "index": "1",
                        "lanes": "0,1,2,3,4,5,6,7",
                        "speed": "100000"
                    }
                }
            ],
            "tables_not_found": []
        },
        "APPL_DB": {
            "keys": [
                {
                    "PORT_TABLE:Ethernet0": {
                        "admin_status": "up",
                        "alias": "etp1",
                        "description": "",
                        "index": "1",
                        "lanes": "0,1,2,3,4,5,6,7",
                        "mtu": "9100",
                        "oper_status": "up",
                        "speed": "100000"
                    }
                }
            ],
            "tables_not_found": []
        },
        "ASIC_DB": {
            "keys": [
                {
                    "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF:oid:0xd00000000056d": {
                        "SAI_HOSTIF_ATTR_NAME": "Ethernet0",
                        "SAI_HOSTIF_ATTR_OBJ_ID": "oid:0x10000000004a4",
                        "SAI_HOSTIF_ATTR_OPER_STATUS": "true",
                        "SAI_HOSTIF_ATTR_TYPE": "SAI_HOSTIF_TYPE_NETDEV",
                        "SAI_HOSTIF_ATTR_VLAN_TAG": "SAI_HOSTIF_VLAN_TAG_STRIP"
                    }
                },
                {
                    "ASIC_STATE:SAI_OBJECT_TYPE_PORT:oid:0x10000000004a4": {
                        "NULL": "NULL",
                        "SAI_PORT_ATTR_ADMIN_STATE": "true",
                        "SAI_PORT_ATTR_MTU": "9122",
                        "SAI_PORT_ATTR_SPEED": "100000"
                    }
                }
            ],
            "tables_not_found": [],
            "vidtorid": {
                "oid:0xd00000000056d": "oid:0xd",
                "oid:0x10000000004a4": "oid:0x1690000000001"
            }
        },
        "STATE_DB": {
            "keys": [
                {
                    "PORT_TABLE|Ethernet0": {
                        "state": "ok"
                    }
                }
            ],
            "tables_not_found": []
        }
    }
}


# --key-map option
root@sonic# dump state port Ethernet0 --key-map
{
    "Ethernet0": {
        "CONFIG_DB": {
            "keys": [
                "PORT|Ethernet0"
            ],
            "tables_not_found": []
        },
        "APPL_DB": {
            "keys": [
                "PORT_TABLE:Ethernet0"
            ],
            "tables_not_found": []
        },
        "ASIC_DB": {
            "keys": [
                "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF:oid:0xd00000000056d",
                "ASIC_STATE:SAI_OBJECT_TYPE_PORT:oid:0x10000000004a4"
            ],
            "tables_not_found": [],
            "vidtorid": {
                "oid:0xd00000000056d": "oid:0xd",
                "oid:0x10000000004a4": "oid:0x1690000000001"
            }
        },
        "STATE_DB": {
            "keys": [
                "PORT_TABLE|Ethernet0"
            ],
            "tables_not_found": []
        }
    }
}

admin@sonic:~$ dump state copp sample_packet --key-map
{
    "sample_packet": {
        "CONFIG_DB": {
            "keys": [],
            "tables_not_found": []
        },
        "APPL_DB": {
            "keys": [],
            "tables_not_found": [
                "COPP_TABLE"
            ]
        },
        "ASIC_DB": {
            "keys": [],
            "tables_not_found": [
                "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF_TRAP",
                "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF_TRAP_GROUP"
            ]
        },
        "STATE_DB": {
            "keys": [
                "COPP_TRAP_TABLE|sflow"
            ],
            "tables_not_found": [
                "COPP_GROUP_TABLE"
            ]
        },
        "CONFIG_FILE": {
            "keys": [
                "COPP_TRAP|sflow",
                "COPP_GROUP|queue2_group1"
            ],
            "tables_not_found": []
        }
    }
}

# db filtering using --db option
admin@sonic:~$ dump state copp arp_req --key-map --db ASIC_DB
{
    "arp_req": {
        "ASIC_DB": {
            "keys": [
                "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF_TRAP:oid:0x22000000000c5b",
                "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF_TRAP_GROUP:oid:0x11000000000c59",
                "ASIC_STATE:SAI_OBJECT_TYPE_POLICER:oid:0x12000000000c5a",
                "ASIC_STATE:SAI_OBJECT_TYPE_QUEUE:oid:0x15000000000626"
            ],
            "tables_not_found": [],
            "vidtorid": {
                "oid:0x22000000000c5b": "oid:0x200000000022",
                "oid:0x11000000000c59": "oid:0x300000011",
                "oid:0x12000000000c5a": "oid:0x200000012",
                "oid:0x15000000000626": "oid:0x12e0000040015"
            }
        }
    }
}


root@sonic# dump state port Ethernet0 --key-map --db CONFIG_DB --db ASIC_DB
{
    "Ethernet0": {
        "CONFIG_DB": {
            "keys": [
                "PORT|Ethernet0"
            ],
            "tables_not_found": []
        },
        "ASIC_DB": {
            "keys": [
                "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF:oid:0xd00000000056d",
                "ASIC_STATE:SAI_OBJECT_TYPE_PORT:oid:0x10000000004a4"
            ],
            "tables_not_found": [],
            "vidtorid": {
                "oid:0xd00000000056d": "oid:0xd",
                "oid:0x10000000004a4": "oid:0x1690000000001"
            }
        }
    }
}



root@sonic# dump state port Ethernet0 --key-map --db STATE_DB
{
    "Ethernet0": {
        "STATE_DB": {
            "keys": [
                "PORT_TABLE|Ethernet0"
            ],
            "tables_not_found": []
        }
    }
}

# Table display using --table/-t
root@sonic# dump state port Ethernet0 --key-map --db ASIC_DB --table
+-------------+-----------+-----------------------------------------------------------+
| port_name   | DB_NAME   | DUMP                                                      |
+=============+===========+===========================================================+
| Ethernet0   | ASIC_DB   | +-------------------------------------------------------+ |
|             |           | |                    Keys Collected                     | |
|             |           | +-------------------------------------------------------+ |
|             |           | | ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF:oid:0xd00000000056d | |
|             |           | |  ASIC_STATE:SAI_OBJECT_TYPE_PORT:oid:0x10000000004a4  | |
|             |           | +-------------------------------------------------------+ |
|             |           | +---------------------+---------------------+             |
|             |           | |         vid         |         rid         |             |
|             |           | +---------------------+---------------------+             |
|             |           | | oid:0xd00000000056d |       oid:0xd       |             |
|             |           | | oid:0x10000000004a4 | oid:0x1690000000001 |             |
|             |           | +---------------------+---------------------+             |
+-------------+-----------+-----------------------------------------------------------+

root@sonic# dump state port Ethernet0 --db APPL_DB --table
+-------------+-----------+---------------------------------------------------------------+
| port_name   | DB_NAME   | DUMP                                                          |
+=============+===========+===============================================================+
| Ethernet0   | APPL_DB   | +----------------------+------------------------------------+ |
|             |           | |         Keys         |         field-value pairs          | |
|             |           | +----------------------+------------------------------------+ |
|             |           | | PORT_TABLE:Ethernet0 | +--------------+-----------------+ | |
|             |           | |                      | | field        | value           | | |
|             |           | |                      | |--------------+-----------------| | |
|             |           | |                      | | admin_status | up              | | |
|             |           | |                      | | alias        | etp1            | | |
|             |           | |                      | | description  |                 | | |
|             |           | |                      | | index        | 1               | | |
|             |           | |                      | | lanes        | 0,1,2,3,4,5,6,7 | | |
|             |           | |                      | | mtu          | 9100            | | |
|             |           | |                      | | oper_status  | up              | | |
|             |           | |                      | | speed        | 100000          | | |
|             |           | |                      | +--------------+-----------------+ | |
|             |           | +----------------------+------------------------------------+ |
+-------------+-----------+---------------------------------------------------------------+

# Identifiers can take a list
root@sonic# dump state port Ethernet0,Ethernet8,Ethernet16 --key-map --db STATE_DB --table
+-------------+-----------+---------------------------+
| port_name   | DB_NAME   | DUMP                      |
+=============+===========+===========================+
| Ethernet0   | STATE_DB  | +----------------------+  |
|             |           | |    Keys Collected    |  |
|             |           | +----------------------+  |
|             |           | | PORT_TABLE|Ethernet0 |  |
|             |           | +----------------------+  |
+-------------+-----------+---------------------------+
| Ethernet8   | STATE_DB  | +----------------------+  |
|             |           | |    Keys Collected    |  |
|             |           | +----------------------+  |
|             |           | | PORT_TABLE|Ethernet8 |  |
|             |           | +----------------------+  |
+-------------+-----------+---------------------------+
| Ethernet16  | STATE_DB  | +-----------------------+ |
|             |           | |    Keys Collected     | |
|             |           | +-----------------------+ |
|             |           | | PORT_TABLE|Ethernet16 | |
|             |           | +-----------------------+ |
+-------------+-----------+---------------------------+

# 'all' use-case
root@sonic# dump state port all --key-map --db ASIC_DB
{
    "Ethernet52": {
        "ASIC_DB": {
            "keys": [
                "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF:oid:0xd0000000004b7",
                "ASIC_STATE:SAI_OBJECT_TYPE_PORT:oid:0x100000000048e"
            ],
            "tables_not_found": []
        },
        "vidtorid": {
            "oid:0xd0000000004b7": "oid:0xe0000000d",
            "oid:0x100000000048e": "oid:0x1040000000001"
        }
    },
    "Ethernet0": {
        "ASIC_DB": {
            "keys": [
                "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF:oid:0xd00000000056d",
                "ASIC_STATE:SAI_OBJECT_TYPE_PORT:oid:0x10000000004a4"
            ],
            "tables_not_found": [],
            "vidtorid": {
                "oid:0xd00000000056d": "oid:0xd",
                "oid:0x10000000004a4": "oid:0x1690000000001"
            }
        }
    },
    <Truncated>
}

# Specify the namespace from which the keys should be fetched from using --namespace
root@sonic# dump state port Ethernet0 --db APPL_DB --namespace asic0
{
    "Ethernet0": {
        "APPL_DB": {
            "keys": [
                {
                    "PORT_TABLE:Ethernet0": {
                        "lanes": "33,34,35,36",
                        "description": "ARISTA01T2:Ethernet3/1/1",
                        "pfc_asym": "off",
                        "mtu": "9100",
                        "alias": "Ethernet1/1",
                        "oper_status": "up",
                        "admin_status": "up",
                        "role": "Ext",
                        "speed": "40000",
                        "asic_port_name": "Eth0-ASIC0"
                    }
                }
            ],
            "tables_not_found": []
        }
    }
}

# Example usage for --verbose option
admin@r-lionfish-07:~$ dump state port Etheohffb --key-map --verbose
-----------------------
MatchRequest:
db:CONFIG_DB , table:PORT , key_regx:Etheohffb , just_keys:True Match Entire List: False
MatchRequest Checks Passed
MatchEngine:
No Entries found for Table|key_pattern provided
-----------------------
MatchRequest:
db:APPL_DB , table:PORT_TABLE , key_regx:Etheohffb , just_keys:True Match Entire List: False
MatchRequest Checks Passed
MatchEngine:
No Entries found for Table|key_pattern provided
-----------------------
MatchRequest:
db:ASIC_DB , table:ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF , key_regx:* , field:SAI_HOSTIF_ATTR_NAME , value:Etheohffb , just_keys:True Return Fields: SAI_HOSTIF_ATTR_OBJ_ID Match Entire List: False
MatchRequest Checks Passed
Filtered Keys:[]
MatchEngine:
No Keys found after applying the filtering criteria
-----------------------
MatchRequest:
db:STATE_DB , table:PORT_TABLE , key_regx:Etheohffb , just_keys:True Match Entire List: False
MatchRequest Checks Passed
MatchEngine:
No Entries found for Table|key_pattern provided
{
    "Etheohffb": {
        "CONFIG_DB": {
            "keys": [],
            "tables_not_found": [
                "PORT"
            ]
        },
        "APPL_DB": {
            "keys": [],
            "tables_not_found": [
                "PORT_TABLE"
            ]
        },
        "ASIC_DB": {
            "keys": [],
            "tables_not_found": [
                "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF",
                "ASIC_STATE:SAI_OBJECT_TYPE_PORT"
            ]
        },
        "STATE_DB": {
            "keys": [],
            "tables_not_found": [
                "PORT_TABLE"
            ]
        }
    }
}

admin@single-asic-sonic-device:~$ dump state port Ethernet0 --namespace asic0
Namespace option is not valid for a single-ASIC device

1.3 Extensibility

Utility should be open to extension i.e. any new modules can be added easily without the need to change the common logic. The common logic should be closed to modification unless there is a very specific use case which demands so.

1.4 Directory Structure

sonic-utilities/
       ├──── dump
             ├── __init__.py
             ├── .......
             ├── <Add any common logic here>
             ├── plugins/
                 ├── __init__.py
                 ├── executor.py
                 ├── copp.py
                 ├── port.py
                 ├── sflow.py
                 ├── ........
                 ├── <Add new modules here>

2 Design

2.0 The Executor Class

This is the base class which all the module classes should inherit from.

class Executor(ABC):

    ARG_NAME = "id" # Arg Identifier
    CONFIG_FILE = "" # Path to config file, if any

    @abstractmethod
    def execute(self, params):
        pass

    @abstractmethod
    def get_all_args(self, namespace):
        pass

2.1 Adding new Modules

To add a new module, these guidelines have to be followed.

  • Create a class which inherits from the Executor class. This should implement the execute() method.
  • The class name (converted to lower case) will be reflected in the click command and the name of the file, should also be the same.
  • Name of the argument is set to "arg". If this has to be changed, override ARG_NAME class variable.
  • This name specified in the "ARG_NAME" is reflected when the command dump state --show is run.
  • The Module Class should implement execute(arg) and get_all_args() method
  • If a CONFIG_FILE is used, update the class variable "CONFIG_FILE". More on this "CONFIG_FILE" in JSON Template 1
Requirements on the Module Class for execute(arg) method
  • The execute method will receive a dictionary. The value passed from the user can be fetched by using ARG_NAME i.e. args[ARG_NAME]
  • The execute method should return a dictionary of the format JSON Template 1.
  • Implementation of the execute method is upto the module implementer, all that is expected from the class here is to return the dictionary with the proper information populated.
JSON Template 1: Return dict by Executor
{
  "<DB_NAME>": {
        "keys": [],              # Relevant keys i.e. "Table<sep>key" info in the corresponding DB which are of interest
        "tables_not_found": []   # Populate this list with those table names, which are supposed to have the info which the module was looking for and yet it did not find one.
                                 # Again, the decision of which tables to look for and which of those are definitely supposed to have the information,
                                   is left to the discretion of the module implementer.
   }
}
Note: DB_NAME could be either of ["CONFIG_DB", "APPL_DB", "ASIC_DB", "STATE_DB", ....] or "CONFIG_FILE".
COPP is a example which will have a entry "CONFIG_FILE". This entry is required for COPP because, the default COPP entries are read from copp_cfg.json by coppmgr and are not present in the CONFIG_DB.  
Any extra entries which are added by the user are present in the CONFIG_DB. Hence it is required to have an extra "CONFIG_FILE" option.
Example JSON Template 1 Object:
This is an example return object from the module class for the interface name "Ethernet104" for the module "port". i.e. dump state port Ethernet104
{
    "CONFIG_DB": {
        "keys": ["PORT|Ethernet104"],
        "tables_not_found" : []
    },
    "APPL_DB": {
        "keys": ["PORT_TABLE:Ethernet104"],
        "tables_not_found" : []
    },
    "ASIC_DB": {
        "keys": ["ASIC_STATE:SAI_OBJECT_TYPE_PORT:oid:0x10000000003bd", "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF:oid:0xd00000000076e"],
        "tables_not_found": []
    }
    "STATE_DB": {
        "keys": ["PORT_TABLE|Ethernet104"],
        "tables_not_found": []
    }
}
Requirements on the Module Class for handling 'all' keyword
  • When the "all" argument is given by the user, get_all_args() method will be invoked and it's the responsibility of the module class to implement this.
  • get_all_args() should return a tuple of list and the list contains all the arguments for which the redis-state has to be returned.
    • Eg: For copp, get_all_args() should return a list of trap_ids i.e. (['arp_req', 'bgpv6', 'sample_packet',..........])
    • Eg: For port, this method will return a list of Interface names i.e (['Ethernet4', 'Ethernet8', 'Ethernet16',........])
  • An example implementation is given in the section 2.3
  • Using this information, The execute method will then be invoked for every value provided in the list.

Note: VidToRid Mapping, field-value data, db filtering, printing/formatting of output to stdout, inclusion in the techsupport output are all handled in the common logic and the module need not bother about these details.

2.2 Module Internals

Module Example 1: PORT
class Port(Executor):

    ARGS = "port_name"

    def get_all_args(self, namespace):
        all_port_names = []
        .......  # Find and fill this list of all_port_names,
        return (all_ports) #Eg: (['Ethernet0', 'Ethernet4', 'Ethernet8', 'Ethernet12', ....])

    def execute(self, param):
        self.template = display_template(dbs=["CONFIG_DB", "APPL_DB", "ASIC_DB"])
        port = param[ARG_NAME]
	ns = param["namespace"]  # namespace info, if any provided by the user
        get_config_info(port, ns) # Populate the return template with the info taken from Config DB
        get_appl_info(port, ns) # Populate the return template with the info taken from Appl DB
        get_asic_info(port, ns) # Populate the return template with the info taken from Asic DB
        ......... # Add the details for any other db's of interest
        return self.template

2.3 Helper Methods Available

List of available helper methods useful when drafting new Executor Modules
1) display_template(dbs=['CONFIG_DB', 'APPL_DB', 'ASIC_DB', 'STATE_DB']): Returns a dictionary of format JSON Template 1
2) MatchEngine / MatchRequest: Provided to abstract the heavy lifting in fetching the required data from redis-db/config-files. More info in the next section.
3) verbose_print(str_): prints to the stdout based on verbosity provided by the user. 
4) handle_error(err_str, excep=False): Prints the error output to stdout, if any experienced by the module, Set excep = True, to raise an exception
5) handle_multiple_keys_matched_error(err_str, key_to_go_with="", excep=False): When a filtering criteria specified by the module matches multiple keys, wherein it is expected to match ony one, this method can be used.

2.4 Match Infrastructure

Essentially consists of MatchEngine & MatchRequest.

Most of the heavy lifting in filling the return dictionary is in getting data out of redis and parse it based on user requirements. To Abstract this functionality out, a MatchEngine class is created. A MatchRequest object has to be passed to the fetch() method of the MatchEngine class

JSON Template 2: MatchRequest object:
{
  "Table": "<STR>",             # Mandatory, A Valid Table Name
  "key_pattern": "<STR>",       # Optional, Defaults to "*". Eg: "*" will match all the keys.
				# table<table_sep>key_pattern is directly applied for filtering entries  
  "field": "<STR>",             # Optional, Defaults to None
  "value": "<STR>",             # Optional, Value to match, Defaults to None
  "return_fields": [
    "<STR>"                     # An optional List of fields for which the corresponding values are returned
  ],
  "db": "<STR>",                # Optional, A Valid DB name, Defaults to "".
  "file": "*.json",             # Optional, A Valid Config JSON file, Eg: copp_cfg.json, Defaults to "".
                                # Only one of the db/file fields should have a non-empty string.
  "just_keys": "true|false"     # Mandatory, if true, Only Returns the keys matched. Does not return field-value pairs. Defaults to True
  "ns" : DEFAULT_NAMESPACE      # namespace argument, if nothing is provided, default namespace is used
  "match_entire_list" : False   # Some of the fields in redis can consist of multiple values eg: trap_ids = "bgp,bgpv6,ospf". 
  			          When this arg is set to true, entire list is matched incluing the ",". 
				  When False, the values are split based on "," and individual items are matched with
}
MatchEngine Usage Details
  • Case 1: field and value in the RMRequest are None. Result: RMEngine returns all the keys which are regex matched by "Table|key_pattern".
  • Case 2: field and value in the RMRequest are not None and a set of keys are matched by the "Table|key_pattern". Result: The RMEngine looks into each of these keys and returns those keys who has their field-value pairs equated to what is provided.
  • Case 3: For a valid combination of db, Table, key_pattern, field and value, if all the field-value pairs are required, set just_keys to true.
  • Case 4: For a valid combination of db, Table, key_pattern, field and value, if only a few specific fields are required, set just_keys to false and use return_fields option.
JSON Template 3: Return Dictionary by the MatchEngine:
{  
  "error": "<STR>",             # Error String, if any. Empty Otherwise
  "keys": [],                   # Match found for the request
  "return_values": {}           # Return Values for the corresponding return_fields passed
}

When the error string is not empty, the other two fields will be empty. Most of the errors thrown by the MatchEngine are usually due to ill-formed MatchRequest.

Possible Error strings returned by the MatchEngine.
 Errors thrown because of ill-formed MatchRequest:
 1) "Argument should be of type MatchRequest"
 2) "Either one of db or file in the request should be non-empty"
 3) "Only one of db or file should be provided"
 4) "DB provided is not valid"
 5) "JSON File not found"
 6) "Not a properly formatted JSON file"
 7) "'key_pattern' cannot be empty"
 8) "No 'table' name provided"
 9) "Field is provided, but no value is provided to compare with"
 10) "When Just_keys is set to False, return_fields should be empty"
 11) "Return Fields should be of list type"
 
 Other Errors:
 12) "No Entries found for Table|key_pattern provided.
 13) "Connection Error"
 14) "No Keys found after applying the filtering criteria"

 Note: Run the "dump state <feature/module> arg" command with -v option to print these errors any other exceptions thrown to the stdout. 

2.5 MatchRequest Examples:

1) Fetch the entry for ASIC_STATE:SAI_OBJECT_TYPE_QUEUE:oid:0x150000000002cf from ASIC_DB (Only Keys)

req = MatchRequest()
req.table = "ASIC_STATE:SAI_OBJECT_TYPE_QUEUE"
req.key_pattern = "oid:0x150000000002cf"
req.db = "ASIC_DB"
req.just_keys = True
req.return_fields = []

Return Dict:
{               
  "error": "",             
  "keys": ["ASIC_STATE:SAI_OBJECT_TYPE_QUEUE:oid:0x1500000000052f"],                  
  "return_values": {}       
}

2) Fetch the entry for ASIC_STATE:SAI_OBJECT_TYPE_QUEUE:oid:0x150000000002cf from ASIC_DB (Keys + Field-Value Pairs)

req = MatchRequest()
req.table = "ASIC_STATE:SAI_OBJECT_TYPE_QUEUE"
req.key_pattern = "oid:0x150000000002cf"
req.db = "ASIC_DB"
req.just_keys = False
req.return_fields = []

Return Dict:
{              
  "error": "",             
  "keys": [{"ASIC_STATE:SAI_OBJECT_TYPE_QUEUE:oid:0x1500000000052f": {
                    "NULL": "NULL",
                    "SAI_QUEUE_ATTR_TYPE": "SAI_QUEUE_TYPE_UNICAST",
                    "SAI_QUEUE_ATTR_INDEX": "4"}],                  
  "return_values": {}       
}


3) Fetch the entry for ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF_TRAP table which has trap type SAI_HOSTIF_TRAP_TYPE_BGPV6 from ASIC_DB

req = MatchRequest()
req.table = "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF_TRAP"
req.key_pattern = "*"
req.field = "SAI_HOSTIF_TRAP_ATTR_TRAP_TYPE"
req.value = "SAI_HOSTIF_TRAP_TYPE_BGPV6"
req.db = "ASIC_DB"
req.return_fields = ["SAI_HOSTIF_TRAP_ATTR_TRAP_GROUP"]

Return Dict:
{                
  "error": "",             
  "keys": ["ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF_TRAP:oid:0x22000000000592"],                  
  "return_values": {"ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF_TRAP:oid:0x22000000000592" : {"SAI_HOSTIF_TRAP_ATTR_TRAP_GROUP" : "oid:0x11000000000591"}}       
}

4) Fetch the entry for COPP_TRAP table which has trap_id sample_packet from the copp_cfg.json file

req = MatchRequest()
req.table = "COPP_TRAP"
req.key_pattern = "*"
req.field = "trap_ids"
req.value = "sample_packet"
req.file = "/etc/sonic/copp_cfg.json"
req.return_fields = ["trap_group"]

Return Dict:
{                
  "error": "",             
  "keys": ["COPP_TRAP|sflow"],                  
  "return_values": {"COPP_TRAP|sflow" : {"trap_group" : "queue2_group1"}}       
}

3 Unit Tests:

S.No Test case synopsis
1 Verify MatchEngine funtionality in cases of invalid Request Objects
2 Verify MatchEngine Match functionality is as expected
3 Verify all the options in the CLI is working as expected
4 Verify the namespace arg is working as expected
5 Verify dump cli options are working as expected
6 Unit tests should be added for every new module added

4 TechSupport

Output for every <feature/module> which extends from Executor class will be added to the techsupport dump. Every Json file will have the corresponding output: dump state <corresponding_feature> all -k. Output will be printed in JSON format for TechSupport Dumps. Only the related keys information will be present in the unified_dump_folder as entire DB dumps are already present in the dump/folder. When operating on a Multi-Asic platform, the file will have a suffix signifying the namespace i.e. eg: "port.asic0" etc

$BASE
   ├──── dump/
         ├── unified_view_dump/
             ├── copp
             ├── port
             ├── <random_feature>
             ├── .......
             ├── <One file for every feature should be present here>        
   ├──── etc/
   ├──── log/  
   ├──── ......
   ├──── ......