def populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for lag_interfaces :param connection: the device connection :param data: previously collected configuration :rtype: dictionary :returns: facts """ if not data: data = connection.get('show running-config | section ^interface') # split the config into instances of the resource resource_delim = 'interface' find_pattern = r'(?:^|\n)%s.*?(?=(?:^|\n)%s|$)' % (resource_delim, resource_delim) resources = [ p.strip() for p in re.findall(find_pattern, data, re.DOTALL) ] objs = {} for resource in resources: if resource: obj = self.render_config(self.generated_spec, resource) if obj: group_name = obj['name'] if group_name in objs and "members" in obj: config = objs[group_name] if "members" not in config: config["members"] = [] objs[group_name]['members'].extend(obj['members']) else: objs[group_name] = obj objs = list(objs.values()) facts = {} if objs: params = utils.validate_config(self.argument_spec, {'config': objs}) facts['lag_interfaces'] = [ utils.remove_empties(cfg) for cfg in params['config'] ] ansible_facts['ansible_network_resources'].update(facts) return ansible_facts
def render_config(self, spec, conf): """ Render config as dictionary structure and delete keys from spec for null values :param spec: The facts tree, generated from the argspec :param conf: The configuration :rtype: dictionary :returns: The generated config """ config = deepcopy(spec) config['holdtime'] = utils.parse_conf_arg(conf, 'holdtime') config['reinit'] = utils.parse_conf_arg(conf, 'reinit') config['timer'] = utils.parse_conf_arg(conf, 'timer') for match in re.findall(r'^(no)? lldp tlv-select (\S+)', conf, re.MULTILINE): tlv_option = match[1].replace("-", "_") config['tlv_select'][tlv_option] = bool(match[0] != "no") return utils.remove_empties(config)
def render_config(self, spec, conf): """ Render config as dictionary structure and delete keys from spec for null values :param spec: The facts tree, generated from the argspec :param conf: The configuration :rtype: dictionary :returns: The generated config """ config = deepcopy(spec) config['severity'] = conf.get('severity') syslog_value = conf.get('syslog') if syslog_value != None: syslog = [] for each in syslog_value['host']: syslog.append(each['address']) config['syslog'] = syslog return utils.remove_empties(config)
def render_config(self, spec, conf): """ Render config as dictionary structure and delete keys from spec for null values :param spec: The facts tree, generated from the argspec :param conf: The configuration :rtype: dictionary :returns: The generated config """ config = deepcopy(spec) match = re.search(r'^(\S+)', conf) intf = match.group(1) if get_interface_type(intf) == 'unknown': return {} config['name'] = intf config['bfd'] = utils.parse_conf_cmd_arg(conf, 'hsrp bfd', 'enable', 'disable') return utils.remove_empties(config)
def populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for lacp :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ if not data: data = connection.get("show running-config | include lacp") resources = data.strip() objs = self.render_config(self.generated_spec, resources) ansible_facts["ansible_network_resources"].pop("lacp", None) facts = {} if objs: params = utils.validate_config( self.argument_spec, {"config": objs} ) facts["lacp"] = utils.remove_empties(params["config"]) ansible_facts["ansible_network_resources"].update(facts) return ansible_facts
def _state_merged(want, have): """ The command generator when state is merged :rtype: A list :returns: the commands necessary to merge the provided into the current configuration """ commands = [] if not have: have = {"name": want["name"]} for key, value in iteritems( flatten_dict(remove_empties(dict_diff(have, want))) ): commands.append(Lacp_interfaces._compute_commands(key, value)) if commands: pad_commands(commands, want["name"]) return commands
def populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for interfaces :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ objs = [] if not data: data = connection.get("show running-config | section ^interface") # operate on a collection of resource x config = data.split("interface ") for conf in config: if conf: obj = self.render_config(self.generated_spec, conf) if obj: if not obj.get("members"): obj.update({"members": []}) objs.append(obj) # for appending members configured with same channel-group for each in range(len(objs)): if each < (len(objs) - 1): if objs[each]["name"] == objs[each + 1]["name"]: objs[each]["members"].append(objs[each + 1]["members"][0]) del objs[each + 1] facts = {} if objs: facts["lag_interfaces"] = [] params = utils.validate_config(self.argument_spec, {"config": objs}) for cfg in params["config"]: facts["lag_interfaces"].append(utils.remove_empties(cfg)) ansible_facts["ansible_network_resources"].update(facts) return ansible_facts
def populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for interfaces :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ objs = [] if not data: data = connection.get('display eth-trunk') # operate on a collection of resource x config = re.split(r'\n\s*\n', data) for conf in config: if conf: obj = self.render_config(self.generated_spec, conf) if obj: if not obj.get('members'): obj.update({'members': []}) objs.append(obj) # for appending members configured with same eth-trunk for each in range(len(objs)): if each < (len(objs) - 1): if objs[each]['name'] == objs[each + 1]['name']: objs[each]['members'].append(objs[each + 1]['members'][0]) del objs[each + 1] facts = {} if objs: facts['lag_interfaces'] = [] params = utils.validate_config(self.argument_spec, {'config': objs}) for cfg in params['config']: facts['lag_interfaces'].append(utils.remove_empties(cfg)) ansible_facts['ansible_network_resources'].update(facts) return ansible_facts
def render_config(self, spec, conf): """ Render config as dictionary structure and delete keys from spec for null values :param spec: The facts tree, generated from the argspec :param conf: The configuration :rtype: dictionary :returns: The generated config """ config = deepcopy(spec) status = '' holdtime_multiplier = '' timer = '' reinit = '' match = re.search(r'LLDP Status\s+:\s*(\S+)', conf) if match: status = match.group(1) match = re.search(r'LLDP Message Tx Interval\s+:\s*(\d+)', conf) if match: timer = int(match.group(1)) match = re.search(r'LLDP Message Tx Hold Multiplier\s+:\s*(\d+)', conf) if match: holdtime_multiplier = int(match.group(1)) match = re.search(r'LLDP Refresh Delay\s+:\s*(\d+)', conf) if match: reinit = match.group(1) if holdtime_multiplier: config['holdtime_multiplier'] = int(holdtime_multiplier) if status: config['enabled'] = True if timer: config['timer'] = int(timer) if reinit: config['reinit'] = int(reinit) return utils.remove_empties(config)
def _state_deleted(self, want, have): """ The command generator when state is deleted :rtype: A list :returns: the commands necessary to remove the current configuration of the provided objects """ commands = [] want_copy = deepcopy(remove_empties(want)) have_copy = deepcopy(have) want_vifs = want_copy.pop('vifs', []) have_vifs = have_copy.pop('vifs', []) for update in self._get_updates(have_copy, want_copy): for key, value in iteritems(update): commands.append( self._compute_commands(key=key, value=value, interface=want_copy['name'], remove=True)) if have_vifs: for have_vif in have_vifs: want_vif = search_obj_in_list(have_vif['vlan_id'], want_vifs, key='vlan_id') if not want_vif: want_vif = {'vlan_id': have_vif['vlan_id']} for update in self._get_updates(have_vif, want_vif): for key, value in iteritems(update): commands.append( self._compute_commands(key=key, interface=want_copy['name'], value=value, vif=want_vif['vlan_id'], remove=True)) return commands
def render_config(self, spec, conf): """ Render config as dictionary structure and delete keys from spec for null values :param spec: The facts tree, generated from the argspec :param conf: The configuration :rtype: dictionary :returns: The generated config """ config = deepcopy(spec) name = conf[0].strip() config['name'] = normalize_interface(name) config['access_groups'] = [] v4 = {'afi': 'ipv4', 'acls': []} v6 = {'afi': 'ipv6', 'acls': []} for c in conf[1:]: if c: acl4 = re.search(r'ip( port)? access-group (\w*) (\w*)', c) acl6 = re.search(r'ipv6( port)? traffic-filter (\w*) (\w*)', c) if acl4: acl = { 'name': acl4.group(2).strip(), 'direction': acl4.group(3).strip() } if acl4.group(1): acl.update({'port': True}) v4['acls'].append(acl) elif acl6: acl = {'name': acl6.group(2), 'direction': acl6.group(3)} if acl6.group(1): acl.update({'port': True}) v6['acls'].append(acl) if len(v4['acls']) > 0: config['access_groups'].append(v4) if len(v6['acls']) > 0: config['access_groups'].append(v6) return utils.remove_empties(config)
def populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for interfaces :param connection: the device connection :param data: previously collected configuration as lxml ElementTree root instance or valid xml sting :rtype: dictionary :returns: facts """ if not HAS_LXML: self._module.fail_json(msg='lxml is not installed.') if not data: config_filter = """ <configuration> <interfaces/> </configuration> """ data = get_resource_config(connection, config_filter=config_filter) if isinstance(data, string_types): data = etree.fromstring( to_bytes(data, errors='surrogate_then_replace')) self._resources = data.xpath('configuration/interfaces/interface') objs = [] for resource in self._resources: if resource is not None: obj = self.render_config(self.generated_spec, resource) if obj: objs.append(obj) facts = {} if objs: facts['lag_interfaces'] = [] params = utils.validate_config(self.argument_spec, {'config': objs}) for cfg in params['config']: facts['lag_interfaces'].append(utils.remove_empties(cfg)) ansible_facts['ansible_network_resources'].update(facts) return ansible_facts
def render_config(self, spec, conf): """ Render config as dictionary structure and delete keys from spec for null values :param spec: The facts tree, generated from the argspec :param conf: The configuration :rtype: dictionary :returns: The generated config """ config = deepcopy(spec) match = re.search(r'^(\S+)', conf) intf = match.group(1) if get_interface_type(intf) == 'unknown': return {} if intf.upper()[:2] in ('HU', 'FO', 'TW', 'TE', 'GI', 'FA', 'ET', 'PO'): # populate the facts from the configuration config['name'] = normalize_interface(intf) has_access = utils.parse_conf_arg(conf, 'switchport access vlan') if has_access: config["access"] = {"vlan": int(has_access)} trunk = dict() trunk["encapsulation"] = utils.parse_conf_arg( conf, 'encapsulation') native_vlan = utils.parse_conf_arg(conf, 'native vlan') if native_vlan: trunk["native_vlan"] = int(native_vlan) allowed_vlan = utils.parse_conf_arg(conf, 'allowed vlan') if allowed_vlan: trunk["allowed_vlans"] = allowed_vlan.split(',') pruning_vlan = utils.parse_conf_arg(conf, 'pruning vlan') if pruning_vlan: trunk['pruning_vlans'] = pruning_vlan.split(',') config['trunk'] = trunk return utils.remove_empties(config)
def populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for vlans :param connection: the device connection :param data: previously collected conf :rtype: dictionary :returns: facts """ objs = [] # **TBD** # N7K EOL/legacy image 6.2 does not support show vlan | json output. # If support is still required for this image then: # - Wrapp the json calls below in a try/except # - When excepted, use a helper method to parse the run_cfg_output, # using the run_cfg_output data to generate compatible json data that # can be read by normalize_table_data. if not data: # Use structured for most of the vlan parameter states. # This data is consistent across the supported nxos platforms. structured = self.get_device_data(connection, 'show vlan | json') # Raw cli config is needed for mapped_vni, which is not included in structured. run_cfg_output = self.get_device_data(connection, 'show running-config | section ^vlan') # Create a single dictionary from all data sources data = self.normalize_table_data(structured, run_cfg_output) for vlan in data: obj = self.render_config(self.generated_spec, vlan) if obj: objs.append(obj) ansible_facts['ansible_network_resources'].pop('vlans', None) facts = {} if objs: facts['vlans'] = [] params = utils.validate_config(self.argument_spec, {'config': objs}) for cfg in params['config']: facts['vlans'].append(utils.remove_empties(cfg)) ansible_facts['ansible_network_resources'].update(facts) return ansible_facts
def populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for acl_interfaces :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ if not data: data = self.get_device_data(connection) data = data.split('interface') resources = [] for i in range(len(data)): intf = data[i].split('\n') for l in range(1, len(intf)): if not re.search( 'ip(v6)?( port)? (access-group|traffic-filter)', intf[l]): intf[l] = '' intf = list(filter(None, intf)) resources.append(intf) objs = [] for resource in resources: if resource: obj = self.render_config(self.generated_spec, resource) if obj: objs.append(obj) ansible_facts['ansible_network_resources'].pop('acl_interfaces', None) facts = {} if objs: params = utils.validate_config(self.argument_spec, {'config': objs}) params = utils.remove_empties(params) facts['acl_interfaces'] = params['config'] ansible_facts['ansible_network_resources'].update(facts) return ansible_facts
def set_config(self, existing_lldp_interfaces_facts): """ Collect the configuration from the args passed to the module, collect the current configuration (as a dict from facts) :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ config = self._module.params['config'] want = [] if config: for w in config: if get_interface_type(w['name']) not in ('management', 'ethernet'): self._module.fail_json( msg= 'This module works with either management or ethernet') w.update({'name': normalize_interface(w['name'])}) want.append(remove_empties(w)) have = existing_lldp_interfaces_facts resp = self.set_state(want, have) return to_list(resp)
def set_config(self, existing_l3_interfaces_facts): """ Collect the configuration from the args passed to the module, collect the current configuration (as a dict from facts) :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ config = self._module.params.get('config') want = [] if config: for w in config: w.update({'name': normalize_interface(w['name'])}) if get_interface_type(w['name']) == 'management': self._module.fail_json( msg= "The 'management' interface is not allowed to be managed by this module" ) want.append(remove_empties(w)) have = existing_l3_interfaces_facts resp = self.set_state(want, have) return to_list(resp)
def populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for firewall_global :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ if not data: # typically data is populated from the current device configuration # data = connection.get('show running-config | section ^interface') # using mock data instead data = self.get_device_data(connection) objs = {} firewalls = findall(r'^set firewall .*$', data, M) if firewalls: objs = self.render_config(firewalls) facts = {} params = utils.validate_config(self.argument_spec, {'config': objs}) facts['firewall_global'] = utils.remove_empties(params['config']) ansible_facts['ansible_network_resources'].update(facts) return ansible_facts
def set_config(self, existing_interfaces_facts, default_intf_list): """ Collect the configuration from the args passed to the module, collect the current configuration (as a dict from facts) :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ config = self._module.params.get('config') want = [] if config: for w in config: w.update({'name': normalize_interface(w['name'])}) want.append(remove_empties(w)) have = deepcopy(existing_interfaces_facts) for i in want: # 'have' does not include objects from the default_interfaces list. # Add any 'want' names from default_interfaces to the 'have' list. if i['name'] in default_intf_list: have.append({'name': i['name']}) resp = self.set_state(want, have) return to_list(resp)
def render_config(self, spec, conf): """ Render config as dictionary structure and delete keys from spec for null values :param spec: The facts tree, generated from the argspec :param conf: The configuration :rtype: dictionary :returns: The generated config """ config = deepcopy(spec) vlans = [] vlan_list = vlan_to_list(utils.parse_conf_arg(conf, 'vlan')) for vlan in vlan_list: config['vlan_id'] = vlan config['name'] = utils.parse_conf_arg(conf, 'name') config['state'] = utils.parse_conf_arg(conf, 'state') vlans.append(utils.remove_empties(config)) return vlans
def __init__(self, *_args, **kwargs): self._empty_fact_val = kwargs.get('empty_fact_val', []) self._facts_module = kwargs.get('facts_module', None) self._gather_subset = kwargs.get('gather_subset', ['!all', '!min']) self._module = kwargs.get('module', None) self._resource = kwargs.get('resource', None) self._tmplt = kwargs.get('tmplt', None) self._connection = None self.state = self._module.params['state'] self.before = self.gather_current() self.changed = False self.commands = [] self.warnings = [] self.have = deepcopy(self.before) self.want = remove_empties( self._module.params).get('config', self._empty_fact_val) self._get_connection() super(RmModule, self).__init__(tmplt=self._tmplt)
def populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for bfd_interfaces :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ objs = [] if not data: data = connection.get( "show running-config | section '^interface|^feature bfd'" ) # Some of the bfd attributes if "feature bfd" in data.split("\n"): resources = data.split("interface ") resources.pop(0) else: resources = [] for resource in resources: if resource: obj = self.render_config(self.generated_spec, resource) if obj and len(obj.keys()) > 1: objs.append(obj) ansible_facts["ansible_network_resources"].pop("bfd_interfaces", None) facts = {} if objs: facts["bfd_interfaces"] = [] params = utils.validate_config( self.argument_spec, {"config": objs} ) for cfg in params["config"]: facts["bfd_interfaces"].append(utils.remove_empties(cfg)) ansible_facts["ansible_network_resources"].update(facts) return ansible_facts
def render_config(self, spec, conf): """ Render config as dictionary structure and delete keys from spec for null values :param spec: The facts tree, generated from the argspec :param conf: The configuration :rtype: dictionary :returns: The generated config """ config = deepcopy(spec) match = re.search(r"^(\S+)", conf) intf = match.group(1) if get_interface_type(intf) == "unknown": return {} config["name"] = intf config["port_priority"] = utils.parse_conf_arg(conf, "lacp port-priority") config["rate"] = utils.parse_conf_arg(conf, "lacp rate") config["mode"] = utils.parse_conf_arg(conf, "mode") suspend_individual = re.search(r"no lacp suspend-individual", conf) if suspend_individual: config["suspend_individual"] = False max_links = utils.parse_conf_arg(conf, "lacp max-bundle") if max_links: config["links"]["max"] = max_links min_links = utils.parse_conf_arg(conf, "lacp min-links") if min_links: config["links"]["min"] = min_links graceful = re.search(r"no lacp graceful-convergence", conf) if graceful: config["convergence"]["gracefule"] = False vpc = re.search(r"lacp vpc-convergence", conf) if vpc: config["convergence"]["vpc"] = True return utils.remove_empties(config)
def render_config(self, conf): """ Render config as dictionary structure and delete keys from spec for null values :param spec: The facts tree, generated from the argspec :param conf: The configuration :rtype: dictionary :returns: The generated config """ config = {} location = {} civic_conf = "\n".join(filter(lambda x: ("civic-based" in x), conf)) elin_conf = "\n".join(filter(lambda x: ("elin" in x), conf)) coordinate_conf = "\n".join( filter(lambda x: ("coordinate-based" in x), conf) ) disable = "\n".join(filter(lambda x: ("disable" in x), conf)) coordinate_based_conf = self.parse_attribs( ["altitude", "datum", "longitude", "latitude"], coordinate_conf ) elin_based_conf = self.parse_lldp_elin_based(elin_conf) civic_based_conf = self.parse_lldp_civic_based(civic_conf) if disable: config["enable"] = False if coordinate_conf: location["coordinate_based"] = coordinate_based_conf config["location"] = location elif civic_based_conf: location["civic_based"] = civic_based_conf config["location"] = location elif elin_conf: location["elin"] = elin_based_conf config["location"] = location return utils.remove_empties(config)
def render_config(self, spec, conf): """ Render config as dictionary structure and delete keys from spec for null values :param spec: The facts tree, generated from the argspec :param conf: The configuration :rtype: dictionary :returns: The generated config """ config = deepcopy(spec) match = re.search(r'^(\S+)', conf) intf = match.group(1) if get_interface_type(intf) == 'unknown': return {} config['name'] = intf config['description'] = utils.parse_conf_arg(conf, 'description') config['speed'] = utils.parse_conf_arg(conf, 'speed') config['mtu'] = utils.parse_conf_arg(conf, 'mtu') config['duplex'] = utils.parse_conf_arg(conf, 'duplex') config['mode'] = utils.parse_conf_cmd_arg(conf, 'switchport', 'layer2', 'layer3') config['enabled'] = utils.parse_conf_cmd_arg(conf, 'shutdown', False, True) # Capture the default 'enabled' state, which may be interface-specific config['enabled_def'] = default_intf_enabled(name=intf, sysdefs=self.sysdefs, mode=config['mode']) config['fabric_forwarding_anycast_gateway'] = utils.parse_conf_cmd_arg( conf, 'fabric forwarding mode anycast-gateway', True) config['ip_forward'] = utils.parse_conf_cmd_arg( conf, 'ip forward', True) interfaces_cfg = utils.remove_empties(config) return interfaces_cfg
def populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for l3_interfaces :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ if not data: data = connection.get_config() # operate on a collection of resource x objs = [] interface_names = re.findall( r"set interfaces (?:ethernet|bonding|vti|vxlan) (?:\'*)(\S+)(?:\'*)", data, re.M, ) if interface_names: for interface in set(interface_names): intf_regex = r" %s .+$" % interface cfg = re.findall(intf_regex, data, re.M) obj = self.render_config(cfg) obj["name"] = interface.strip("'") if obj: objs.append(obj) ansible_facts["ansible_network_resources"].pop("l3_interfaces", None) facts = {} if objs: facts["l3_interfaces"] = [] params = utils.validate_config(self.argument_spec, {"config": objs}) for cfg in params["config"]: facts["l3_interfaces"].append(utils.remove_empties(cfg)) ansible_facts["ansible_network_resources"].update(facts) return ansible_facts
def render_config(self, spec, conf): """ Render config as dictionary structure and delete keys from spec for null values :param spec: The facts tree, generated from the argspec :param conf: The configuration :rtype: dictionary :returns: The generated config """ config = deepcopy(spec) # populate the facts from the configuration config['name'] = re.match(r'(\S+)', conf).group(1).replace('"', '') has_mode = re.search(r"switchport mode (\S+)", conf) if has_mode: config["mode"] = has_mode.group(1) has_access = re.search(r"switchport access vlan (\d+)", conf) if has_access: config["access"] = {"vlan": int(has_access.group(1))} has_trunk = re.findall(r"switchport trunk (.+)", conf) if has_trunk: trunk = {} for match in has_trunk: has_native = re.match(r"native vlan (\d+)", match) if has_native: trunk["native_vlan"] = int(has_native.group(1)) continue has_allowed = re.match(r"allowed vlan (\S+)", match) if has_allowed: # TODO: listify? trunk["trunk_allowed_vlans"] = has_allowed.group(1) continue config['trunk'] = trunk return utils.remove_empties(config)
def _add_global_attr(self, w, h, opr=True): """ This function forms the set/delete commands based on the 'opr' type for firewall_global attributes. :param w: the desired config. :param h: the target config. :param opr: True/False. :return: generated commands list. """ commands = [] w_fg = deepcopy(remove_empties(w)) l_set = ('config_trap', 'validation', 'log_martians', 'syn_cookies', 'twa_hazards_protection') if w_fg: for key, val in iteritems(w_fg): if opr and key in l_set and not (h and self._is_w_same( w_fg, h, key)): commands.append( self._form_attr_cmd(attr=key, val=self._bool_to_str(val), opr=opr)) elif not opr: if key and self._is_del(l_set, h): commands.append( self._form_attr_cmd(attr=key, key=self._bool_to_str(val), opr=opr)) continue elif key in l_set and not (h and self._in_target( h, key)) and not self._is_del(l_set, h): commands.append( self._form_attr_cmd(attr=key, val=self._bool_to_str(val), opr=opr)) else: commands.extend(self._render_attr_config( w_fg, h, key, opr)) return commands
def render_config(self, spec, conf): """ Render config as dictionary structure and delete keys from spec for null values :param spec: The facts tree, generated from the argspec :param conf: The configuration :rtype: dictionary :returns: The generated config """ config = deepcopy(spec) match = re.search(r'^(\S+)', conf) intf = match.group(1) if get_interface_type(intf) == 'unknown': return {} config['name'] = intf config['port_priority'] = utils.parse_conf_arg(conf, 'lacp port-priority') config['rate'] = utils.parse_conf_arg(conf, 'lacp rate') config['mode'] = utils.parse_conf_arg(conf, 'mode') suspend_individual = re.search(r'no lacp suspend-individual', conf) if suspend_individual: config['suspend_individual'] = False max_links = utils.parse_conf_arg(conf, 'lacp max-bundle') if max_links: config['links']['max'] = max_links min_links = utils.parse_conf_arg(conf, 'lacp min-links') if min_links: config['links']['min'] = min_links graceful = re.search(r'no lacp graceful-convergence', conf) if graceful: config['convergence']['gracefule'] = False vpc = re.search(r'lacp vpc-convergence', conf) if vpc: config['convergence']['vpc'] = True return utils.remove_empties(config)
def render_config(self, spec, con): """ Render config as dictionary structure and delete keys from spec for null values :param spec: The facts tree, generated from the argspec :param conf: The configuration :rtype: dictionary :returns: The generated config """ # config=deepcopy(spec) config = [] global_afi_list = [] global_af = [] global_dest_list = [] if con: for conf in con: if conf.startswith('vrf context'): svrf = re.match('vrf context (\S+)\n', conf).group(1) afi_list = [] af = [] dest_list = [] config_dict = {'vrf': svrf, 'address_families': []} conf = conf.split('\n') # considering from the second line as first line is 'vrf context..' conf = conf[1:] for c in conf: if 'ip route' in c or 'ipv6 route' in c: self.get_command(c, afi_list, dest_list, af) config_dict['address_families'] = af config.append(config_dict) else: if 'ip route' in conf or 'ipv6 route' in conf: self.get_command(conf, global_afi_list, global_dest_list, global_af) config.append(utils.remove_empties({'address_families': global_af})) return config