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 """ self.router_id = None self.root = build_root_xml_node("configuration") self.protocols = build_child_xml_node(self.root, "protocols") self.routing_options = build_child_xml_node(self.root, "routing-options") state = self._module.params["state"] if (state in ("merged", "replaced", "overridden", "rendered") and not want): self._module.fail_json( msg="value of config parameter must not be empty for state {0}" .format(state)) config_xmls = [] if state == "overridden": config_xmls = self._state_overridden(want, have) elif state == "deleted": config_xmls = self._state_deleted(want, have) elif state in ("merged", "rendered"): config_xmls = self._state_merged(want, have) elif state == "replaced": config_xmls = self._state_replaced(want, have) for xml in config_xmls: self.protocols.append(xml) return [tostring(xml) for xml in self.root.getchildren()]
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"] root = build_root_xml_node("configuration") routing_options = build_child_xml_node(root, "routing-options") routing_instances = build_child_xml_node(root, "routing-instances") if state == "overridden": config_xmls = self._state_overridden(want, have) elif state == "deleted": config_xmls = self._state_deleted(want, have) elif state == "merged": config_xmls = self._state_merged(want, have) elif state == "replaced": config_xmls = self._state_replaced(want, have) for xml in config_xmls: if xml["root_type"] == "routing-options": routing_options.append(xml["static_route_xml"]) elif xml["root_type"] == "routing-instances": routing_instances.append(xml["static_route_xml"]) return [tostring(xml) for xml in root.getchildren()]
def _state_deleted(self, want, have): """ The command generator when state is deleted :rtype: A list :returns: the xml necessary to migrate the current configuration to the desired configuration """ ospf_xml = [] delete = {"delete": "delete"} if not want: ospf_node = build_child_xml_node(self.protocols, "ospf") ospf_node.attrib.update(delete) router_id = have[0].get("router_id") if router_id: build_child_xml_node( self.routing_options, "router-id", self.router_id, attrib=delete, ) return ospf_node ospf_xml = self._state_merged(want, have, delete=delete) return ospf_xml
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 """ plist_xml = [] existing_plist = [] plist_node = None delete = {"delete": "delete"} if have is not None: # get the instances in running config # form existing instance list for h_rinst in have: existing_plist.append(h_rinst["name"]) # Delete target routing-instance if want: for entry in want: if entry["name"] not in existing_plist: continue plist_node = build_root_xml_node("prefix-list") build_child_xml_node(plist_node, "name", entry["name"]) plist_node.attrib.update(delete) plist_xml.append(plist_node) else: # Delete all the routing-instance plist_node = build_root_xml_node("prefix-list") plist_node.attrib.update(delete) plist_xml.append(plist_node) if plist_node is not None: plist_xml.append(plist_node) return plist_xml
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 """ delete = {"delete": "delete"} if have is not None: build_child_xml_node(self.root, "snmp", None, delete)
def _state_merged(self, want, have, delete=None): """ The command generator when state is merged :rtype: A list :returns: the xml necessary to migrate the current configuration to the desired configuration """ acl_intf_xml = [] for config in want: root_node, unit_node = self._get_common_xml_node(config["name"]) build_child_xml_node(unit_node, "name", "0") family_node = build_child_xml_node(unit_node, "family") for acl_filter in config["access_groups"]: inet_family = "inet" if acl_filter["afi"] == "ipv6": inet_family = "inet6" inet_node = build_child_xml_node(family_node, inet_family) if acl_filter.get("acls"): filter_node = build_child_xml_node(inet_node, "filter") for acl in acl_filter["acls"]: acl_node = None if acl["direction"] == "in": acl_node = build_child_xml_node( filter_node, "input-list", acl["name"]) else: acl_node = build_child_xml_node( filter_node, "output-list", acl["name"]) if delete: acl_node.attrib.update(delete) elif delete: build_child_xml_node(inet_node, "filter", None, delete) acl_intf_xml.append(root_node) return acl_intf_xml
def _state_merged(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 list xml configuration necessary to migrate the current configuration to the desired configuration """ family_xml = [] family_root = build_root_xml_node("family") want = remove_empties(want) # Generate xml node for autonomous-system if want.get("as_number"): build_child_xml_node( self.routing_options, "autonomous-system", want.get("as_number"), ) w_af_list = want.get("address_family") # render global address family attribute commands self.render_af(w_af_list, family_root) # render commands for group address family attribute commands if "groups" in want.keys(): groups = want.get("groups") for group in groups: groups_node = build_root_xml_node("group") build_child_xml_node(groups_node, "name", group["name"]) g_family_root = build_child_xml_node(groups_node, "family") w_gaf_list = group.get("address_family") self.render_af(w_gaf_list, g_family_root) # render neighbor address-family commands if "neighbors" in group.keys(): neighbors = group.get("neighbors") for neighbor in neighbors: neighbors_node = build_child_xml_node( groups_node, "neighbor" ) build_child_xml_node( neighbors_node, "name", neighbor["neighbor_address"], ) n_family_root = build_child_xml_node( neighbors_node, "family" ) w_naf_list = neighbor.get("address_family") self.render_af(w_naf_list, n_family_root) family_xml.append(groups_node) family_xml.append(family_root) return family_xml
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 """ want = remove_empties(want) # add hostname node if "hostname" in want.keys(): build_child_xml_node(self.root, "host-name", want.get("hostname"))
def _state_merged(self, want, have): """The command generator when state is merged :rtype: A list :returns: the xml necessary to merge the provided into the current configuration """ intf_xml = [] for config in want: vlan_name = str(config["name"]) vlan_id = str(config["vlan_id"]) vlan_description = config.get("description") vlan_root = build_root_xml_node("vlan") build_child_xml_node(vlan_root, "name", vlan_name) build_child_xml_node(vlan_root, "vlan-id", vlan_id) if vlan_description: build_child_xml_node(vlan_root, "description", vlan_description) if config.get("l3_interface"): build_child_xml_node(vlan_root, "l3-interface", config.get("l3_interface")) intf_xml.append(vlan_root) return intf_xml
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 """ delete = {"delete": "delete"} if have is not None: if "autonomous_system" in have.keys(): build_child_xml_node(self.routing_options, "autonomous-system", None, delete) if "router_id" in have.keys(): build_child_xml_node(self.routing_options, "router-id", None, delete)
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 """ self.root = build_root_xml_node("configuration") self.snmp = build_child_xml_node(self.root, "snmp") cmd_lst = [] state = self._module.params["state"] if (state in ("merged", "replaced", "rendered", "overridden") and not want): self._module.fail_json( msg="value of config parameter must not be empty for state {0}" .format(state)) if state == "deleted": self._state_deleted(want, have) elif state in ("merged", "rendered"): self._state_merged(want, have) elif state == "replaced": self._state_replaced(want, have) elif state == "overridden": self._state_replaced(want, have) if self.root is not None: for xml in self.root.getchildren(): xml = tostring(xml) cmd_lst.append(xml) return cmd_lst
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 """ lacp_xml = [] lacp_root = build_root_xml_node('lacp') build_child_xml_node(lacp_root, 'system-priority', None, {'delete': 'delete'}) element = build_child_xml_node(lacp_root, 'link-protection', None, {'delete': 'delete'}) build_child_xml_node(element, 'non-revertive', None, {'delete': 'delete'}) lacp_xml.append(lacp_root) return lacp_xml
def _add_node(self, want, h_key, w_key, node, cfg=False): """ Append the child node to the root node :param want: the desired configuration as a dictionary :param h_key: the current configuration key :param: node: root node """ if cfg: if want.get(w_key): build_child_xml_node(node, h_key, want[w_key]) else: if w_key in want.keys(): b_val = want.get(w_key) if b_val is not None: if b_val is True: build_child_xml_node(node, h_key) return node
def _state_merged(self, want, have): """ The xml generator when state is merged :rtype: A list :returns: the xml necessary to merge the provided into the current configuration """ intf_xml = [] for config in want: root_node, unit_node = self._get_common_xml_node(config['name']) build_child_xml_node(unit_node, 'name', str(config['unit'])) if config.get('ipv4'): self.build_ipaddr_et(config, unit_node) if config.get('ipv6'): self.build_ipaddr_et(config, unit_node, protocol='ipv6') intf_xml.append(root_node) return intf_xml
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 """ prefix_list_xml = [] for instance in want: instance = remove_empties(instance) # generate node: prefix-list prefix_root = build_root_xml_node("prefix-list") # generate node: name if "name" in instance.keys(): build_child_xml_node(prefix_root, "name", instance.get("name")) # generate node: prefix-list-item if "address_prefixes" in instance.keys(): address_prefixes = instance.get("address_prefixes") for entry in address_prefixes: add_prefix_node = build_child_xml_node( prefix_root, "prefix-list-item") # generate name node build_child_xml_node(add_prefix_node, "name", entry) # generate node: dynamic_db if "dynamic_db" in instance.keys() and instance.get("dynamic_db"): build_child_xml_node(prefix_root, "dynamic-db") prefix_list_xml.append(prefix_root) return prefix_list_xml
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 """ routing_xml = [] want = remove_empties(want) # add authentication-keys node if "autonomous_system" in want.keys(): as_num = want.get("autonomous_system") # Generate xml node for autonomous-system if as_num.get("as_number"): as_node = build_child_xml_node( self.routing_options, "autonomous-system", as_num.get("as_number"), ) # Add node for loops if as_num.get("loops"): build_child_xml_node(as_node, "loops", as_num.get("loops")) # Add node for asdot_notation if as_num.get("asdot_notation"): if "asdot_notation" in as_num.keys(): build_child_xml_node(as_node, "asdot-notation") if "router_id" in want.keys(): build_child_xml_node(self.routing_options, "router-id", want.get("router_id")) return routing_xml
def _state_purged(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 """ bgp_xml = [] delete = {"delete": "delete"} build_child_xml_node(self.protocols, "bgp", None, delete) autonomous_system = have.get("as_number") if autonomous_system: build_child_xml_node( self.routing_options, "autonomous-system", None, {"delete": "delete"}, ) return bgp_xml
def _state_merged(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 list xml configuration necessary to migrate the current configuration to the desired configuration """ lacp_xml = [] lacp_root = build_root_xml_node('lacp') build_child_xml_node(lacp_root, 'system-priority', want.get('system_priority')) if want.get('link_protection') == 'non-revertive': build_subtree(lacp_root, 'link-protection/non-revertive') elif want.get('link_protection') == 'revertive': link_root = build_child_xml_node(lacp_root, 'link-protection') build_child_xml_node(link_root, 'non-revertive', None, {'delete': 'delete'}) lacp_xml.append(lacp_root) return lacp_xml
def _state_deleted(self, want, have): """ The command generator when state is deleted :rtype: A list :returns: the xml necessary to migrate the current configuration to the desired configuration """ ospf_xml = [] delete = {"delete": "delete"} if have: for have_ospf in have: have_areas = have_ospf.get("areas") or [] for area in have_areas: ospf_node = build_child_xml_node(self.protocols, "ospf") area_node = build_child_xml_node(ospf_node, "area", area["area_id"]) area_node.attrib.update(delete) ospf_xml.append(ospf_node) return ospf_xml
def _state_replaced(self, want, have): """The command generator when state is replaced :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ self._state_deleted(want, have) self.snmp = build_child_xml_node(self.root, "snmp") self._state_merged(want, have)
def _state_deleted(self, want, have): """ The command generator when state is deleted :rtype: A list :returns: the xml necessary to remove the current configuration of the provided objects """ intf_xml = [] if not want: want = have for config in want: vlan_name = config["name"] vlan_root = build_root_xml_node("vlan") vlan_root.attrib.update({"delete": "delete"}) build_child_xml_node(vlan_root, "name", vlan_name) intf_xml.append(vlan_root) return intf_xml
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 """ lldp_xml = [] lldp_root = build_root_xml_node("lldp") build_child_xml_node(lldp_root, "management-address", None, {"delete": "delete"}) build_child_xml_node(lldp_root, "advertisement-interval", None, {"delete": "delete"}) build_child_xml_node(lldp_root, "transmit-delay", None, {"delete": "delete"}) build_child_xml_node(lldp_root, "hold-multiplier", None, {"delete": "delete"}) build_child_xml_node(lldp_root, "disable", None, {"delete": "delete"}) lldp_xml.append(lldp_root) return lldp_xml
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 """ lldp_xml = [] lldp_root = build_root_xml_node('lldp') build_child_xml_node(lldp_root, 'management-address', None, {'delete': 'delete'}) build_child_xml_node(lldp_root, 'advertisement-interval', None, {'delete': 'delete'}) build_child_xml_node(lldp_root, 'transmit-delay', None, {'delete': 'delete'}) build_child_xml_node(lldp_root, 'hold-multiplier', None, {'delete': 'delete'}) build_child_xml_node(lldp_root, 'disable', None, {'delete': 'delete'}) lldp_xml.append(lldp_root) return lldp_xml
def _state_deleted(self, want, have): """ The xml configuration generator when state is deleted :rtype: A list :returns: the xml configuration necessary to remove the current configuration of the provided objects """ lldp_intf_xml = [] intf_obj = want if not intf_obj: # delete lldp interfaces attribute from all the existing interface intf_obj = have for config in intf_obj: lldp_intf_root = build_root_xml_node("interface") lldp_intf_root.attrib.update({"delete": "delete"}) build_child_xml_node(lldp_intf_root, "name", config["name"]) lldp_intf_xml.append(lldp_intf_root) return lldp_intf_xml
def _state_overridden(self, want, have): """The xml configuration generator when state is merged :rtype: A list :returns: the xml configuration necessary to merge the provided into the current configuration """ bgp_xml = [] family_root = None if have is not None and have.get("address_family"): h_af = have.get("address_family") existing_af = [af["afi"] for af in h_af] for af in existing_af: if family_root is None: family_root = build_child_xml_node(self.bgp, "family") build_child_xml_node(family_root, af, None, {"delete": "delete"}) if family_root is not None: bgp_xml.append(family_root) bgp_xml.extend(self._state_deleted(want, have)) bgp_xml.extend(self._state_merged(want, have)) return bgp_xml
def _state_merged(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 list xml configuration necessary to migrate the current configuration to the desired configuration """ lacp_xml = [] lacp_root = build_root_xml_node("lacp") build_child_xml_node(lacp_root, "system-priority", want.get("system_priority")) if want.get("link_protection") == "non-revertive": build_subtree(lacp_root, "link-protection/non-revertive") elif want.get("link_protection") == "revertive": link_root = build_child_xml_node(lacp_root, "link-protection") build_child_xml_node(link_root, "non-revertive", None, {"delete": "delete"}) lacp_xml.append(lacp_root) return lacp_xml
def _state_purged(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 """ bgp_xml = [] delete = {"delete": "delete"} bgp_node = build_child_xml_node(self.root, "bgp") bgp_node.attrib.update(delete) bgp_xml.append(bgp_node) return bgp_xml
def _state_overridden(self, want, have): """ The command generator when state is overridden :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ plist_xml = [] delete = {"delete": "delete"} if have is not None: have_plist = [entry["name"] for entry in have] want_plist = [entry["name"] for entry in want] for instance in have_plist: if instance not in want_plist: plist_node = build_root_xml_node("prefix-list") build_child_xml_node(plist_node, "name", instance) plist_node.attrib.update(delete) plist_xml.append(plist_node) plist_xml.extend(self._state_deleted(want, have)) plist_xml.extend(self._state_merged(want, have)) return plist_xml
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 """ rinst_xml = [] existing_rinsts = [] rinstance_node = None delete = {"delete": "delete"} if have is not None: # get the instances in running config # form existing instance list for h_rinst in have: existing_rinsts.append(h_rinst["name"]) # Delete target routing-instance if want: for instance in want: if instance["name"] not in existing_rinsts: continue rinstance_node = build_root_xml_node("instance") build_child_xml_node(rinstance_node, "name", instance["name"]) rinstance_node.attrib.update(delete) rinst_xml.append(rinstance_node) else: # Delete all the routing-instance rinstance_node = build_root_xml_node("instance") rinstance_node.attrib.update(delete) rinst_xml.append(rinstance_node) if rinstance_node is not None: rinst_xml.append(rinstance_node) return rinst_xml
def _state_deleted(self, want, have): """ The command generator when state is deleted :rtype: A list :returns: the xml necessary to migrate the current configuration to the desired configuration """ acls_xml = [] family_node = build_root_xml_node("family") delete = dict(delete="delete") if not want: want = have for config in want: try: family = "inet6" if config.get("afi") == "ipv6" else "inet" except KeyError: family = "inet" inet_node = build_child_xml_node(family_node, family) # Look deeply into have to match replace correctly existing_acls = [] for conf in have: if conf.get("afi") == config.get("afi"): existing_acls.extend(conf["acls"] or []) acl_names = [acl["name"] for acl in existing_acls] if not config["acls"]: inet_node.attrib.update(delete) continue for acl in config["acls"]: if acl["name"] not in acl_names: continue filter_node = build_child_xml_node(inet_node, "filter") build_child_xml_node(filter_node, "name", acl["name"]) if not acl.get("aces"): filter_node.attrib.update(delete) continue for ace in acl["aces"]: # if ace["name"] not in ace_names: term_node = build_child_xml_node(filter_node, "term") build_child_xml_node(term_node, "name", ace["name"]) term_node.attrib.update(delete) acls_xml.append(family_node) return acls_xml