Perform a snmpwalk on the domain specified by the oids, on the device
        configured in instance.
        lookup_names is a boolean to specify whether or not to use the mibs to
        resolve the name and values.

        Returns a dictionary:
        dict[oid/metric_name][row index] = value
        In case of scalar objects, the row index is just 0

def check_table(
        self,
        instance,
        snmp_engine,
        mib_view_controller,
        oids,
        lookup_names,
        timeout,
        retries,
        enforce_constraints=False,
        mibs_to_load=None,
    ):
        '''
        Perform a snmpwalk on the domain specified by the oids, on the device
        configured in instance.
        lookup_names is a boolean to specify whether or not to use the mibs to
        resolve the name and values.

        Returns a dictionary:
        dict[oid/metric_name][row index] = value
        In case of scalar objects, the row index is just 0
        '''
        # UPDATE: We used to perform only a snmpgetnext command to fetch metric values.
        # It returns the wrong value when the OID passeed is referring to a specific leaf.
        # For example:
        # snmpgetnext -v2c -c public localhost:11111 1.3.6.1.2.1.25.4.2.1.7.222
        # iso.3.6.1.2.1.25.4.2.1.7.224 = INTEGER: 2
        # SOLUTION: perform a snmpget command and fallback with snmpgetnext if not found

        # Set aliases for snmpget and snmpgetnext with logging
        transport_target = self.get_transport_target(instance, timeout, retries)
        auth_data = self.get_auth_data(instance)
        context_engine_id, context_name = self.get_context_data(instance)

        first_oid = 0
        all_binds = []
        results = defaultdict(dict)

        while first_oid < len(oids):
            try:
                # Start with snmpget command
                oids_batch = oids[first_oid : first_oid + self.oid_batch_size]
                self.log.debug("Running SNMP command get on OIDS {}".format(oids_batch))
                error_indication, error_status, error_index, var_binds = next(
                    hlapi.getCmd(
                        snmp_engine,
                        auth_data,
                        transport_target,
                        hlapi.ContextData(context_engine_id, context_name),
                        *(oids_batch),
                        lookupMib=enforce_constraints
                    )
                )
                self.log.debug("Returned vars: {}".format(var_binds))

                # Raise on error_indication
                self.raise_on_error_indication(error_indication, instance)

                missing_results = []
                complete_results = []

                for var in var_binds:
                    result_oid, value = var
                    if reply_invalid(value):
                        oid_tuple = result_oid.asTuple()
                        missing_results.append(hlapi.ObjectType(hlapi.ObjectIdentity(oid_tuple)))
                    else:
                        complete_results.append(var)

                if missing_results:
                    # If we didn't catch the metric using snmpget, try snmpnext
                    self.log.debug("Running SNMP command getNext on OIDS {}".format(missing_results))
                    for error_indication, error_status, _, var_binds_table in hlapi.nextCmd(
                        snmp_engine,
                        auth_data,
                        transport_target,
                        hlapi.ContextData(context_engine_id, context_name),
                        *missing_results,
                        lookupMib=enforce_constraints,
                        ignoreNonIncreasingOid=self.ignore_nonincreasing_oid,
                        lexicographicMode=False  # Don't walk through the entire MIB, stop at end of table
                    ):

                        self.log.debug("Returned vars: {}".format(var_binds_table))
                        # Raise on error_indication
                        self.raise_on_error_indication(error_indication, instance)

                        if error_status:
                            message = "{} for instance {}".format(error_status.prettyPrint(), instance["ip_address"])
                            instance["service_check_error"] = message

                            # submit CRITICAL service check if we can't connect to device
                            if 'unknownUserName' in message:
                                instance["service_check_severity"] = Status.CRITICAL
                                self.log.error(message)
                            else:
                                self.warning(message)

                        for table_row in var_binds_table:
                            complete_results.append(table_row)

                all_binds.extend(complete_results)

            except PySnmpError as e:
                if "service_check_error" not in instance:
                    instance["service_check_error"] = "Fail to collect some metrics: {}".format(e)
                if "service_check_severity" not in instance:
                    instance["service_check_severity"] = Status.CRITICAL
                self.warning("Fail to collect some metrics: {}".format(e))

            # if we fail move onto next batch
            first_oid = first_oid + self.oid_batch_size

        # if we've collected some variables, it's not that bad.
        if "service_check_severity" in instance and len(all_binds):
            instance["service_check_severity"] = Status.WARNING

        for result_oid, value in all_binds:
            if lookup_names:
                if not enforce_constraints:
                    # if enforce_constraints is false, then MIB resolution has not been done yet
                    # so we need to do it manually. We have to specify the mibs that we will need
                    # to resolve the name.
                    oid_to_resolve = hlapi.ObjectIdentity(result_oid.asTuple()).loadMibs(*mibs_to_load)
                    result_oid = oid_to_resolve.resolveWithMib(mib_view_controller)
                _, metric, indexes = result_oid.getMibSymbol()
                results[metric][indexes] = value
            else:
                oid = result_oid.asTuple()
                matching = ".".join([str(i) for i in oid])
                results[matching] = value
        self.log.debug("Raw results: {}".format(results))
        return results