def network(ipaddress, info_type, namespace): """Show IP (IPv4) BGP network""" if multi_asic.is_multi_asic() and namespace not in multi_asic.get_namespace_list(): ctx = click.get_current_context() ctx.fail('-n/--namespace option required. provide namespace from list {}'\ .format(multi_asic.get_namespace_list())) command = 'show ip bgp' if ipaddress is not None: if '/' in ipaddress: # For network prefixes then this all info_type(s) are available pass else: # For an ipaddress then check info_type, exit if specified option doesn't work. if info_type in ['longer-prefixes']: click.echo('The parameter option: "{}" only available if passing a network prefix'.format(info_type)) click.echo("EX: 'show ip bgp network 10.0.0.0/24 longer-prefixes'") raise click.Abort() command += ' {}'.format(ipaddress) # info_type is only valid if prefix/ipaddress is specified if info_type is not None: command += ' {}'.format(info_type) output = bgp_util.run_bgp_command(command, namespace) click.echo(output.rstrip('\n'))
def state(ctx, module, identifier, db, table, key_map, verbose, namespace): """ Dump the current state of the identifier for the specified module from Redis DB or CONFIG_FILE """ if not multi_asic.is_multi_asic() and namespace != DEFAULT_NAMESPACE: click.echo("Namespace option is not valid for a single-ASIC device") ctx.exit() if multi_asic.is_multi_asic() and (namespace != DEFAULT_NAMESPACE and namespace not in multi_asic.get_namespace_list()): click.echo("Namespace option is not valid. Choose one of {}".format( multi_asic.get_namespace_list())) ctx.exit() if module not in plugins.dump_modules: click.echo("No Matching Plugin has been Implemented") ctx.exit() if verbose: os.environ["VERBOSE"] = "1" else: os.environ["VERBOSE"] = "0" ctx.module = module obj = plugins.dump_modules[module]() if identifier == "all": ids = obj.get_all_args(namespace) else: ids = identifier.split(",") params = {} collected_info = {} params['namespace'] = namespace for arg in ids: params[plugins.dump_modules[module].ARG_NAME] = arg try: collected_info[arg] = obj.execute(params) except ValueError as err: click.fail(f"Failed to execute plugin: {err}") if len(db) > 0: collected_info = filter_out_dbs(db, collected_info) vidtorid = extract_rid(collected_info, namespace) if not key_map: collected_info = populate_fv(collected_info, module, namespace) for id in vidtorid.keys(): collected_info[id]["ASIC_DB"]["vidtorid"] = vidtorid[id] print_dump(collected_info, table, module, identifier, key_map) return
def neighbors(ipaddress, info_type, namespace): """Show IP (IPv4) BGP neighbors""" command = 'show ip bgp neighbor' if ipaddress is not None: if not bgp_util.is_ipv4_address(ipaddress): ctx = click.get_current_context() ctx.fail("{} is not valid ipv4 address\n".format(ipaddress)) try: actual_namespace = bgp_util.get_namespace_for_bgp_neighbor( ipaddress) if namespace is not None and namespace != actual_namespace: click.echo( "[WARNING]: bgp neighbor {} is present in namespace {} not in {}" .format(ipaddress, actual_namespace, namespace)) # save the namespace in which the bgp neighbor is configured namespace = actual_namespace command += ' {}'.format(ipaddress) # info_type is only valid if ipaddress is specified if info_type is not None: command += ' {}'.format(info_type) except ValueError as err: ctx = click.get_current_context() ctx.fail("{}\n".format(err)) ns_list = multi_asic.get_namespace_list(namespace) output = "" for ns in ns_list: output += bgp_util.run_bgp_command(command, ns) click.echo(output.rstrip('\n'))
def neighbors(ipaddress, info_type, namespace): """Show IPv6 BGP neighbors""" if ipaddress is not None: if not bgp_util.is_ipv6_address(ipaddress): ctx = click.get_current_context() ctx.fail("{} is not valid ipv6 address\n".format(ipaddress)) try: actual_namespace = bgp_util.get_namespace_for_bgp_neighbor( ipaddress) if namespace is not None and namespace != actual_namespace: click.echo( "bgp neighbor {} is present in namespace {} not in {}" .format(ipaddress, actual_namespace, namespace)) # save the namespace in which the bgp neighbor is configured namespace = actual_namespace except ValueError as err: ctx = click.get_current_context() ctx.fail("{}\n".format(err)) else: ipaddress = "" info_type = "" if info_type is None else info_type command = 'show bgp ipv6 neighbor {} {}'.format( ipaddress, info_type) ns_list = multi_asic.get_namespace_list(namespace) output = "" for ns in ns_list: output += bgp_util.run_bgp_command(command, ns) click.echo(output.rstrip('\n'))
def get_namespace_for_bgp_neighbor(neighbor_ip): namespace_list = multi_asic.get_namespace_list() for namespace in namespace_list: if is_bgp_neigh_present(neighbor_ip, namespace): return namespace # neighbor IP not present in any namespace raise ValueError(' Bgp neighbor {} not configured'.format(neighbor_ip))
def show_thresholds(self, resource): """ CRM Handler to display thresholds information. """ configdb = self.cfgdb if configdb is None: # Get the namespace list namespaces = multi_asic.get_namespace_list() configdb = ConfigDBConnector(namespace=namespaces[0]) configdb.connect() crm_info = configdb.get_entry('CRM', 'Config') header = ("Resource Name", "Threshold Type", "Low Threshold", "High Threshold") data = [] if crm_info: if resource == 'all': for res in [ "ipv4_route", "ipv6_route", "ipv4_nexthop", "ipv6_nexthop", "ipv4_neighbor", "ipv6_neighbor", "nexthop_group_member", "nexthop_group", "acl_table", "acl_group", "acl_entry", "acl_counter", "fdb_entry", "ipmc_entry", "snat_entry", "dnat_entry", "mpls_inseg", "mpls_nexthop" ]: try: data.append([ res, crm_info[res + "_threshold_type"], crm_info[res + "_low_threshold"], crm_info[res + "_high_threshold"] ]) except KeyError: pass else: try: data.append([ resource, crm_info[resource + "_threshold_type"], crm_info[resource + "_low_threshold"], crm_info[resource + "_high_threshold"] ]) except KeyError: pass else: click.echo('\nError! Could not get CRM configuration.') click.echo() click.echo( tabulate(data, headers=header, tablefmt="simple", missingval="")) click.echo()
def get_acl_rule_counters(module): """ @summary: Parse the output of CLI 'aclshow -a' to get counters value of all ACL rules. @param module: The AnsibleModule object @return: Return ACL rule counters data in dict """ counter_aggrgeate_map = defaultdict(list) counters = [] namespace_list = multi_asic.get_namespace_list() for ns in namespace_list: cmd = 'sudo ip netns exec {} '.format(ns) if ns else '' rc, stdout, stderr = module.run_command(cmd + 'aclshow -a') if rc != 0: module.fail_json( msg= 'Failed to get acl counter data, rc=%s, stdout=%s, stderr=%s' % (rc, stdout, stderr)) output_lines = stdout.splitlines()[ 2:] # Skip the header lines in output for line in output_lines: line_expanded = line.split() if len(line_expanded) == 5: try: packets_count = int(line_expanded[3]) except ValueError: packets_count = 0 try: bytes_count = int(line_expanded[4]) except ValueError: bytes_count = 0 key = (line_expanded[0], line_expanded[1], line_expanded[2]) if key in counter_aggrgeate_map: counter_aggrgeate_map[key][ 0] = packets_count + counter_aggrgeate_map[key][0] counter_aggrgeate_map[key][ 1] = bytes_count + counter_aggrgeate_map[key][1] else: counter_aggrgeate_map[key].append(packets_count) counter_aggrgeate_map[key].append(bytes_count) for k, v in counter_aggrgeate_map.items(): counter = dict(rule_name=k[0], table_name=k[1], priority=k[2], packets_count=v[0], bytes_count=v[1]) counters.append(counter) return counters
def __static_checks(self): if not self.db and not self.file: return EXCEP_DICT["NO_SRC"] if self.db and self.file: return EXCEP_DICT["SRC_VAGUE"] if not self.db: try: with open(self.file) as f: json.load(f) except Exception as e: return EXCEP_DICT["FILE_R_EXEP"] + str(e) if not self.file and self.db not in SonicDBConfig.getDbList(): return EXCEP_DICT["INV_DB"] if not self.table: return EXCEP_DICT["NO_TABLE"] if not isinstance(self.return_fields, list): return EXCEP_DICT["BAD_FORMAT_RE_FIELDS"] if not self.just_keys and self.return_fields: return EXCEP_DICT["JUST_KEYS_COMPAT"] if self.field and not self.value: return EXCEP_DICT["NO_VALUE"] if self.ns != DEFAULT_NAMESPACE and self.ns not in multi_asic.get_namespace_list( ): return EXCEP_DICT["INV_NS"] + " Choose From {}".format( multi_asic.get_namespace_list()) verbose_print("MatchRequest Checks Passed") return ""
def run(self): """ Run ACL capabilities facts collection. """ self.facts['acl_capabilities'] = {} namespace_list = multi_asic.get_namespace_list() swsssdk.SonicDBConfig.load_sonic_global_db_config() conn = swsssdk.SonicV2Connector(namespace=namespace_list[0]) conn.connect(conn.STATE_DB) keys = conn.keys(conn.STATE_DB, 'ACL_STAGE_CAPABILITY_TABLE|*') or [] for key in keys: capab = conn.get_all(conn.STATE_DB, key) self.facts['acl_capabilities'][key.split('|')[-1]] = capab self.module.exit_json(ansible_facts=self.facts)
def run(self): """ Main method of the class """ self.facts['switch_capabilities'] = {} namespace_list = multi_asic.get_namespace_list() swsssdk.SonicDBConfig.load_sonic_global_db_config() conn = swsssdk.SonicV2Connector(namespace=namespace_list[0]) conn.connect(conn.STATE_DB) keys = conn.keys(conn.STATE_DB, 'SWITCH_CAPABILITY|*') for key in keys: capab = conn.get_all(conn.STATE_DB, key) self.facts['switch_capabilities'][key.split('|')[-1]] = capab self.module.exit_json(ansible_facts=self.facts)
def get_po_names(self): ''' Collect configured lag interface names ''' namespace_list = multi_asic.get_namespace_list() for ns in namespace_list: rt, out, err = self.module.run_command( "sonic-cfggen -m /etc/sonic/minigraph.xml {} -v \"PORTCHANNEL.keys() | join(' ')\"" .format('-n ' + ns if ns else '')) if rt != 0: fail_msg = "Command to retrieve portchannel names failed return=%d, out=%s, err=%s" % ( rt, out, err) self.module.fail_json(msg=fail_msg) else: for po in out.split(): if multi_asic.is_port_channel_internal(po): continue self.lag_names[po] = ns return
def show_summary(self): """ CRM Handler to display general information. """ configdb = self.cfgdb if configdb is None: # Get the namespace list namespaces = multi_asic.get_namespace_list() configdb = swsssdk.ConfigDBConnector(namespace=namespaces[0]) configdb.connect() crm_info = configdb.get_entry('CRM', 'Config') if crm_info: click.echo('\nPolling Interval: ' + crm_info['polling_interval'] + ' second(s)\n') else: click.echo('\nError! Could not get CRM configuration.\n')
def parse_png(png, hname): neighbors = {} devices = {} neighbors_namespace = defaultdict(str) console_dev = '' console_port = '' mgmt_dev = '' mgmt_port = '' try: from sonic_py_common import multi_asic namespace_list = multi_asic.get_namespace_list() except ImportError: namespace_list = [''] for child in png: if child.tag == str(QName(ns, "DeviceInterfaceLinks")): for link in child.findall(str(QName(ns, "DeviceLinkBase"))): linktype = link.find(str(QName(ns, "ElementType"))).text if linktype != "DeviceInterfaceLink" and linktype != "UnderlayInterfaceLink": continue enddevice = link.find(str(QName(ns, "EndDevice"))).text endport = link.find(str(QName(ns, "EndPort"))).text startdevice = link.find(str(QName(ns, "StartDevice"))).text startport = link.find(str(QName(ns, "StartPort"))).text if enddevice == hname: if port_alias_to_name_map.has_key(endport): endport = port_alias_to_name_map[endport] if startdevice.lower() in namespace_list: neighbors_namespace[endport] = startdevice.lower() else: neighbors[endport] = { 'name': startdevice, 'port': startport, 'namespace': '' } elif startdevice == hname: if port_alias_to_name_map.has_key(startport): startport = port_alias_to_name_map[startport] if enddevice.lower() in namespace_list: neighbors_namespace[startport] = enddevice.lower() else: neighbors[startport] = { 'name': enddevice, 'port': endport, 'namespace': '' } if child.tag == str(QName(ns, "Devices")): for device in child.findall(str(QName(ns, "Device"))): lo_addr = None # don't shadow type() d_type = None mgmt_addr = None hwsku = None if str(QName(ns3, "type")) in device.attrib: d_type = device.attrib[str(QName(ns3, "type"))] for node in device: if node.tag == str(QName(ns, "Address")): lo_addr = node.find(str(QName( ns2, "IPPrefix"))).text.split('/')[0] elif node.tag == str(QName(ns, "ManagementAddress")): mgmt_addr = node.find(str(QName( ns2, "IPPrefix"))).text.split('/')[0] elif node.tag == str(QName(ns, "Hostname")): name = node.text elif node.tag == str(QName(ns, "HwSku")): hwsku = node.text if name.lower() in namespace_list: continue devices[name] = { 'lo_addr': lo_addr, 'type': d_type, 'mgmt_addr': mgmt_addr, 'hwsku': hwsku } if child.tag == str(QName(ns, "DeviceInterfaceLinks")): for if_link in child.findall(str(QName(ns, 'DeviceLinkBase'))): if str(QName(ns3, "type")) in if_link.attrib: link_type = if_link.attrib[str(QName(ns3, "type"))] if link_type == 'DeviceSerialLink': for node in if_link: if node.tag == str(QName(ns, "EndPort")): console_port = node.text.split()[-1] elif node.tag == str(QName(ns, "EndDevice")): console_dev = node.text elif link_type == 'DeviceMgmtLink': for node in if_link: if node.tag == str(QName(ns, "EndPort")): mgmt_port = node.text.split()[-1] elif node.tag == str(QName(ns, "EndDevice")): mgmt_dev = node.text for k, v in neighbors.iteritems(): v['namespace'] = neighbors_namespace[k] return (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port)
def multi_asic_ns_choices(): if not multi_asic.is_multi_asic(): return [constants.DEFAULT_NAMESPACE] choices = multi_asic.get_namespace_list() return choices
#!/usr/bin/python import json import sys from ansible.module_utils.basic import * try: from sonic_py_common import multi_asic NAMESPACE_LIST = multi_asic.get_namespace_list() except ImportError: NAMESPACE_LIST = [''] DOCUMENTATION = ''' --- module: lag_facts Ansible_version_added: "2.0.0.2" Sonic_version: "2.0" short_description: Retrieve lag(LACP) information from a device description: - Retrieved facts will be inserted to: lag_facts: - 'names': [list all portchannel names] - 'lags': {portchannel: detailed portchannel information } ''' EXAMPLES = ''' # Gather lab facts - name: Gather lag info lag_facts: host=10.255.0.200 - name: display lag information debug: var=lag_facts '''
def main(): module = AnsibleModule(argument_spec=dict( up_ports=dict(type='raw', default={}), namespace=dict(default=None), ), supports_check_mode=False) m_args = module.params up_ports = m_args['up_ports'] namespace_passed = m_args['namespace'] # Create a python script file in the DUT. with open(INTF_IP_GET_INFO_SCRIPT, "w") as f: f.write(INTF_IP_GET_INFO_CMDs) f.close() interfaces = dict() ips = dict( all_ipv4_addresses=[], all_ipv6_addresses=[], ) # Initialize the cmd string which to invoke the python script which we created on the DUT. cmd_prefix = '' cmd = '/usr/bin/python {}'.format(INTF_IP_GET_INFO_SCRIPT) for namespace in multi_asic.get_namespace_list(): if namespace_passed and namespace != namespace_passed: continue # If the user passed a namespace parameter invoke that script with the cmd_prefix if namespace: cmd_prefix = 'sudo ip netns exec {} '.format(namespace) rc, output, err = module.run_command(cmd_prefix + cmd, use_unsafe_shell=True) if rc != 0: module.fail_json( msg="Failed to run {}, rc={}, stdout={}, stderr={}".format( cmd, rc, output, err)) # Get the output from the gather interface info script. if output: ips_interfaces = json.loads(output) interfaces.update(ips_interfaces["interfaces"]) ips.update(ips_interfaces["ips"]) # Remove the file which was created earlier os.remove(INTF_IP_GET_INFO_SCRIPT) results = {} down_ports = [] for name in up_ports: try: if not interfaces[name]['link']: down_ports += [name] except: down_ports += [name] pass results['ansible_interface_facts'] = interfaces results['ansible_interface_ips'] = ips results['ansible_interface_link_down_ports'] = down_ports module.exit_json(ansible_facts=results)