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 = [] for key, value in iteritems( flatten_dict(dict_delete(have, remove_empties(want))) ): cmd = self._compute_commands(key, value, remove=True) if cmd: commands.append(cmd) 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) 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_ospf_param(self, want, have, opr=True): """ This function forms the set/delete commands for ospf leaf attributes and triggers the process for other child attributes. for firewall_global attributes. :param w: the desired config. :param h: the target config. :param opr: True/False. :return: generated commands list. """ commands = [] w = deepcopy(remove_empties(want)) if w: for key, val in iteritems(w): commands.extend(self._render_child_param(w, have, key, opr)) return commands
def _state_deleted(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 = [] for key, value in iteritems(flatten_dict(dict_delete(have, remove_empties(want)))): commands.append(Lacp_interfaces._compute_commands(key, value, remove=True)) if commands: pad_commands(commands, have['name']) return commands
def parse_attribs(self, attribs, conf): config = {} for item in attribs: value = utils.parse_conf_arg(conf, item) if value and item == 'mtu': config[item] = int(value.strip("'")) elif value: config[item] = value.strip("'") else: config[item] = None if 'disable' in conf: config['enabled'] = False else: config['enabled'] = 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) vms = [] conf_config = conf[0][ "extreme-virtual-service:virtual-services-config"] conf_state = conf[1]["extreme-virtual-service:virtual-services-state"] if conf_config.get("virtual-service-config") and conf_state.get( "virtual-service-state"): conf_config = conf_config["virtual-service-config"] conf_state = conf_state["virtual-service-state"] for d in range(len(conf_config)): config["auto_start"] = conf_config[d]["enable"] config["image"] = conf_state[d]["package-info"]["path"] + str( '/') + conf_state[d]["package-info"]["name"] config["memory_size"] = conf_config[d]["memory-size"] config["name"] = conf_config[d]["name"] config["num_cores"] = conf_config[d]["num-cores"] config["operational_state"] = "started" if conf_state[d][ "state"]["state"] == 1 else "stopped" config["virtual_ports"] = [] if conf_config[d].get("vports"): conf_vport = conf_config[d]["vports"]["vport"] for num in range(len(conf_config[d]["vports"]["vport"])): config_vport = {} config_vport["name"] = conf_vport[num].get("name") config_vport["type"] = conf_vport[num].get( "connect-type").lower() config_vport["port"] = conf_vport[num].get("port") if conf_vport[num].get("vlans"): config_vport["vlan_id"] = conf_vport[num]["vlans"][ "vlan"][0]["id"] config["virtual_ports"].append(config_vport) config["vnc"]["enabled"] = False if conf_config[d][ "vnc-port"] == 0 else True config["vnc"]["port"] = conf_config[d]["vnc-port"] vms.append(utils.remove_empties(config)) return vms
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> <protocols> <lldp> <interface> </interface> </lldp> </protocols> </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/protocols/lldp/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["lldp_interfaces"] = [] params = utils.validate_config( self.argument_spec, {"config": objs} ) for cfg in params["config"]: facts["lldp_interfaces"].append(utils.remove_empties(cfg)) ansible_facts["ansible_network_resources"].update(facts) return ansible_facts
def set_state(self, want, have): """ Select the appropriate function based on the state provided :param want: the desired configuration as a dictionary :param have: the current configuration as a dictionary :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ state = self._module.params['state'] commands = [] if state in ('overridden', 'merged', 'replaced', 'rendered') and not want: self._module.fail_json( msg='value of config parameter must not be empty for state {0}' .format(state)) if state == 'overridden': commands.extend(self._state_overridden(want, have)) elif state == 'deleted': if not want: for intf in have: commands.extend(self._state_deleted({}, intf)) else: for item in want: obj_in_have = search_obj_in_list(item['name'], have) or {} commands.extend( self._state_deleted(remove_empties(item), obj_in_have)) else: # Instead of passing entire want and have # list of dictionaries to the respective # _state_* methods we are passing the want # and have dictionaries per interface for item in want: name = item['name'] obj_in_have = search_obj_in_list(name, have) or {} if state == 'merged' or state == 'rendered': commands.extend(self._state_merged(item, obj_in_have)) elif state == 'replaced': commands.extend(self._state_replaced(item, obj_in_have)) return commands
def populate_facts(self, connection, ansible_facts, data=None): """Populate the facts for Prefix_lists network resource :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ facts = {} if not data: data = self.get_config(connection) # parse native config using the Prefix_lists template prefix_lists_parser = Prefix_listsTemplate(lines=data.splitlines(), module=self._module) objs = prefix_lists_parser.parse() if objs: for afi, pl in iteritems(objs): if "prefix_lists" in pl: pl["prefix_lists"] = sorted( list(pl["prefix_lists"].values()), key=lambda k, sk="name": k[sk], ) for plist in pl["prefix_lists"]: for en in plist: if "entries" in en: plist["entries"] = sorted( list(plist["entries"].values()), key=lambda k, sk="sequence": k[sk], ) objs = sorted(list(objs.values()), key=lambda k, sk="afi": k[sk]) else: objs = [] ansible_facts["ansible_network_resources"].pop("prefix_lists", None) params = utils.remove_empties( prefix_lists_parser.validate_config(self.argument_spec, {"config": objs}, redact=True)) facts["prefix_lists"] = params.get("config", []) ansible_facts["ansible_network_resources"].update(facts) return ansible_facts
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 "VLAN Name" not in conf: conf = list(filter(None, conf.split(" "))) config["vlan_id"] = int(conf[0]) config["name"] = conf[1] try: 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" except IndexError: pass elif vlan_info == "Type" and "VLAN 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 populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for ospfv2 :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_ospfv2_data(connection) ipv4 = {"processes": []} rmmod = NetworkTemplate(lines=data.splitlines(), tmplt=Ospfv2Template()) current = rmmod.parse() # convert some of the dicts to lists for key, sortv in [("processes", "process_id")]: if key in current and current[key]: current[key] = current[key].values() current[key] = sorted(current[key], key=lambda k, sk=sortv: k[sk]) for process in current.get("processes", []): if "areas" in process: process["areas"] = list(process["areas"].values()) process["areas"] = sorted(process["areas"], key=lambda k, sk="area_id": k[sk]) for area in process["areas"]: # if 'ranges' in area: # area['ranges'] = sorted(area['ranges'], # key=lambda k, s='ranges': k[s]) if "filters" in area: area["filters"].sort() ipv4["processes"].append(process) ansible_facts["ansible_network_resources"].pop("ospfv2", None) facts = {} if current: params = utils.validate_config(self.argument_spec, {"config": ipv4}) params = utils.remove_empties(params) facts["ospfv2"] = 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 acls :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) # split the config into instances of the resource find_pattern = r'(?:^|\n)(?:ip|ipv6) access\-list.*?(?=(?:^|\n)(?:ip|ipv6) access\-list|$)' resources = [p for p in re.findall(find_pattern, data, re.DOTALL)] objs = [] ipv4list = [] ipv6list = [] for resource in resources: if "ipv6" in resource: ipv6list.append(resource) else: ipv4list.append(resource) ipv4list = ["\n".join(ipv4list)] ipv6list = ["\n".join(ipv6list)] for resource in ipv4list: if resource: obj = self.render_config(self.generated_spec, resource) if obj: objs.append(obj) for resource in ipv6list: if resource: obj = self.render_config(self.generated_spec, resource) if obj: objs.append(obj) ansible_facts['ansible_network_resources'].pop('acls', None) facts = {} if objs: facts['acls'] = [] params = utils.validate_config(self.argument_spec, {'config': objs}) for cfg in params['config']: facts['acls'].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 Bgp_global network resource :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ facts = {} objs = {} config_lines = [] if not data: data = self.get_device_data(connection) for resource in data.splitlines(): if "address-family" not in resource: config_lines.append(re.sub("'", "", resource)) bgp_global_parser = Bgp_globalTemplate(lines=config_lines, module=self._module) objs = bgp_global_parser.parse() if "neighbor" in objs: objs["neighbor"] = list(objs["neighbor"].values()) objs["neighbor"] = sorted(objs["neighbor"], key=lambda k: k["address"]) if "network" in objs: objs["network"] = sorted(objs["network"], key=lambda k: k["address"]) if "aggregate_address" in objs: objs["aggregate_address"] = sorted(objs["aggregate_address"], key=lambda k: k["prefix"]) ansible_facts["ansible_network_resources"].pop("bgp_global", None) params = utils.remove_empties( bgp_global_parser.validate_config(self.argument_spec, {"config": objs}, redact=True)) facts["bgp_global"] = params.get("config", []) ansible_facts["ansible_network_resources"].update(facts) return ansible_facts
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" ) else: running_config = data.split("\n\n") structured, run_cfg_output = running_config[0], running_config[1] # 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 static_routes :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ if not HAS_LXML: self._module.fail_json(msg="lxml is not installed.") if not HAS_XMLTODICT: self._module.fail_json(msg="xmltodict is not installed.") if not data: config_filter = """ <configuration> <routing-instances/> <routing-options/> </configuration> """ data = connection.get_configuration(filter=config_filter) if isinstance(data, string_types): data = etree.fromstring( to_bytes(data, errors="surrogate_then_replace")) resources = data.xpath("configuration/routing-options") vrf_resources = data.xpath("configuration/routing-instances") resources.extend(vrf_resources) objs = [] for resource in resources: if resource is not None: xml = self._get_xml_dict(resource) obj = self.render_config(self.generated_spec, xml) if obj: objs.append(obj) facts = {} if objs: facts["static_routes"] = [] params = utils.validate_config(self.argument_spec, {"config": objs}) for cfg in params["config"]: facts["static_routes"].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 acls :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ if not HAS_LXML: self._module.fail_json(msg=missing_required_lib("lxml")) if not data: config_filter = """ <configuration> <firewall/> </configuration> """ data = connection.get_configuration(filter=config_filter) if isinstance(data, string_types): data = etree.fromstring( to_bytes(data, errors="surrogate_then_replace")) resources = data.xpath("configuration/firewall") objs = [] for resource in resources: if resource: xml = self._get_xml_dict(resource) for family, sub_dict in xml["firewall"]["family"].items(): sub_dict["family"] = family obj = self.render_config(self.generated_spec, dict(firewall=sub_dict)) if obj: objs.append(obj) facts = {} if objs: facts["junos_acls"] = [] params = utils.validate_config(self.argument_spec, {"config": objs}) for cfg in params["config"]: facts["junos_acls"].append(utils.remove_empties(cfg)) ansible_facts["ansible_network_resources"].update(facts) return ansible_facts
def set_config(self, existing_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"])}) want.append(remove_empties(w)) have = deepcopy(existing_interfaces_facts) resp = self.set_state(want, have) return to_list(resp)
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, 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 """ vif_conf = "\n".join(filter(lambda x: ("vif" in x), conf)) eth_conf = "\n".join(filter(lambda x: ("vif" not in x), conf)) config = self.parse_attribs(["description", "speed", "mtu", "duplex"], eth_conf) config["vifs"] = self.parse_vifs(vif_conf) 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 {} 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_mode = utils.parse_conf_arg(conf, 'switchport mode') if has_mode: config['mode'] = has_mode has_access = utils.parse_conf_arg(conf, 'switchport access vlan') if has_access: config["access"] = {"vlan": int(has_access)} has_voice = utils.parse_conf_arg(conf, 'switchport voice vlan') if has_voice: config["voice"] = {"vlan": int(has_voice)} 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 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 match.group(1).lower() == "preconfigure": match = re.search(r"^(\S+) (.*)", conf) if match: intf = match.group(2) if get_interface_type(intf) == "unknown": return {} # populate the facts from the configuration config["name"] = intf # Get the configured IPV4 details ipv4 = [] ipv4_all = re.findall(r"ipv4 address (\S+.*)", conf) for each in ipv4_all: each_ipv4 = dict() if "secondary" in each: each_ipv4["address"] = each.split(" secondary")[0] each_ipv4["secondary"] = True else: each_ipv4["address"] = each 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() each_ipv6["address"] = each ipv6.append(each_ipv6) config["ipv6"] = ipv6 return utils.remove_empties(config)
def populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for bgp_global :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ if not HAS_LXML: self._module.fail_json(msg="lxml is not installed.") if not data: config_filter = """ <configuration> <protocols> <bgp> </bgp> </protocols> </configuration> """ data = self.get_connection(connection, config_filter) if isinstance(data, string_types): data = etree.fromstring( to_bytes(data, errors="surrogate_then_replace")) objs = {} resources = data.xpath("configuration/protocols/bgp") autonomous_system = data.xpath( "configuration/routing-options/autonomous-system") if autonomous_system: self.autonomous_system = self._get_xml_dict( autonomous_system.pop()) else: self.autonomous_system = "" for resource in resources: if resource: xml = self._get_xml_dict(resource) objs = self.render_config(self.generated_spec, xml) facts = {} if objs: facts["bgp_global"] = {} params = utils.validate_config(self.argument_spec, {"config": objs}) facts["bgp_global"] = utils.remove_empties(params["config"]) ansible_facts["ansible_network_resources"].update(facts) return ansible_facts
def main(): api_keys_list_spec = { "key_name": dict(type="str"), "id": dict(type="str"), "description": dict(type="str"), "locale": dict(type="str", choices=["en-US", "ja-JP"]), "role_id": dict(type="int"), "time_zone": dict(type="str"), "active": dict(type="bool"), "created": dict(type="int"), "last_sign_in": dict(type="int"), "unlock_time": dict(type="int"), "unsuccessful_sign_in_attempts": dict(type="int"), "expiry_date": dict(type="int"), "secret_key": dict(no_log=True, type="str"), "service_account": dict(type="bool"), "current": dict(type="bool"), } argspec = dict( state=dict(choices=["present", "absent", "gathered"], default="present"), api_keys=dict( type="list", elements="dict", options=api_keys_list_spec, no_log=False, ), ) module = AnsibleModule(argument_spec=argspec, supports_check_mode=True) deepsec_request = DeepSecurityRequest(module) module.params = utils.remove_empties(module.params) if module.params["state"] == "gathered": display_gathered_result(argspec=argspec, module=module, deepsec_request=deepsec_request) elif module.params["state"] == "absent": delete_module_api_config(argspec=argspec, module=module, deepsec_request=deepsec_request) elif module.params["state"] == "present": configure_module_api(argspec=argspec, module=module, deepsec_request=deepsec_request)
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 """ vif_conf = '\n'.join(filter(lambda x: ('vif' in x), conf)) eth_conf = '\n'.join(filter(lambda x: ('vif' not in x), conf)) config = self.parse_attribs(['description', 'speed', 'mtu', 'duplex'], eth_conf) config['vifs'] = self.parse_vifs(vif_conf) return utils.remove_empties(config)
def _state_deleted(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 = [] for x in [ k for k in have.get("system", {}) if k not in remove_empties(want.get("system", {})) ]: commands.append("no lacp system {0}".format(x)) 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['access_groups'] = [] acl_v4_config = {} acl_v6_config = {} def common_iter_code(cmd, conf): # Common code for IPV4 and IPV6 config parsing acls = [] re_cmd = cmd + ' (\\S+.*)' ip_all = re.findall(re_cmd, conf) for each in ip_all: acl = {} access_grp_config = each.split(' ') acl['name'] = access_grp_config[0] acl['direction'] = access_grp_config[1] acls.append(acl) return acls if 'ip' in conf: acls = common_iter_code('ip access-group', conf) acl_v4_config['afi'] = 'ipv4' acl_v4_config['acls'] = acls config['access_groups'].append(acl_v4_config) if 'ipv6' in conf: acls = common_iter_code('ipv6 traffic-filter', conf) acl_v6_config['afi'] = 'ipv6' acl_v6_config['acls'] = acls config['access_groups'].append(acl_v6_config) return utils.remove_empties(config)
def populate_facts(self, connection, ansible_facts, data=None): """Populate the facts for Logging_global network resource :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ facts = {} objs = [] sev_map = get_logging_sevmap() if not data: data = self.get_config(connection) # parse native config using the Logging_global template logging_global_parser = Logging_globalTemplate(lines=data.splitlines(), module=self._module) objs = logging_global_parser.parse() if objs: for k in ("console", "history", "logfile", "module", "monitor"): if "severity" in objs.get(k, {}): objs[k]["severity"] = sev_map[objs[k]["severity"]] # pre-sort list of dictionaries pkey = {"hosts": "host", "facilities": "facility"} for x in ("hosts", "facilities"): if x in objs: for item in objs[x]: if "severity" in item: item["severity"] = sev_map[item["severity"]] objs[x] = sorted(objs[x], key=lambda k: k[pkey[x]]) ansible_facts["ansible_network_resources"].pop("logging_global", None) params = utils.remove_empties( logging_global_parser.validate_config(self.argument_spec, {"config": objs}, redact=True)) facts["logging_global"] = params.get("config", {}) ansible_facts["ansible_network_resources"].update(facts) return ansible_facts
def _state_merged(self, 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 = [] want_copy = deepcopy(remove_empties(want)) have_copy = deepcopy(have) want_vifs = want_copy.pop("vifs", []) have_vifs = have_copy.pop("vifs", []) updates = dict_diff(have_copy, want_copy) if updates: for key, value in iteritems(updates): commands.append( self._compute_commands(key=key, value=value, interface=want_copy["name"])) if want_vifs: for want_vif in want_vifs: have_vif = search_obj_in_list(want_vif["vlan_id"], have_vifs, key="vlan_id") if not have_vif: have_vif = { "vlan_id": want_vif["vlan_id"], "enabled": True, } vif_updates = dict_diff(have_vif, want_vif) if vif_updates: for key, value in iteritems(vif_updates): commands.append( self._compute_commands( key=key, value=value, interface=want_copy["name"], vif=want_vif["vlan_id"], )) return commands
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 = [] if not want: want = [{'afi': 'ipv4'}, {'afi': 'ipv6'}] for item in want: item = remove_empties(item) have_item = search_obj_in_list(item['afi'], have, key='afi') or {} if 'acls' not in item: if have_item: for acl in have_item['acls']: commands.append('no {0} access-list {1}'.format( have_item['afi'], acl['name'])) else: for want_acl in item['acls']: have_acl = search_obj_in_list( want_acl['name'], have_item.get('acls', [])) or {} if have_acl: if 'aces' not in want_acl: commands.append('no {0} access-list {1}'.format( have_item['afi'], have_acl['name'])) else: acl_updates = [] for want_ace in want_acl['aces']: have_ace = search_obj_in_list( want_ace.get('sequence'), have_acl.get('aces', []), key='sequence') or {} if have_ace: acl_updates.append('no {0}'.format( have_ace['sequence'])) if acl_updates: acl_updates.insert( 0, '{0} access-list {1}'.format( have_item['afi'], have_acl['name'])) commands.extend(acl_updates) 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["access_groups"] = [] acl_v4_config = {} acl_v6_config = {} def common_iter_code(cmd, conf): # Common code for IPV4 and IPV6 config parsing acls = [] re_cmd = cmd + " (\\S+.*)" ip_all = re.findall(re_cmd, conf) for each in ip_all: acl = {} access_grp_config = each.split(" ") acl["name"] = access_grp_config[0] acl["direction"] = access_grp_config[1] acls.append(acl) return acls if "ip" in conf: acls = common_iter_code("ip access-group", conf) acl_v4_config["afi"] = "ipv4" acl_v4_config["acls"] = acls config["access_groups"].append(acl_v4_config) if "ipv6" in conf: acls = common_iter_code("ipv6 traffic-filter", conf) acl_v6_config["afi"] = "ipv6" acl_v6_config["acls"] = acls config["access_groups"].append(acl_v6_config) return utils.remove_empties(config)