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 """ commands = [] want_afi = [w["afi"] for w in want] for h in have: if h["afi"] in want_afi: w = search_obj_in_list(h["afi"], want, "afi") for h_acl in h["acls"]: w_acl = search_obj_in_list(h_acl["name"], w["acls"], "name") if not w_acl: del_dict = { "afi": h["afi"], "acls": [{ "name": h_acl["name"] }], } commands.extend(self._state_deleted([del_dict], have)) else: # if afi is not in want commands.extend(self._state_deleted([{"afi": h["afi"]}], have)) for w in want: commands.extend(self._state_replaced(w, have)) return commands
def set_commands(self, want, have, deleted=False): commands = [] have_name = search_obj_in_list(want["name"], have, "name") if have_name and have_name.get("access_groups"): if want.get("access_groups"): for w_afi in want["access_groups"]: ip = "ipv6" if w_afi["afi"] == "ipv4": ip = "ip" have_afi = search_obj_in_list( w_afi["afi"], have_name["access_groups"], "afi" ) if have_afi: new_acls = [] if deleted: if w_afi.get("acls") and have_afi.get("acls"): new_acls = [ acl for acl in w_afi.get("acls") if acl in have_afi.get("acls") ] elif "acls" not in w_afi.keys(): new_acls = have_afi.get("acls") else: if w_afi.get("acls"): new_acls = [ acl for acl in w_afi["acls"] if acl not in have_afi["acls"] ] commands.extend( self.process_acl(new_acls, ip, deleted) ) else: if not deleted: if w_afi.get("acls"): commands.extend( self.process_acl(w_afi["acls"], ip) ) else: # only name is given to delete if deleted and "access_groups" in have_name.keys(): commands.extend(self.process_access_group(have_name, True)) else: if not deleted: # and 'access_groups' in have_name.keys(): commands.extend(self.process_access_group(want)) if len(commands) > 0: commands.insert(0, "interface " + want["name"]) return commands
def _state_replaced(self, w, have): """ The command generator when state is replaced :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ commands = [] obj_in_have = flatten_dict(search_obj_in_list(w['name'], have, 'name')) if obj_in_have: diff = dict_diff(w, obj_in_have) else: diff = w merged_commands = self.set_commands(w, have, True) if 'name' not in diff: diff['name'] = w['name'] dkeys = diff.keys() for k in w.copy(): if k in self.exclude_params and k in dkeys: del diff[k] replaced_commands = self.del_attribs(diff) if merged_commands: cmds = set(replaced_commands).intersection(set(merged_commands)) for cmd in cmds: merged_commands.remove(cmd) commands.extend(replaced_commands) commands.extend(merged_commands) return commands
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 """ commands = [] del_commands = [] delete_dict = {} obj_in_have = flatten_dict( search_obj_in_list(want["name"], have, "name")) for k1 in obj_in_have.keys(): if k1 not in want.keys(): delete_dict.update({k1: obj_in_have[k1]}) if delete_dict: delete_dict.update({"name": want["name"]}) del_commands = self.del_commands(delete_dict) merged_commands = self.set_commands(want, have) if merged_commands: cmds = set(del_commands).intersection(set(merged_commands)) for cmd in cmds: merged_commands.remove(cmd) commands.extend(del_commands) commands.extend(merged_commands) return commands
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 """ # overridden is the same as replaced behavior except for the scope. cmds = [] existing_interfaces = [] for h in have: existing_interfaces.append(h["name"]) obj_in_want = search_obj_in_list(h["name"], want, "name") if obj_in_want: if h != obj_in_want: replaced_cmds = self._state_replaced(obj_in_want, [h]) if replaced_cmds: cmds.extend(replaced_cmds) else: cmds.extend(self.del_attribs(h)) for w in want: if w["name"] not in existing_interfaces: # This is an object that was excluded from the 'have' list # because all of its params are currently set to default states # -OR- it's a new object that does not exist on the device yet. cmds.extend(self.add_commands(w)) return cmds
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 """ cmds = [] obj_in_have = search_obj_in_list(want["name"], have, "name") if obj_in_have: diff = dict_diff(want, obj_in_have) else: diff = want merged_cmds = self.set_commands(want, have) if "name" not in diff: diff["name"] = want["name"] replaced_cmds = [] if obj_in_have: replaced_cmds = self.del_attribs(diff) if replaced_cmds or merged_cmds: for cmd in set(replaced_cmds).intersection(set(merged_cmds)): merged_cmds.remove(cmd) cmds.extend(replaced_cmds) cmds.extend(merged_cmds) return cmds
def _state_overridden(self, want, have): """ The command generator when state is overridden Scope includes all interface objects on the device. :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ # overridden behavior is the same as replaced except for scope. cmds = [] for i in have: obj_in_want = search_obj_in_list(i["name"], want, "name") if obj_in_want: if i != obj_in_want: v4_cmds = self._v4_cmds( obj_in_want.pop("ipv4", []), i.pop("ipv4", []), state="overridden", ) replaced_cmds = self._state_replaced(obj_in_want, [i]) replaced_cmds.extend(v4_cmds) self.cmd_order_fixup(replaced_cmds, obj_in_want["name"]) cmds.extend(replaced_cmds) else: deleted_cmds = self.generate_delete_commands(i) self.cmd_order_fixup(deleted_cmds, i["name"]) cmds.extend(deleted_cmds) for i in want: if [item for item in have if i["name"] == item["name"]]: continue cmds.extend(self.add_commands(i, name=i["name"])) return cmds
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 """ cmds = [] for h in have: # Clean up bfd attrs for any interfaces not listed in the play h = flatten_dict(h) obj_in_want = flatten_dict( search_obj_in_list(h["name"], want, "name") ) if obj_in_want: # Let the 'want' loop handle all vals for this interface continue cmds.extend(self.del_attribs(h)) for w in want: # Update any want attrs if needed. The overridden state considers # the play as the source of truth for the entire device, therefore # set any unspecified attrs to their default state. w = self.set_none_vals_to_defaults(flatten_dict(w)) cmds.extend(self.set_commands(w, have)) return cmds
def _state_replaced(self, want, have): """ The command generator when state is replaced. Scope is limited to vlan objects defined in the playbook. :rtype: A list :returns: The minimum command set required to migrate the current configuration to the desired configuration. """ obj_in_have = search_obj_in_list(want['vlan_id'], have, 'vlan_id') if obj_in_have: # ignore states that are already reset, then diff what's left obj_in_have = self.remove_default_states(obj_in_have) diff = dict_diff(want, obj_in_have) # Remove merge items from diff; what's left will be used to # remove states not specified in the playbook for k in dict(set(want.items()) - set(obj_in_have.items())).keys(): diff.pop(k, None) else: diff = want # merged_cmds: 'want' cmds to update 'have' states that don't match # replaced_cmds: remaining 'have' cmds that need to be reset to default merged_cmds = self.set_commands(want, have) replaced_cmds = [] if obj_in_have: # Remaining diff items are used to reset states to default replaced_cmds = self.del_attribs(diff) cmds = [] if replaced_cmds or merged_cmds: cmds += ['vlan %s' % str(want['vlan_id'])] cmds += merged_cmds + replaced_cmds return cmds
def _state_overridden(self, want, have): """ The command generator when state is overridden. Scope includes all vlan objects on the device. :rtype: A list :returns: the minimum command set required to migrate the current configuration to the desired configuration. """ # overridden behavior is the same as replaced except for scope. cmds = [] existing_vlans = [] for h in have: existing_vlans.append(h['vlan_id']) obj_in_want = search_obj_in_list(h['vlan_id'], want, 'vlan_id') if obj_in_want: if h != obj_in_want: replaced_cmds = self._state_replaced(obj_in_want, [h]) if replaced_cmds: cmds.extend(replaced_cmds) else: cmds.append('no vlan %s' % h['vlan_id']) # Add wanted vlans that don't exist on the device yet for w in want: if w['vlan_id'] not in existing_vlans: new_vlan = ['vlan %s' % w['vlan_id']] cmds.extend(new_vlan + self.add_commands(w)) return cmds
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 """ commands = [] for h in have: h = flatten_dict(h) obj_in_want = flatten_dict( search_obj_in_list(h['name'], want, 'name')) if h == obj_in_want: continue for w in want: w = flatten_dict(w) if h['name'] == w['name']: wkeys = w.keys() hkeys = h.keys() for k in wkeys: if k in self.exclude_params and k in hkeys: del h[k] commands.extend(self.del_attribs(h)) for w in want: commands.extend(self.set_commands(flatten_dict(w), have, True)) return commands
def set_commands(self, w, have, replace=False): commands = [] obj_in_have = flatten_dict(search_obj_in_list(w['name'], have, 'name')) if not obj_in_have: commands = self.add_commands(w) else: diff = self.diff_of_dicts(w, obj_in_have) if diff and not replace: if 'mode' in diff.keys() and diff['mode']: commands = self.add_commands(diff) if "allowed_vlans" in diff.keys() and diff["allowed_vlans"]: vlan_tobe_added = diff["allowed_vlans"].split(',') vlan_list = vlan_tobe_added[:] if obj_in_have.get("allowed_vlans"): have_vlans = obj_in_have["allowed_vlans"].split(',') else: have_vlans = [] for w_vlans in vlan_list: if w_vlans in have_vlans: vlan_tobe_added.pop(vlan_tobe_added.index(w_vlans)) if vlan_tobe_added: diff.update( {"allowed_vlans": ','.join(vlan_tobe_added)}) if have_vlans: commands = self.add_commands(diff, True) else: commands = self.add_commands(diff) return commands commands = self.add_commands(diff) return commands
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 """ new_commands = [] del_dict = {"name": want["name"], "access_groups": []} obj_in_have = search_obj_in_list(want["name"], have, "name") if obj_in_have != want: commands = [] if obj_in_have and "access_groups" in obj_in_have.keys(): for ag in obj_in_have["access_groups"]: want_afi = [] if want.get("access_groups"): want_afi = search_obj_in_list(ag["afi"], want["access_groups"], "afi") if not want_afi: # whatever in have is not in want del_dict["access_groups"].append(ag) else: del_acl = [] for acl in ag["acls"]: if want_afi.get("acls"): if acl not in want_afi["acls"]: del_acl.append(acl) else: del_acl.append(acl) afi = want_afi["afi"] del_dict["access_groups"].append({ "afi": afi, "acls": del_acl }) commands.extend(self._state_deleted([del_dict], have)) commands.extend(self._state_merged(want, have)) new_commands.append(commands[0]) commands = [ commands[i] for i in range(1, len(commands)) if commands[i] != commands[0] ] new_commands.extend(commands) return new_commands
def set_commands(self, want, have): cmds = [] obj_in_have = flatten_dict(search_obj_in_list(want['name'], have, 'name')) if not obj_in_have: cmds = self.add_commands(want) else: diff = self.diff_of_dicts(want, obj_in_have) cmds = self.add_commands(diff) return cmds
def set_commands(self, w, have): commands = [] obj_in_have = search_obj_in_list(w['vlan_id'], have, 'vlan_id') if not obj_in_have: commands = self.add_commands(w) else: diff = self.diff_of_dicts(w, obj_in_have) commands = self.add_commands(diff) return commands
def set_commands(self, w, have): commands = [] obj_in_have = search_obj_in_list(w["name"], have, "name") if not obj_in_have: commands = self.add_commands(w) else: diff = self.diff_of_dicts(w, obj_in_have) commands = self.add_commands(diff, obj_in_have) return commands
def set_commands(self, w, have): commands = [] obj_in_have = search_obj_in_list(w['name'], have, 'name') if not obj_in_have: commands = self.add_commands(w['members'], w['name']) else: diff = self.diff_list_of_dicts(w['members'], obj_in_have['members']) commands = self.add_commands(diff, w['name']) return commands
def del_intf_commands(self, w, have): commands = [] obj_in_have = search_obj_in_list(w["name"], have, "name") if obj_in_have: lst_to_del = self.intersect_list_of_dicts(w["members"], obj_in_have["members"]) if lst_to_del: for item in lst_to_del: commands.append("interface" + " " + item["member"]) commands.append("no channel-group") return commands
def del_intf_commands(self, w, have): commands = [] obj_in_have = search_obj_in_list(w['name'], have, 'name') if obj_in_have: lst_to_del = self.intersect_list_of_dicts(w['members'], obj_in_have['members']) if lst_to_del: for item in lst_to_del: commands.append('interface' + ' ' + item['member']) commands.append('no channel-group') return commands
def set_commands(self, want, have, deleted=False): commands = [] have_name = search_obj_in_list(want['name'], have, 'name') if have_name and have_name.get('access_groups'): if want.get('access_groups'): for w_afi in want['access_groups']: ip = 'ipv6' if w_afi['afi'] == 'ipv4': ip = 'ip' have_afi = search_obj_in_list( w_afi['afi'], have_name['access_groups'], 'afi') if have_afi: new_acls = [] if deleted: if w_afi.get('acls') and have_afi.get('acls'): new_acls = [ acl for acl in w_afi.get('acls') if acl in have_afi.get('acls')] elif 'acls' not in w_afi.keys(): new_acls = have_afi.get('acls') else: if w_afi.get('acls'): new_acls = [ acl for acl in w_afi['acls'] if acl not in have_afi['acls']] commands.extend(self.process_acl( new_acls, ip, deleted)) else: if not deleted: if w_afi.get('acls'): commands.extend( self.process_acl(w_afi['acls'], ip)) else: # only name is given to delete if deleted and 'access_groups' in have_name.keys(): commands.extend(self.process_access_group(have_name, True)) else: if not deleted: # and 'access_groups' in have_name.keys(): commands.extend(self.process_access_group(want)) if len(commands) > 0: commands.insert(0, 'interface ' + want['name']) return commands
def set_commands(self, want, have): commands = [] obj_in_have = flatten_dict( search_obj_in_list(want["name"], have, "name")) if not obj_in_have: commands = self.add_commands(flatten_dict(want)) else: diff = dict_diff(obj_in_have, want) if diff: diff.update({"name": want["name"]}) commands = self.add_commands(diff) return commands
def _state_purged(self, want, have): """The command generator when state is purged :rtype: A list :returns: the commands necessary to purge interfaces from running configuration """ commands = [] if want: for w in want: obj_in_have = search_obj_in_list(w["name"], have, "name") if obj_in_have: commands.append("no interface {0}".format(w["name"])) return commands
def _state_replaced(self, w, have): """ The command generator when state is replaced :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ commands = [] name = w["name"] obj_in_have = search_obj_in_list(name, have, "name") if obj_in_have: # If 'w' does not specify mode then intf may need to change to its # default mode, however default mode may depend on sysdef. if not w.get("mode") and re.search("Ethernet|port-channel", name): sysdefs = self.intf_defs["sysdefs"] sysdef_mode = sysdefs["mode"] if obj_in_have.get("mode") != sysdef_mode: w["mode"] = sysdef_mode diff = dict_diff(w, obj_in_have) else: diff = w merged_commands = self.set_commands(w, have) if merged_commands: # merged_commands: # - These commands are changes specified by the playbook. # - merged_commands apply to both existing and new objects # replaced_commands: # - These are the unspecified commands, used to reset any params # that are not already set to default states # - replaced_commands should only be used on 'have' objects # (interfaces that already exist) if obj_in_have: if "name" not in diff: diff["name"] = name wkeys = w.keys() dkeys = diff.keys() for k in wkeys: if k in self.exclude_params and k in dkeys: del diff[k] replaced_commands = self.del_attribs(diff) cmds = set(replaced_commands).intersection( set(merged_commands) ) for cmd in cmds: merged_commands.remove(cmd) commands.extend(replaced_commands) commands.extend(merged_commands) return commands
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 """ commands = [] for h in have: obj_in_want = search_obj_in_list(h['name'], want, 'name') if h == obj_in_want: continue commands.extend(self.del_all_attribs(h)) for w in want: commands.extend(self.set_commands(w, have)) return commands
def set_commands(self, w, have): commands = [] obj_in_have = search_obj_in_list(w["name"], have, "name") if not obj_in_have: commands = self.add_commands(w, w["name"]) else: diff = {} diff.update({ "ipv4": self.diff_list_of_dicts(w.get("ipv4"), obj_in_have.get("ipv4")) }) diff.update({ "ipv6": self.diff_list_of_dicts(w.get("ipv6"), obj_in_have.get("ipv6")) }) commands = self.add_commands(diff, w["name"]) return commands
def set_commands(self, w, have): commands = [] obj_in_have = search_obj_in_list(w['name'], have, 'name') if not obj_in_have: commands = self.add_commands(w, w['name']) else: diff = {} diff.update({ 'ipv4': self.diff_list_of_dicts(w.get('ipv4'), obj_in_have.get('ipv4')) }) diff.update({ 'ipv6': self.diff_list_of_dicts(w.get('ipv6'), obj_in_have.get('ipv6')) }) commands = self.add_commands(diff, w['name']) 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 want: for w in want: obj_in_have = search_obj_in_list(w["name"], have, "name") commands.extend(self.del_all_attribs(obj_in_have)) else: if not have: return commands for h in have: commands.extend(self.del_all_attribs(h)) 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 """ if not (want or have): return [] cmds = [] if want: for w in want: obj_in_have = flatten_dict(search_obj_in_list(w['name'], have, 'name')) cmds.extend(self.del_attribs(obj_in_have)) else: for h in have: cmds.extend(self.del_attribs(flatten_dict(h))) return cmds
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 want: for w in want: obj_in_have = search_obj_in_list(w['vlan_id'], have, 'vlan_id') commands.append('no vlan ' + str(obj_in_have['vlan_id'])) else: if not have: return commands for h in have: commands.append('no vlan ' + str(h['vlan_id'])) return commands
def _state_replaced(self, want, have): """ The command generator when state is replaced Scope is limited to interface objects defined in the playbook. :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ cmds = [] name = want["name"] obj_in_have = search_obj_in_list(want["name"], have, "name") have_v4 = obj_in_have.pop("ipv4", []) if obj_in_have else [] have_v6 = obj_in_have.pop("ipv6", []) if obj_in_have else [] # Process lists of dicts separately v4_cmds = self._v4_cmds( want.pop("ipv4", []), have_v4, state="replaced" ) v6_cmds = self._v6_cmds( want.pop("ipv6", []), have_v6, state="replaced" ) # Process remaining attrs if obj_in_have: # Find 'want' changes first diff = self.diff_of_dicts(want, obj_in_have) rmv = {"name": name} haves_not_in_want = ( set(obj_in_have.keys()) - set(want.keys()) - set(diff.keys()) ) for i in haves_not_in_want: rmv[i] = obj_in_have[i] cmds.extend(self.generate_delete_commands(rmv)) else: diff = want cmds.extend(self.add_commands(diff, name=name)) cmds.extend(v4_cmds) cmds.extend(v6_cmds) self.cmd_order_fixup(cmds, name) return cmds