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 = [] for want_acl in want['acls']: have_acl = search_obj_in_list(want_acl['name'], have['acls']) or {} acl_updates = [] for have_ace in have_acl.get('aces', []): want_ace = search_obj_in_list(have_ace['sequence'], want_acl['aces'], key='sequence') or {} if not want_ace: acl_updates.append('no {0}'.format(have_ace['sequence'])) for want_ace in want_acl.get('aces', []): have_ace = search_obj_in_list(want_ace.get('sequence'), have_acl.get('aces', []), key='sequence') or {} set_cmd = self._set_commands(want_ace, have_ace) if set_cmd: acl_updates.append(set_cmd) if acl_updates: acl_updates.insert(0, '{0} access-list {1}'.format(want['afi'], want_acl['name'])) commands.extend(acl_updates) return commands
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 = [] if not have: have = {} for want_acl in want['acls']: have_acl = search_obj_in_list(want_acl['name'], have.get('acls', {})) or {} 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 {} set_cmd = self._set_commands(want_ace, have_ace) if set_cmd: acl_updates.append(set_cmd) if acl_updates: acl_updates.insert(0, '{0} access-list {1}'.format(want['afi'], want_acl['name'])) commands.extend(acl_updates) 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 = [] # Remove extraneous AFI that are present in config but not # specified in `want` for have_afi in have: want_afi = search_obj_in_list(have_afi['afi'], want, key='afi') or {} if not want_afi: for acl in have_afi.get('acls', []): commands.append('no {0} access-list {1}'.format(have_afi['afi'], acl['name'])) # First we remove the extraneous ACLs from the AFIs that # are present both in `want` and in `have` and then # we call `_state_replaced` to update the ACEs within those ACLs for want_afi in want: want_afi = remove_empties(want_afi) have_afi = search_obj_in_list(want_afi['afi'], have, key='afi') or {} if have_afi: for have_acl in have_afi.get('acls', []): want_acl = search_obj_in_list(have_acl['name'], want_afi.get('acls', [])) or {} if not want_acl: commands.append('no {0} access-list {1}'.format(have_afi['afi'], have_acl['name'])) commands.extend(self._state_replaced(want_afi, have_afi)) return commands
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 == 'overridden': commands.extend( self._state_overridden( want, have ) ) elif state == 'deleted': if not want: for intf in have: commands.extend( self._state_deleted( {'name': intf['name']}, intf ) ) else: for item in want: obj_in_have = search_obj_in_list(item['name'], have) commands.extend( self._state_deleted( item, obj_in_have ) ) else: for item in want: name = item['name'] obj_in_have = search_obj_in_list(name, have) if state == 'merged': commands.extend( self._state_merged( item, obj_in_have ) ) elif state == 'replaced': commands.extend( self._state_replaced( item, obj_in_have ) ) return commands
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 """ commands = [] state = self._module.params["state"] if state in ("overridden", "merged", "replaced") 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(Lacp_interfaces._state_overridden(want, have)) elif state == "deleted": if not want: for intf in have: commands.extend( Lacp_interfaces._state_deleted( {"name": intf["name"]}, intf ) ) else: for item in want: obj_in_have = search_obj_in_list(item["name"], have) commands.extend( Lacp_interfaces._state_deleted(item, obj_in_have) ) else: for item in want: name = item["name"] obj_in_have = search_obj_in_list(name, have) if state == "merged": commands.extend( Lacp_interfaces._state_merged(item, obj_in_have) ) elif state == "replaced": commands.extend( Lacp_interfaces._state_replaced(item, obj_in_have) ) 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 = [] if have: for h_ar in have: w_ar = search_obj_in_list(h_ar['name'], want) if not w_ar and 'access_rules' in h_ar: commands.append( self._compute_command(name=h_ar['name'], opr=False)) else: h_rules = h_ar.get('access_rules') or [] key = 'direction' if w_ar: w_rules = w_ar.get('access_rules') or [] if not w_rules and h_rules: commands.append( self._compute_command(name=h_ar['name'], opr=False)) if h_rules: for h_rule in h_rules: w_rule = search_obj_in_list(h_rule['afi'], w_rules, key='afi') have_rules = h_rule.get('rules') or [] if w_rule: want_rules = w_rule.get('rules') or [] for h in have_rules: if key in h: w = search_obj_in_list(h[key], want_rules, key=key) if not w or key not in w or ( 'name' in h and w and 'name' not in w): commands.append( self._compute_command( afi=h_rule['afi'], name=h_ar['name'], attrib=h[key], opr=False)) commands.extend(self._state_merged(want, have)) return commands
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 == "overridden": commands.extend(self._state_overridden(want, have)) elif state == "deleted": commands.extend(self._state_deleted(want, 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) if state == "merged": commands.extend(self._state_merged(item, obj_in_have)) elif state == "replaced": commands.extend(self._state_replaced(item, obj_in_have)) 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 = [] want = remove_empties(want) delete_commands = [] for have_afi in have.get('access_groups', []): want_afi = search_obj_in_list(have_afi['afi'], want.get('access_groups', []), key='afi') or {} afi = have_afi.get('afi') for acl in have_afi.get('acls', []): if acl not in want_afi.get('acls', []): delete_commands.extend( self._compute_commands(afi, [acl], remove=True)) if delete_commands: pad_commands(delete_commands, want['name']) commands.extend(delete_commands) merged_commands = self._state_merged(want, have) if merged_commands and delete_commands: del merged_commands[0] commands.extend(merged_commands) return commands
def _delete_access_rules(self, want, have, opr=False): """ This function forms the delete commands based on the 'opr' type for 'access_rules' attributes. :param want: desired config. :param have: target config. :param opr: True/False. :return: generated commands list. """ commands = [] h_rules = {} w_rs = deepcopy(remove_empties(want)) w_rules = w_rs.get('access_rules') or [] if have: h_rs = deepcopy(remove_empties(have)) h_rules = h_rs.get('access_rules') or [] # if all firewall config needed to be deleted for specific interface # when operation is delete. if not w_rules and h_rules: commands.append(self._compute_command(name=want['name'], opr=opr)) if w_rules: for w in w_rules: h = search_obj_in_list(w['afi'], h_rules, key='afi') commands.extend(self._delete_rules(want['name'], w, h)) return commands
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 _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 """ commandset = [] for w in want: commands = [] intf_command = ["interface " + w['name']] obj_in_have = search_obj_in_list(w['name'], have, 'name') if 'access_groups' not in w.keys() or not w['access_groups']: commands = remove_commands(obj_in_have, w['name']) if w['access_groups']: for w_grp in w['access_groups']: if 'acls' not in w_grp.keys() or not w_grp['acls']: obj = self.get_acls_from_afi(w['name'], w_grp['afi'], have) to_delete = { 'access_groups': [{ 'acls': obj, 'afi': w_grp['afi'] }] } commands = remove_commands(to_delete, w['name']) else: if 'access_groups' not in obj_in_have.keys( ) or not obj_in_have['access_groups']: continue group = {'access_groups': [w_grp]} obj = self.get_acl_diff(group, obj_in_have, True) if obj[0]: to_delete = { 'access_groups': [{ 'acls': obj[0], 'afi': 'ipv4' }] } commands.append( remove_commands(to_delete, w['name'])) if obj[1]: to_delete = { 'access_groups': [{ 'acls': obj[1], 'afi': 'ipv6' }] } commands.append( remove_commands(to_delete, w['name'])) if commands: commands = list(itertools.chain(*commands)) if commands: commandset.append(intf_command) commandset.append(commands) if commandset: commandset = list(itertools.chain(*commandset)) return commandset
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 _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 """ commandset = [] want_interface = [] for w in want: commands = [] diff_access_group = [] want_interface.append(w['name']) obj_in_have = search_obj_in_list(w['name'], have, 'name') if not obj_in_have or 'access_groups' not in obj_in_have.keys(): commands.append(add_commands(w['access_groups'], w['name'])) else: if 'access_groups' in obj_in_have.keys(): obj = self.get_acl_diff(obj_in_have, w) if obj[0]: to_delete = { 'access_groups': [{ 'acls': obj[0], 'afi': 'ipv4' }] } commands.append(remove_commands(to_delete, w['name'])) if obj[1]: to_delete = { 'access_groups': [{ 'acls': obj[1], 'afi': 'ipv6' }] } commands.append(remove_commands(to_delete, w['name'])) diff = self.get_acl_diff(w, obj_in_have) if diff[0]: diff_access_group.append({ 'afi': 'ipv4', 'acls': diff[0] }) if diff[1]: diff_access_group.append({ 'afi': 'ipv6', 'acls': diff[1] }) if diff_access_group: commands.append( add_commands(diff_access_group, w['name'])) if commands: intf_command = ["interface " + w['name']] commands = list(itertools.chain(*commands)) commandset.append(intf_command) commandset.append(commands) if commandset: commandset = list(itertools.chain(*commandset)) return commandset
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 have_intf in have: intf_in_want = search_obj_in_list(have_intf["name"], want) if not intf_in_want: commands.extend(self._purge_attribs(have_intf)) for intf in want: intf_in_have = search_obj_in_list(intf["name"], have) commands.extend(self._state_replaced(intf, intf_in_have)) 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 have_intf in have: want_intf = search_obj_in_list(have_intf['name'], want) or {} if not want_intf: commands.extend(self._state_deleted(want_intf, have_intf)) for want_intf in want: have_intf = search_obj_in_list(want_intf['name'], have) or {} commands.extend(self._state_replaced(want_intf, have_intf)) 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 _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 = [] for w in want: h = search_obj_in_list(w['name'], have) commands.extend(self._render_access_rules(w, h)) return commands
def _state_overridden(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 intf in have: intf_in_want = search_obj_in_list(intf['name'], want) if not intf_in_want: commands.extend( Lacp_interfaces._state_deleted({'name': intf['name']}, intf)) for intf in want: intf_in_have = search_obj_in_list(intf['name'], have) commands.extend(Lacp_interfaces._state_replaced( intf, intf_in_have)) 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 = [] if have: for h in have: w = search_obj_in_list(h['name'], want) commands.extend(self._render_access_rules(h, w, opr=False)) commands.extend(self._state_merged(want, have)) 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_commands(h)) for w in want: commands.extend(self.set_commands(w, have)) 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 = [] # This handles deletion for both empty/no config # and just interface name provided. if 'access_groups' not in want: for x in have.get('access_groups', []): afi = x.get('afi') for have_acl in x.get('acls', []): commands.extend( self._compute_commands(afi, [have_acl], remove=True)) else: for want_afi in want['access_groups']: have_afi = search_obj_in_list(want_afi['afi'], have.get('access_groups', []), key='afi') or {} afi = have_afi.get('afi') # If only the AFI has be specified, we # delete all the access-groups for that AFI if 'acls' not in want_afi: for have_acl in have_afi.get('acls', []): commands.extend( self._compute_commands(afi, [have_acl], remove=True)) # If one or more acl has been explicitly specified, we # delete that and leave the rest untouched else: for acl in want_afi['acls']: if acl in have_afi.get('acls', []): commands.extend( self._compute_commands(afi, [acl], remove=True)) if commands: pad_commands(commands, have['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_commands(obj_in_have)) else: if not have: return commands for h in have: commands.extend(self.del_all_commands(h)) return commands
def diff_list_of_dicts(self, want, have): if not want: want = [] if not have: have = [] diff = [] for w_item in want: h_item = search_obj_in_list(w_item['member'], have, key='member') or {} delta = dict_diff(h_item, w_item) if delta: if 'member' not in delta.keys(): delta['member'] = w_item['member'] diff.append(delta) return diff
def _find_vrf(self, item, entries): """ This method iterates through the items in `entries` and returns the object that matches `item`. :rtype: A dict :returns: the obj in `entries` that matches `item` """ obj = {} afi = item.get("vrf") if afi: obj = search_obj_in_list(afi, entries, key="vrf") or {} else: for x in entries: if "vrf" not in remove_empties(x): obj = x break return obj
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: h = search_obj_in_list(w['name'], have) if h and 'access_rules' in h: commands.extend(self._delete_access_rules(w, h, opr=False)) elif have: for h in have: if 'access_rules' in h: commands.append( self._compute_command(name=h['name'], opr=False)) return commands
def diff_list_of_dicts(w, h, key='member'): """ Returns a list containing diff between two list of dictionaries """ if not w: w = [] if not h: h = [] diff = [] for w_item in w: h_item = search_obj_in_list(w_item[key], h, key=key) or {} d = dict_diff(h_item, w_item) if d: if key not in d.keys(): d[key] = w_item[key] diff.append(d) return diff
def _render_rules(self, name, want, have, opr=True): """ This function forms the set/delete commands based on the 'opr' type for rules attributes. :param name: interface id/name. :param want: desired config. :param have: target config. :param opr: True/False. :return: generated commands list. """ commands = [] h_rules = [] key = 'direction' w_rules = want.get('rules') or [] if have: h_rules = have.get('rules') or [] for w in w_rules: h = search_obj_in_list(w[key], h_rules, key=key) if key in w: if opr: if 'name' in w and not (h and h[key] == w[key] and h['name'] == w['name']): commands.append( self._compute_command(afi=want['afi'], name=name, attrib=w[key], value=w['name'])) elif not (h and key in h): commands.append( self._compute_command(afi=want['afi'], name=name, attrib=w[key])) elif not opr: if not h or key not in h or ('name' in w and h and 'name' not in h): commands.append( self._compute_command(afi=want['afi'], name=name, attrib=w[key], opr=opr)) return commands
def _render_access_rules(self, want, have, opr=True): """ This function forms the set/delete commands based on the 'opr' type for 'access_rules' attributes. :param want: desired config. :param have: target config. :param opr: True/False. :return: generated commands list. """ commands = [] h_rules = {} w_rs = deepcopy(remove_empties(want)) w_rules = w_rs.get('access_rules') or [] if have: h_rs = deepcopy(remove_empties(have)) h_rules = h_rs.get('access_rules') or [] if w_rules: for w in w_rules: h = search_obj_in_list(w['afi'], h_rules, key='afi') commands.extend(self._render_rules(want['name'], w, h, opr)) 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: for item in have: commands.extend(self._purge_attribs(intf=item)) else: for item in want: name = item["name"] obj_in_have = search_obj_in_list(name, have) if not obj_in_have: self._module.fail_json( msg=("interface {0} does not exist".format(name))) commands.extend(self._purge_attribs(intf=obj_in_have)) return commands