def is_warm_restart_enabled(container_name): state_db = SonicV2Connector(host='127.0.0.1') state_db.connect(state_db.STATE_DB, False) TABLE_NAME_SEPARATOR = '|' prefix = 'WARM_RESTART_ENABLE_TABLE' + TABLE_NAME_SEPARATOR # Get the system warm reboot enable state _hash = '{}{}'.format(prefix, 'system') wr_system_state = state_db.get(state_db.STATE_DB, _hash, "enable") wr_enable_state = True if wr_system_state == "true" else False # Get the container warm reboot enable state _hash = '{}{}'.format(prefix, container_name) wr_container_state = state_db.get(state_db.STATE_DB, _hash, "enable") wr_enable_state |= True if wr_container_state == "true" else False state_db.close(state_db.STATE_DB) return wr_enable_state
def reinit_data(self): """ Re-initialize all data. """ # reinit cache self.physical_classes_map = {} self.physical_description_map = {} self.physical_hw_version_map = {} self.physical_serial_number_map = {} self.physical_mfg_name_map = {} self.physical_model_name_map = {} # update interface maps _, self.if_alias_map, _, _, _ = \ mibs.init_sync_d_interface_tables(SonicV2Connector()) device_metadata = mibs.get_device_metadata(self.statedb) chassis_sub_id = (self.CHASSIS_ID, ) self.physical_entities = [chassis_sub_id] if not device_metadata or not device_metadata.get(b"chassis_serial_number"): chassis_serial_number = "" else: chassis_serial_number = device_metadata[b"chassis_serial_number"] self.physical_classes_map[chassis_sub_id] = PhysicalClass.CHASSIS self.physical_serial_number_map[chassis_sub_id] = chassis_serial_number # retrieve the initial list of transceivers that are present in the system transceiver_info = self.statedb.keys(self.statedb.STATE_DB, self.TRANSCEIVER_KEY_PATTERN) if transceiver_info: self.transceiver_entries = [entry.decode() \ for entry in transceiver_info] else: self.transceiver_entries = [] # update cache with initial data for transceiver_entry in self.transceiver_entries: # extract interface name interface = transceiver_entry.split(mibs.TABLE_NAME_SEPARATOR_VBAR)[-1] self._update_transceiver_cache(interface)
def get_chassis_info(): """ This function is used to get the Chassis serial / model / rev number """ chassis_info_dict = {} try: # Init statedb connection db = SonicV2Connector() db.connect(db.STATE_DB) table = CHASSIS_INFO_TABLE.format(1) chassis_info_dict['serial'] = db.get(db.STATE_DB, table, CHASSIS_INFO_SERIAL_FIELD) chassis_info_dict['model'] = db.get(db.STATE_DB, table, CHASSIS_INFO_MODEL_FIELD) chassis_info_dict['revision'] = db.get(db.STATE_DB, table, CHASSIS_INFO_REV_FIELD) except Exception: pass return chassis_info_dict
def __init__(self): super().__init__() self.statedb = SonicV2Connector() self.statedb.connect(self.statedb.STATE_DB) self.if_alias_map = {} # List of available sub OIDs. self.physical_entities = [] # Map sub ID to its data. self.physical_classes_map = {} self.physical_description_map = {} self.physical_hw_version_map = {} self.physical_serial_number_map = {} self.physical_mfg_name_map = {} self.physical_model_name_map = {} self.pubsub = None
def __init__(self): REDIS_TIMEOUT_MS = 0 # Update this list to support more interfaces tbl_lst = [ swsscommon.STATE_PORT_TABLE_NAME, swsscommon.STATE_VLAN_TABLE_NAME ] self.appl_db = swsscommon.DBConnector("STATE_DB", REDIS_TIMEOUT_MS, True) self.state_db = SonicV2Connector(host='127.0.0.1', decode_responses=True) self.state_db.connect(self.state_db.STATE_DB, False) self.sel = swsscommon.Select() self.tbls = [ swsscommon.SubscriberStateTable(self.appl_db, t) for t in tbl_lst ] self.cur_interfaces = {} for t in self.tbls: self.sel.addSelectable(t)
def __init__(self): """ ctor """ super().__init__() self.statedb = SonicV2Connector() self.statedb.connect(self.statedb.STATE_DB) # list of available sub OIDs self.sub_ids = [] # sensor MIB requiered values self.ent_phy_sensor_type_map = {} self.ent_phy_sensor_scale_map = {} self.ent_phy_sensor_precision_map = {} self.ent_phy_sensor_value_map = {} self.ent_phy_sensor_oper_state_map = {} self.transceiver_dom = []
def remotevtep(count): """Show All Remote VTEP Information""" if (count is not None) and (count != 'count'): click.echo("Unacceptable argument {}".format(count)) return header = ['SIP', 'DIP', 'Creation Source', 'OperStatus'] body = [] db = SonicV2Connector(host='127.0.0.1') db.connect(db.STATE_DB) vxlan_keys = db.keys(db.STATE_DB, 'VXLAN_TUNNEL_TABLE|*') if vxlan_keys is not None: vxlan_count = len(vxlan_keys) else: vxlan_count = 0 if (count is not None): output = 'Total count : ' output += ('%s \n' % (str(vxlan_count))) click.echo(output) else: num = 0 if vxlan_keys is not None: for key in natsorted(vxlan_keys): vxlan_table = db.get_all(db.STATE_DB, key); if vxlan_table is None: continue body.append([vxlan_table['src_ip'], vxlan_table['dst_ip'], vxlan_table['tnl_src'], 'oper_' + vxlan_table['operstatus']]) num += 1 click.echo(tabulate(body, header, tablefmt="grid")) output = 'Total count : ' output += ('%s \n' % (str(num))) click.echo(output)
def __connect_to_redis(self): '''! Establishes connection to the redis DB @return False - If connection to the redis DB failed True - If connection to the redis DB is successful ''' # Connect to ConfigDB try: if self.configDB is None: self.configDB = ConfigDBConnector() self.configDB.connect() except: self.configDB = None return False # Connect to AppDB try: if self.applDB is None: self.applDB = SonicV2Connector() self.applDB.connect(self.applDB.APPL_DB) except: self.applDB = None return False return True
def state(redis_unix_socket_path): """Show warm restart state""" kwargs = {} if redis_unix_socket_path: kwargs['unix_socket_path'] = redis_unix_socket_path data = {} db = SonicV2Connector(host='127.0.0.1') db.connect(db.STATE_DB, False) # Make one attempt only TABLE_NAME_SEPARATOR = '|' prefix = 'WARM_RESTART_TABLE' + TABLE_NAME_SEPARATOR _hash = '{}{}'.format(prefix, '*') table_keys = db.keys(db.STATE_DB, _hash) def remove_prefix(text, prefix): if text.startswith(prefix): return text[len(prefix):] return text table = [] for tk in table_keys: entry = db.get_all(db.STATE_DB, tk) r = [] r.append(remove_prefix(tk, prefix)) r.append(entry['restore_count']) if 'state' not in entry: r.append("") else: r.append(entry['state']) table.append(r) header = ['name', 'restore_count', 'state'] click.echo(tabulate(table, header))
def upgrade_docker(container_name, url, cleanup_image, skip_check, tag, warm): """ Upgrade docker image from local binary or URL""" # Warn the user if they are calling the deprecated version of the subcommand (with an underscore instead of a hyphen) if "upgrade_docker" in sys.argv: print_deprecation_warning("upgrade_docker", "upgrade-docker") image_name = get_container_image_name(container_name) image_latest = image_name + ":latest" image_id_previous = get_container_image_id(image_latest) DEFAULT_IMAGE_PATH = os.path.join("/tmp/", image_name) if url.startswith('http://') or url.startswith('https://'): click.echo('Downloading image...') validate_url_or_abort(url) try: urllib.urlretrieve(url, DEFAULT_IMAGE_PATH, reporthook) except Exception as e: click.echo("Download error", e) raise click.Abort() image_path = DEFAULT_IMAGE_PATH else: image_path = os.path.join("./", url) # Verify that the local file exists and is a regular file # TODO: Verify the file is a *proper Docker image file* if not os.path.isfile(image_path): click.echo("Image file '{}' does not exist or is not a regular file. Aborting...".format(image_path)) raise click.Abort() warm_configured = False # warm restart enable/disable config is put in stateDB, not persistent across cold reboot, not saved to config_DB.json file state_db = SonicV2Connector(host='127.0.0.1') state_db.connect(state_db.STATE_DB, False) TABLE_NAME_SEPARATOR = '|' prefix = 'WARM_RESTART_ENABLE_TABLE' + TABLE_NAME_SEPARATOR _hash = '{}{}'.format(prefix, container_name) if state_db.get(state_db.STATE_DB, _hash, "enable") == "true": warm_configured = True state_db.close(state_db.STATE_DB) if container_name == "swss" or container_name == "bgp" or container_name == "teamd": if warm_configured is False and warm: run_command("config warm_restart enable %s" % container_name) # Fetch tag of current running image tag_previous = get_docker_tag_name(image_latest) # Load the new image beforehand to shorten disruption time run_command("docker load < %s" % image_path) warm_app_names = [] # warm restart specific procssing for swss, bgp and teamd dockers. if warm_configured is True or warm: # make sure orchagent is in clean state if swss is to be upgraded if container_name == "swss": skipPendingTaskCheck = "" if skip_check: skipPendingTaskCheck = " -s" cmd = "docker exec -i swss orchagent_restart_check -w 2000 -r 5 " + skipPendingTaskCheck proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) (out, err) = proc.communicate() if proc.returncode != 0: if not skip_check: click.echo("Orchagent is not in clean state, RESTARTCHECK failed") # Restore orignal config before exit if warm_configured is False and warm: run_command("config warm_restart disable %s" % container_name) # Clean the image loaded earlier image_id_latest = get_container_image_id(image_latest) run_command("docker rmi -f %s" % image_id_latest) # Re-point latest tag to previous tag run_command("docker tag %s:%s %s" % (image_name, tag_previous, image_latest)) sys.exit(proc.returncode) else: click.echo("Orchagent is not in clean state, upgrading it anyway") else: click.echo("Orchagent is in clean state and frozen for warm upgrade") warm_app_names = ["orchagent", "neighsyncd"] elif container_name == "bgp": # Kill bgpd to restart the bgp graceful restart procedure click.echo("Stopping bgp ...") run_command("docker exec -i bgp pkill -9 zebra") run_command("docker exec -i bgp pkill -9 bgpd") warm_app_names = ["bgp"] click.echo("Stopped bgp ...") elif container_name == "teamd": click.echo("Stopping teamd ...") # Send USR1 signal to all teamd instances to stop them # It will prepare teamd for warm-reboot run_command("docker exec -i teamd pkill -USR1 teamd > /dev/null") warm_app_names = ["teamsyncd"] click.echo("Stopped teamd ...") # clean app reconcilation state from last warm start if exists for warm_app_name in warm_app_names: hdel_warm_restart_table("STATE_DB", "WARM_RESTART_TABLE", warm_app_name, "state") run_command("docker kill %s > /dev/null" % container_name) run_command("docker rm %s " % container_name) if tag is None: # example image: docker-lldp-sv2:latest tag = get_docker_tag_name(image_latest) run_command("docker tag %s:latest %s:%s" % (image_name, image_name, tag)) run_command("systemctl restart %s" % container_name) # All images id under the image name image_id_all = get_container_image_id_all(image_name) # this is image_id for image with "latest" tag image_id_latest = get_container_image_id(image_latest) for id in image_id_all: if id != image_id_latest: # Unless requested, the previoud docker image will be preserved if not cleanup_image and id == image_id_previous: continue run_command("docker rmi -f %s" % id) exp_state = "reconciled" state = "" # post warm restart specific procssing for swss, bgp and teamd dockers, wait for reconciliation state. if warm_configured is True or warm: count = 0 for warm_app_name in warm_app_names: state = "" # Wait up to 180 seconds for reconciled state while state != exp_state and count < 90: sys.stdout.write("\r {}: ".format(warm_app_name)) sys.stdout.write("[%-s" % ('='*count)) sys.stdout.flush() count += 1 time.sleep(2) state = hget_warm_restart_table("STATE_DB", "WARM_RESTART_TABLE", warm_app_name, "state") log.log_notice("%s reached %s state" % (warm_app_name, state)) sys.stdout.write("]\n\r") if state != exp_state: click.echo("%s failed to reach %s state" % (warm_app_name, exp_state)) log.log_error("%s failed to reach %s state" % (warm_app_name, exp_state)) else: exp_state = "" # this is cold upgrade # Restore to previous cold restart setting if warm_configured is False and warm: if container_name == "swss" or container_name == "bgp" or container_name == "teamd": run_command("config warm_restart disable %s" % container_name) if state == exp_state: click.echo('Done') else: click.echo('Failed') sys.exit(1)
def hdel_warm_restart_table(db_name, table_name, warm_app_name, key): db = SonicV2Connector() db.connect(db_name, False) _hash = table_name + db.get_db_separator(db_name) + warm_app_name client = db.get_redis_client(db_name) return client.hdel(_hash, key)
def hash_view(nhg): config_db = ConfigDBConnector() config_db.connect() fg_nhg_prefix_table = {} fg_nhg_alias = {} fg_nhg_prefix_table = config_db.get_table('FG_NHG_PREFIX') for key, value in fg_nhg_prefix_table.items(): fg_nhg_alias[key] = value['FG_NHG'] state_db = SonicV2Connector(host='127.0.0.1') state_db.connect(state_db.STATE_DB, False) # Make one attempt only STATE_DB TABLE_NAME_SEPARATOR = '|' prefix = 'FG_ROUTE_TABLE' + TABLE_NAME_SEPARATOR _hash = '{}{}'.format(prefix, '*') table_keys = [] table_keys = state_db.keys(state_db.STATE_DB, _hash) t_dict = {} table = [] output_dict = {} bank_dict = {} if nhg is None: for nhg_prefix in table_keys: bank_dict = {} t_dict = state_db.get_all(state_db.STATE_DB, nhg_prefix) vals = sorted(set([val for val in t_dict.values()])) for nh_ip in vals: bank_ids = sorted( [int(k) for k, v in t_dict.items() if v == nh_ip]) bank_ids = [str(x) for x in bank_ids] if nhg_prefix in output_dict: output_dict[nhg_prefix].append(nh_ip.split("@")[0]) else: output_dict[nhg_prefix] = [nh_ip.split("@")[0]] bank_dict[nh_ip.split("@")[0]] = bank_ids bank_dict = OrderedDict(sorted(bank_dict.items())) nhg_prefix_report = (nhg_prefix.split("|")[1]) header = ["FG_NHG_PREFIX", "Next Hop", "Hash buckets"] for nhip, val in bank_dict.items(): formatted_banks = ','.replace(',', '\n').join(bank_dict[nhip]) table.append([nhg_prefix_report, nhip, formatted_banks]) click.echo(tabulate(table, header, tablefmt="grid")) else: for nhg_prefix, alias in fg_nhg_alias.items(): if nhg == alias: if ":" in nhg_prefix: for key in table_keys: mod_key = key.split("|")[1].split("/")[0] mod_nhg_prefix = nhg_prefix.split("/")[0] if ipaddress.ip_address(unicode( mod_key)).exploded == ipaddress.ip_address( unicode(mod_nhg_prefix)).exploded: t_dict = state_db.get_all(state_db.STATE_DB, key) nhg_prefix = "FG_ROUTE_TABLE|" + nhg_prefix else: nhg_prefix = "FG_ROUTE_TABLE|" + nhg_prefix t_dict = state_db.get_all(state_db.STATE_DB, nhg_prefix) vals = sorted(set([val for val in t_dict.values()])) for nh_ip in vals: bank_ids = sorted( [int(k) for k, v in t_dict.items() if v == nh_ip]) bank_ids = [str(x) for x in bank_ids] if nhg_prefix in output_dict: output_dict[nhg_prefix].append(nh_ip.split("@")[0]) else: output_dict[nhg_prefix] = [nh_ip.split("@")[0]] bank_dict[nh_ip.split("@")[0]] = bank_ids nhg_prefix_report = (nhg_prefix.split("|")[1]) bank_dict = OrderedDict(sorted(bank_dict.items())) header = ["FG_NHG_PREFIX", "Next Hop", "Hash buckets"] for nhip, val in bank_dict.items(): formatted_banks = ','.replace(',', '\n').join(bank_dict[nhip]) table.append([nhg_prefix_report, nhip, formatted_banks]) click.echo(tabulate(table, header, tablefmt="grid"))
def __init__(self, update_interval=None): super(LldpSyncDaemon, self).__init__() self._update_interval = update_interval or DEFAULT_UPDATE_INTERVAL self.db_connector = SonicV2Connector() self.db_connector.connect(self.db_connector.APPL_DB)
raise click.Abort() image_path = DEFAULT_IMAGE_PATH else: image_path = os.path.join("./", url) # Verify that the local file exists and is a regular file # TODO: Verify the file is a *proper Docker image file* if not os.path.isfile(image_path): click.echo( "Image file '{}' does not exist or is not a regular file. Aborting..." .format(image_path)) raise click.Abort() warm_configured = False # warm restart enable/disable config is put in stateDB, not persistent across cold reboot, not saved to config_DB.json file state_db = SonicV2Connector(host='127.0.0.1') state_db.connect(state_db.STATE_DB, False) TABLE_NAME_SEPARATOR = '|' prefix = 'WARM_RESTART_ENABLE_TABLE' + TABLE_NAME_SEPARATOR _hash = '{}{}'.format(prefix, container_name) if state_db.get(state_db.STATE_DB, _hash, "enable") == "true": warm_configured = True state_db.close(state_db.STATE_DB) if container_name == "swss" or container_name == "bgp" or container_name == "teamd": if warm_configured == False and warm: run_command("config warm_restart enable %s" % container_name) # Fetch tag of current running image tag_previous = get_docker_tag_name(image_latest) # Load the new image beforehand to shorten disruption time
def add_udp(ctx, global_ip, global_port, local_ip, local_port, nat_type, twice_nat_id): """Add Static UDP Protocol NAPT-related configutation""" # Verify the ip address format if is_valid_ipv4_address(local_ip) is False: ctx.fail( "Given local ip address {} is invalid. Please enter a valid local ip address !!" .format(local_ip)) if is_valid_ipv4_address(global_ip) is False: ctx.fail( "Given global ip address {} is invalid. Please enter a valid global ip address !!" .format(global_ip)) config_db = ConfigDBConnector() config_db.connect() entryFound = False table = "STATIC_NAPT" key = "{}|UDP|{}".format(global_ip, global_port) dataKey1 = 'local_ip' dataKey2 = 'local_port' dataKey3 = 'nat_type' dataKey4 = 'twice_nat_id' data = config_db.get_entry(table, key) if data: if data[dataKey1] == local_ip and data[dataKey2] == str(local_port): click.echo( "Trying to add static napt entry, which is already present.") entryFound = True if nat_type == 'snat': ipAddress = local_ip else: ipAddress = global_ip if isIpOverlappingWithAnyStaticEntry(ipAddress, 'STATIC_NAT') is True: ctx.fail("Given entry is overlapping with existing NAT entry !!") if entryFound is False: counters_db = SonicV2Connector() counters_db.connect(counters_db.COUNTERS_DB) snat_entries = 0 max_entries = 0 exists = counters_db.exists(counters_db.COUNTERS_DB, 'COUNTERS_GLOBAL_NAT:Values') if exists: counter_entry = counters_db.get_all(counters_db.COUNTERS_DB, 'COUNTERS_GLOBAL_NAT:Values') if 'SNAT_ENTRIES' in counter_entry: snat_entries = counter_entry['SNAT_ENTRIES'] if 'MAX_NAT_ENTRIES' in counter_entry: max_entries = counter_entry['MAX_NAT_ENTRIES'] if int(snat_entries) >= int(max_entries): click.echo( "Max limit is reached for NAT entries, skipping adding the entry." ) entryFound = True if entryFound is False: count = 0 if twice_nat_id is not None: count = getTwiceNatIdCountWithStaticEntries( twice_nat_id, table, count) count = getTwiceNatIdCountWithDynamicBinding( twice_nat_id, count, None) if count > 1: ctx.fail( "Same Twice nat id is not allowed for more than 2 entries!!" ) if nat_type is not None and twice_nat_id is not None: config_db.set_entry( table, key, { dataKey1: local_ip, dataKey2: local_port, dataKey3: nat_type, dataKey4: twice_nat_id }) elif nat_type is not None: config_db.set_entry(table, key, { dataKey1: local_ip, dataKey2: local_port, dataKey3: nat_type }) elif twice_nat_id is not None: config_db.set_entry(table, key, { dataKey1: local_ip, dataKey2: local_port, dataKey4: twice_nat_id }) else: config_db.set_entry(table, key, { dataKey1: local_ip, dataKey2: local_port })
def mock_dedicated_appl_db(self, filename): jsonfile = os.path.join(mock_db_path, 'appl_db', filename) dbconnector.dedicated_dbs['APPL_DB'] = jsonfile appl_db = SonicV2Connector(host='127.0.0.1') appl_db.connect(appl_db.APPL_DB) return appl_db
def create_dbconnector(): db = SonicV2Connector() db.connect(db.APPL_DB) return db
def __init__(self): HealthChecker.__init__(self) self._db = SonicV2Connector(host="127.0.0.1") self._db.connect(self._db.STATE_DB)
def init_sync_d_interface_tables(): """ DRY helper method. Connects to and initializes interface maps for SyncD-connected MIB(s). :return: tuple(db_conn, if_name_map, if_id_map, oid_map, if_alias_map) """ # SyncD database connector. THIS MUST BE INITIALIZED ON A PER-THREAD BASIS. # Redis PubSub objects (such as those within swsssdk) are NOT thread-safe. db_conn = SonicV2Connector(**redis_kwargs) db_conn.connect(COUNTERS_DB) # { if_name (SONiC) -> sai_id } # ex: { "Ethernet76" : "1000000000023" } if_name_map = db_conn.get_all(COUNTERS_DB, COUNTERS_PORT_NAME_MAP, blocking=True) logger.debug("Port name map:\n" + pprint.pformat(if_name_map, indent=2)) # { sai_id -> if_name (SONiC) } if_id_map = { sai_id: if_name for if_name, sai_id in if_name_map.items() # only map the interface if it's a style understood to be a SONiC interface. if get_index(if_name) is not None } logger.debug("Interface name map:\n" + pprint.pformat(if_id_map, indent=2)) # { OID -> sai_id } oid_sai_map = { get_index(if_name): sai_id for if_name, sai_id in if_name_map.items() # only map the interface if it's a style understood to be a SONiC interface. if get_index(if_name) is not None } logger.debug("OID sai map:\n" + pprint.pformat(oid_sai_map, indent=2)) # { OID -> if_name (SONiC) } oid_name_map = { get_index(if_name): if_name for if_name in if_name_map # only map the interface if it's a style understood to be a SONiC interface. if get_index(if_name) is not None } logger.debug("OID name map:\n" + pprint.pformat(oid_name_map, indent=2)) # SyncD consistency checks. if not oid_sai_map: # In the event no interface exists that follows the SONiC pattern, no OIDs are able to be registered. # A RuntimeError here will prevent the 'main' module from loading. (This is desirable.) message = "No interfaces found matching pattern '{}'. SyncD database is incoherent." \ .format(SONIC_ETHERNET_RE_PATTERN) logger.error(message) raise RuntimeError(message) elif len(if_id_map) < len(if_name_map) or len(oid_sai_map) < len( if_name_map): # a length mismatch indicates a bad interface name logger.warning( "SyncD database contains incoherent interface names. Interfaces must match pattern '{}'" .format(SONIC_ETHERNET_RE_PATTERN)) logger.warning("Port name map:\n" + pprint.pformat(if_name_map, indent=2)) # { SONiC name -> optional rename } if_alias_map = _if_alias_map logger.debug("Chassis name map:\n" + pprint.pformat(if_alias_map, indent=2)) if if_alias_map is None or len(if_alias_map) == 0: logger.warning("No alias map found--port names will use SONiC names.") if_alias_map = dict(zip(if_name_map.keys(), if_name_map.keys())) return db_conn, if_name_map, if_alias_map, if_id_map, oid_sai_map, oid_name_map
def __init__(self): """ init the handler """ self.statedb = SonicV2Connector() self.statedb.connect(self.statedb.STATE_DB)
def pcie_aer_display(ctx, severity): device_key = ctx.params['device_key'] no_zero = not ctx.params['verbose'] header = ["AER - " + severity.upper().replace("_", "")] fields = aer_fields[severity] pcie_dev_list = list() dev_found = False statedb = SonicV2Connector() statedb.connect(statedb.STATE_DB) table = OrderedDict() for field in fields: table[field] = [field] if device_key: pcie_dev_list = ["PCIE_DEVICE|%s" % device_key] else: keys = statedb.keys(statedb.STATE_DB, "PCIE_DEVICE|*") if keys: pcie_dev_list = sorted(keys) for pcie_dev_key in pcie_dev_list: aer_attribute = statedb.get_all(statedb.STATE_DB, pcie_dev_key) if not aer_attribute: continue if device_key: dev_found = True if no_zero and all(val == '0' for key, val in aer_attribute.items() if key.startswith(severity)): continue pcie_dev = pcie_dev_key.split("|")[1] Id = aer_attribute['id'] # Tabulate Header device_name = "%s\n%s" % (pcie_dev, Id) header.append(device_name) # Tabulate Row for field in fields: key = severity + "|" + field table[field].append(aer_attribute.get(key, 'NA')) if device_key and not dev_found: ctx.exit("Device not found in DB") # Strip fields with no non-zero value if no_zero: for field in fields: if all(val == '0' for val in table[field][1:]): del table[field] if not (no_zero and (len(header) == 1)): if ctx.obj: click.echo("") click.echo(tabulate(list(table.values()), header, tablefmt="grid")) ctx.obj = True