def populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for lldp_global :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ objs = dict() if not data: data = connection.get('show running-config | section ^lldp') # operate on a collection of resource x config = data.split('\n') for conf in config: if conf: obj = self.render_config(self.generated_spec, conf) if obj: objs.update(obj) facts = {} if objs: params = utils.validate_config(self.argument_spec, {'config': utils.remove_empties(objs)}) facts['lldp_global'] = utils.remove_empties(params['config']) ansible_facts['ansible_network_resources'].update(facts) return ansible_facts
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 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: objs.append(obj) facts = {} if objs: params = utils.validate_config(self.argument_spec, {'config': objs}) facts['l3_interfaces'] = [utils.remove_empties(cfg) for cfg in params['config']] ansible_facts['ansible_network_resources'].update(facts) return ansible_facts
def populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for lldp_global :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 | section lldp') obj = {} if data: obj.update(self.render_config(self.generated_spec, data)) ansible_facts['ansible_network_resources'].pop('lldp_global', None) facts = {} if obj: params = utils.validate_config(self.argument_spec, {'config': obj}) facts['lldp_global'] = utils.remove_empties(params['config']) else: facts['lldp_global'] = {} ansible_facts['ansible_network_resources'].update(facts) return ansible_facts
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 connection: pass if not data: data = connection.get('show lacp sys-id') obj = {} if data: lacp_obj = self.render_config(self.generated_spec, data) if lacp_obj: obj = lacp_obj ansible_facts['ansible_network_resources'].pop('lacp', None) facts = {} params = utils.validate_config(self.argument_spec, {'config': obj}) facts['lacp'] = utils.remove_empties(params['config']) ansible_facts['ansible_network_resources'].update(facts) return ansible_facts
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 configuration :rtype: dictionary :returns: facts """ if not data: data = self.get_device_data(connection) # split the config into instances of the resource resource_delim = 'lacp' 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: objs.update(obj) ansible_facts['ansible_network_resources'].pop('lacp', None) facts = {'lacp': {}} 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 populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for l2_interfaces :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected configuration :rtype: dictionary :returns: facts """ if not data: data = self.get_device_data(connection) # operate on a collection of resource x config = data.split('interface ') objs = [] for conf in config: if conf: obj = self.render_config(self.generated_spec, conf) if obj: objs.append(obj) facts = {} if objs: params = utils.validate_config(self.argument_spec, {'config': objs}) facts['l2_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) # populate the facts from the configuration config['name'] = re.match(r'(\S+)', conf).group(1).replace('"', '') 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 _set_config(self, want, have, module): # Set the interface config based on the want and have config commands = [] # To remove keys with None values from want dict want = utils.remove_empties(want) # Get the diff b/w want and have want_dict = dict_to_set(want) have_dict = dict_to_set(have) diff = want_dict - have_dict # To get the channel-id from lag port-channel name lag_config = dict(diff).get('members') channel_name = re.search(r'(\d+)', want.get('name')) if channel_name: channel_id = channel_name.group() else: module.fail_json(msg="Lag Interface Name is not correct!") if lag_config: for each in lag_config: each = dict(each) each_interface = 'interface {0}'.format(each.get('member')) if have.get('name') == want['members'][0]['member'] or have.get('name').lower().startswith('po'): if each.get('mode'): cmd = 'channel-group {0} mode {1}'.format(channel_id, each.get('mode')) self.add_command_to_config_list(each_interface, cmd, commands) elif each.get('link'): cmd = 'channel-group {0} link {1}'.format(channel_id, each.get('link')) self.add_command_to_config_list(each_interface, cmd, commands) 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 {} # populate the facts from the configuration config['name'] = normalize_interface(intf) config['description'] = utils.parse_conf_arg(conf, 'description') config['speed'] = utils.parse_conf_arg(conf, 'speed') if utils.parse_conf_arg(conf, 'mtu'): config['mtu'] = int(utils.parse_conf_arg(conf, 'mtu')) config['duplex'] = utils.parse_conf_arg(conf, 'duplex') enabled = utils.parse_conf_cmd_arg(conf, 'shutdown', False) config['enabled'] = enabled if enabled is not None else True 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 = '' if match: intf = match.group(1) if get_interface_type(intf) == 'unknown': return {} if intf.lower().startswith('gi'): config['name'] = normalize_interface(intf) receive = utils.parse_conf_arg(conf, 'Rx:') transmit = utils.parse_conf_arg(conf, 'Tx:') if receive == 'enabled': config['receive'] = True elif receive == 'disabled': config['receive'] = False if transmit == 'enabled': config['transmit'] = True elif transmit == 'disabled': config['transmit'] = False 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'] = normalize_interface(intf) port_priority = utils.parse_conf_arg(conf, 'lacp port-priority') max_bundle = utils.parse_conf_arg(conf, 'lacp max-bundle') if port_priority: config['port_priority'] = int(port_priority) if 'lacp fast-switchover' in conf: config['fast_switchover'] = True if max_bundle: config['max_bundle'] = int(max_bundle) 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['name'] = utils.parse_conf_arg(conf, 'interface') matches = re.findall(r'.*ip address (.+)$', conf, re.MULTILINE) if matches: config["ipv4"] = [] for match in matches: address, dummy, remainder = match.partition(" ") ipv4 = {"address": address} if remainder == "secondary": ipv4["secondary"] = True config['ipv4'].append(ipv4) matches = re.findall(r'.*ipv6 address (.+)$', conf, re.MULTILINE) if matches: config["ipv6"] = [] for match in matches: address, dummy, remainder = match.partition(" ") ipv6 = {"address": address} config['ipv6'].append(ipv6) 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 {} # populate the facts from the configuration config['name'] = normalize_interface(intf) ipv4 = [] ipv4_all = re.findall(r"ip address (\S+.*)", conf) for each in ipv4_all: each_ipv4 = dict() if 'secondary' not in each and 'dhcp' not in each: each_ipv4['address'] = each elif 'secondary' in each: each_ipv4['address'] = each.split(' secondary')[0] each_ipv4['secondary'] = True elif 'dhcp' in each: each_ipv4['address'] = 'dhcp' if 'client-id' in each: each_ipv4['dhcp_client'] = int(each.split(' hostname ')[0].split('/')[-1]) if 'hostname' in each: each_ipv4["dhcp_hostname"] = each.split(' hostname ')[-1] if 'client-id' in each and each_ipv4['dhcp_client'] is None: each_ipv4['dhcp_client'] = int(each.split('/')[-1]) if 'hostname' in each and not each_ipv4["dhcp_hostname"]: each_ipv4["dhcp_hostname"] = each.split(' hostname ')[-1] ipv4.append(each_ipv4) config['ipv4'] = ipv4 # Get the configured IPV6 details ipv6 = [] ipv6_all = re.findall(r"ipv6 address (\S+)", conf) for each in ipv6_all: each_ipv6 = dict() if 'autoconfig' in each: each_ipv6['autoconfig'] = True if 'dhcp' in each: each_ipv6['dhcp'] = True each_ipv6['address'] = each.lower() ipv6.append(each_ipv6) config['ipv6'] = ipv6 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['system']['priority'] = int(conf.split(',')[0]) 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) interface_name = utils.parse_conf_arg(conf, 'interface') if interface_name.startswith("Port-Channel"): config["name"] = interface_name return utils.remove_empties(config) interface = {'member': interface_name} match = re.match(r'.*channel-group (\d+) mode (\S+)', conf, re.MULTILINE | re.DOTALL) if match: config['name'], interface['mode'] = match.groups() config["name"] = "Port-Channel" + config["name"] config['members'] = [interface] 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["name"] = conf["name"] config["enabled"] = bool(conf["enabled"]) 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['name'] = utils.parse_conf_arg(conf, 'interface') config['port_priority'] = utils.parse_conf_arg(conf, 'port-priority') config['rate'] = utils.parse_conf_arg(conf, 'rate') 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['name'] = utils.parse_conf_arg(conf, 'interface') matches = re.findall(r'(no )?lldp (\S+)', conf) for match in matches: config[match[1]] = not bool(match[0]) 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["name"] = conf["name"] config["state"] = "suspend" if conf["status"] == "SUSPENDED" else conf[ "status"].lower() config["vlan_id"] = conf["vlan-id"] return utils.remove_empties(config)
def render_config(self, spec, conf, vlan_info): """ 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) if vlan_info == 'Name' and 'Name' not in conf: conf = list(filter(None, conf.split(' '))) config['vlan_id'] = int(conf[0]) config['name'] = conf[1] if len(conf[2].split('/')) > 1: if conf[2].split('/')[0] == 'sus': config['state'] = 'suspend' elif conf[2].split('/')[0] == 'act': config['state'] = 'active' config['shutdown'] = 'enabled' else: if conf[2] == 'suspended': config['state'] = 'suspend' elif conf[2] == 'active': config['state'] = 'active' config['shutdown'] = 'disabled' elif vlan_info == 'Type' and 'Type' not in conf: conf = list(filter(None, conf.split(' '))) config['mtu'] = int(conf[3]) elif vlan_info == 'Remote': if len(conf.split(',')) > 1 or conf.isdigit(): remote_span_vlan = [] if len(conf.split(',')) > 1: remote_span_vlan = conf.split(',') else: remote_span_vlan.append(conf) remote_span = [] for each in remote_span_vlan: remote_span.append(int(each)) config['remote_span'] = remote_span 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['interval'] = conf["openconfig-lldp:config"]["hello-timer"] for item in self.TLV_SELECT_OPTIONS: config["tlv_select"][item.lower()] = ( False if (item in conf["openconfig-lldp:config"] ["suppress-tlv-advertisement"]) else True) 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['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) if conf["config"]["type"] == "ethernetCsmacd": conf_dict = conf["openconfig-if-ethernet:ethernet"]["openconfig-vlan:switched-vlan"]["config"] config["name"] = conf["name"] if conf_dict["interface-mode"] == "ACCESS": config["access"]["vlan"] = conf_dict.get("access-vlan") else: if 'native-vlan' in conf_dict: config["trunk"]["native_vlan"] = conf_dict.get("native-vlan") config["trunk"]["trunk_allowed_vlans"] = conf_dict.get("trunk-vlans") 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 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 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 lag_interfaces :param connection: the device connection :param ansible_facts: Facts dictionary :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 = {'lag_interfaces': []} 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) # populate the facts from the configuration config['name'] = re.match(r'(\S+)', conf).group(1) description = utils.parse_conf_arg(conf, 'description') if description is not None: config['description'] = description.replace('"', '') shutdown = utils.parse_conf_cmd_arg(conf, 'shutdown', False) config['enabled'] = shutdown if shutdown is False else True config['mtu'] = utils.parse_conf_arg(conf, 'mtu') speed_pair = utils.parse_conf_arg(conf, 'speed') if speed_pair: state = speed_pair.split() if state[0] == 'forced': state = state[1] else: state = state[0] if state == 'auto': config['duplex'] = state else: # remaining options are all e.g., 10half or 40gfull config['speed'] = state[:-4] config['duplex'] = state[-4:] 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 {} member_config = {} channel_group = utils.parse_conf_arg(conf, 'channel-group') if intf.startswith('Gi'): config['name'] = intf config['members'] = [] if channel_group: channel_group = channel_group.split(' ') id = channel_group[0] config['name'] = 'Port-channel{0}'.format(str(id)) if 'mode' in channel_group: mode = channel_group[2] member_config.update({'mode': mode}) if 'link' in channel_group: link = channel_group[2] member_config.update({'link': link}) if member_config.get('mode') or member_config.get('link'): member_config['member'] = normalize_interface(intf) config['members'].append(member_config) 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) holdtime = utils.parse_conf_arg(conf, 'lldp holdtime') timer = utils.parse_conf_arg(conf, 'lldp timer') reinit = utils.parse_conf_arg(conf, 'lldp reinit') if holdtime: config['holdtime'] = int(holdtime) if 'lldp run' in conf: config['enabled'] = True if timer: config['timer'] = int(timer) if reinit: config['reinit'] = int(reinit) 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 ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ if connection: pass objs = [] mtu_objs = [] remote_objs = [] final_objs = [] if not data: data = connection.get('show vlan') # operate on a collection of resource x config = data.split('\n') # Get individual vlan configs separately vlan_info = '' for conf in config: if 'Name' in conf: vlan_info = 'Name' elif 'Type' in conf: vlan_info = 'Type' elif 'Remote' in conf: vlan_info = 'Remote' if conf and ' ' not in filter(None, conf.split('-')): obj = self.render_config(self.generated_spec, conf, vlan_info) if 'mtu' in obj: mtu_objs.append(obj) elif 'remote_span' in obj: remote_objs = obj elif obj: objs.append(obj) # Appending MTU value to the retrieved dictionary for o, m in zip(objs, mtu_objs): o.update(m) final_objs.append(o) # Appending Remote Span value to related VLAN: if remote_objs: if remote_objs.get('remote_span'): for each in remote_objs.get('remote_span'): for every in final_objs: if each == every.get('vlan_id'): every.update({'remote_span': True}) break facts = {} if final_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