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 vlan_id, extant in have.items(): if vlan_id in want: desired = want[vlan_id] else: desired = dict() add_config = dict_diff(extant, desired) del_config = dict_diff(desired, extant) commands.extend(generate_commands(vlan_id, add_config, del_config)) # Handle vlans not already in config new_vlans = [vlan_id for vlan_id in want if vlan_id not in have] for vlan_id in new_vlans: desired = want[vlan_id] extant = dict(vlan_id=vlan_id) add_config = dict_diff(extant, desired) commands.extend(generate_commands(vlan_id, add_config, {})) return commands
def get_diff(self, comparable, base): diff = {} if not base: diff = comparable else: diff = dict_diff(base, comparable) return diff
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 _render_updates(self, want, have): commands = [] if have: temp_have_legacy_protos = have.pop('legacy_protocols', None) else: have = {} temp_want_legacy_protos = want.pop('legacy_protocols', None) updates = dict_diff(have, want) if have and temp_have_legacy_protos: have['legacy_protocols'] = temp_have_legacy_protos if not have and temp_want_legacy_protos: want['legacy_protocols'] = temp_want_legacy_protos commands.extend(self._add_lldp_protocols(want, have)) if updates: for key, value in iteritems(updates): if value: if key == 'enable': commands.append(self._compute_command()) elif key == 'address': commands.append( self._compute_command('management-address', str(value))) elif key == 'snmp': if value == 'disable': commands.append( self._compute_command(key, remove=True)) else: commands.append( self._compute_command(key, str(value))) 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 = 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) if 'name' not in diff: diff['name'] = w['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) 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 _render_updates(self, want, have): commands = [] temp_have_members = have.pop('members', None) temp_want_members = want.pop('members', None) updates = dict_diff(have, want) if temp_have_members: have['members'] = temp_have_members if temp_want_members: want['members'] = temp_want_members commands.extend(self._add_bond_members(want, have)) if updates: for key, value in iteritems(updates): if value: if key == 'arp_monitor': commands.extend( self._add_arp_monitor(updates, key, want, have) ) else: commands.append(self._compute_command(have['name'], key, str(value))) return commands
def _add_location(self, name, want_item, have_item): commands = [] have_dict = {} have_ca = {} set_cmd = name + ' location ' want_location_type = want_item.get('location') or {} have_location_type = have_item.get('location') or {} if want_location_type['coordinate_based']: want_dict = want_location_type.get('coordinate_based') or {} if is_dict_element_present(have_location_type, 'coordinate_based'): have_dict = have_location_type.get('coordinate_based') or {} location_type = 'coordinate-based' updates = dict_diff(have_dict, want_dict) for key, value in iteritems(updates): if value: commands.append( self._compute_command(set_cmd + location_type, key, str(value)) ) elif want_location_type['civic_based']: location_type = 'civic-based' want_dict = want_location_type.get('civic_based') or {} want_ca = want_dict.get('ca_info') or [] if is_dict_element_present(have_location_type, 'civic_based'): have_dict = have_location_type.get('civic_based') or {} have_ca = have_dict.get('ca_info') or [] if want_dict['country_code'] != have_dict['country_code']: commands.append( self._compute_command( set_cmd + location_type, 'country-code', str(want_dict['country_code']) ) ) else: commands.append( self._compute_command( set_cmd + location_type, 'country-code', str(want_dict['country_code']) ) ) commands.extend(self._add_civic_address(name, want_ca, have_ca)) elif want_location_type['elin']: location_type = 'elin' if is_dict_element_present(have_location_type, 'elin'): if want_location_type.get('elin') != have_location_type.get('elin'): commands.append( self._compute_command( set_cmd + location_type, value=str(want_location_type['elin']) ) ) else: commands.append( self._compute_command( set_cmd + location_type, value=str(want_location_type['elin']) ) ) return commands
def test_dict_diff(): base = dict(obj2=dict(), b1=True, b2=False, b3=False, one=1, two=2, three=3, obj1=dict(key1=1, key2=2), l1=[1, 3], l2=[1, 2, 3], l4=[4], nested=dict(n1=dict(n2=2))) other = dict(b1=True, b2=False, b3=True, b4=True, one=1, three=4, four=4, obj1=dict(key1=2), l1=[2, 1], l2=[3, 2, 1], l3=[1], nested=dict(n1=dict(n2=2, n3=3))) result = dict_diff(base, other) # string assertions assert 'one' not in result assert 'two' not in result assert result['three'] == 4 assert result['four'] == 4 # dict assertions assert 'obj1' in result assert 'key1' in result['obj1'] assert 'key2' not in result['obj1'] # list assertions assert result['l1'] == [2, 1] assert 'l2' not in result assert result['l3'] == [1] assert 'l4' not in result # nested assertions assert 'obj1' in result assert result['obj1']['key1'] == 2 assert 'key2' not in result['obj1'] # bool assertions assert 'b1' not in result assert 'b2' not in result assert result['b3'] assert result['b4']
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 = [] diff = dict_diff(have, want) commands.extend(self.set_commands(diff)) return commands
def set_config(want, have): commands = [] to_set = dict_diff(have, want) for member in to_set.get("members", []): channel_id = want["name"][12:] commands.extend([ "interface {0}".format(member["member"]), "channel-group {0} mode {1}".format(channel_id, member["mode"]), ]) 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 key, extant in have.items(): if key in want: desired = want[key] else: desired = dict() add_config = dict_diff(extant, desired) del_config = dict_diff(desired, extant) commands.extend(generate_commands(key, add_config, del_config)) return commands
def _state_replaced(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 vlan_id, desired in want.items(): if vlan_id in have: extant = have[vlan_id] else: extant = dict() add_config = dict_diff(extant, desired) del_config = dict_diff(desired, extant) commands.extend(generate_commands(vlan_id, add_config, del_config)) return commands
def _state_replaced(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 key, desired in want.items(): interface_name = normalize_interface(key) if interface_name in have: extant = have[interface_name] else: extant = dict() add_config = dict_diff(extant, desired) del_config = dict_diff(desired, extant) commands.extend(generate_commands(key, add_config, del_config)) return commands
def remove_config(want, have): commands = [] if not want.get("members"): return ["no interface {0}".format(want["name"])] to_remove = dict_diff(want, have) for member in to_remove.get("members", []): commands.extend([ "interface {0}".format(member["member"]), "no channel-group", ]) return commands
def _state_replaced(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 = [] to_set = dict_diff(have, want) if 'system' in to_set: system = to_set['system'] if 'priority' in system: commands.append('lacp system-priority {0}'.format( system['priority'])) to_del = dict_diff(want, have) if 'system' in to_del: system = to_del['system'] system_set = to_set.get('system', {}) if 'priority' in system and 'priority' not in system_set: commands.append('no lacp system-priority') 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 = [] updates = dict_diff(have, want) if updates: for key, value in iteritems(flatten_dict(remove_empties(updates))): commands.append(self._compute_commands(key, value)) 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 = [] to_del = dict_diff(want, have) if 'system' in to_del: system = to_del['system'] if 'priority' in system: commands.append('no lacp system-priority') return commands
def _state_merged(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 = [] to_set = dict_diff(have, want) if 'system' in to_set: system = to_set['system'] if 'priority' in system: commands.append('lacp system-priority {0}'.format( system['priority'])) 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 = [] merge_dict = dict_diff(have, want) # merge_dict will contain new and unique values in want delete_dict = self.find_delete_params(have, want) self._module.params['state'] = 'deleted' commands.extend(self._state_deleted(delete_dict)) # delete self._module.params['state'] = 'merged' commands.extend(self.set_commands(merge_dict)) # merge self._module.params['state'] = 'replaced' return commands
def _state_merged(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 = [] updates = dict_diff(have, want) if updates: for key, value in iteritems( flatten_dict(remove_empties(updates['system']))): commands.append('lacp system {0} {1}'.format( key.replace('address', 'mac'), value)) 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 = {'name': want['name']} for key, value in iteritems( flatten_dict(remove_empties(dict_diff(have, want)))): commands.append(self._compute_commands(key, value)) if commands: pad_commands(commands, want['name']) return commands
def _state_merged(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 vlan_id, desired in want.items(): if vlan_id in have: extant = have[vlan_id] else: extant = dict() add_config = dict_diff(extant, desired) commands.extend(generate_commands(vlan_id, add_config, {})) return commands
def state_merged(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 = [] to_set = dict_diff(have, want) tlv_options = to_set.pop("tlv_select", {}) for key, value in to_set.items(): commands.append("lldp {0} {1}".format(key, value)) for key, value in tlv_options.items(): device_option = key.replace("_", "-") if value is True: commands.append("lldp tlv-select {0}".format(device_option)) elif value is False: commands.append("no lldp tlv-select {0}".format(device_option)) 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 = [] to_remove = dict_diff(want, have) tlv_options = to_remove.pop("tlv_select", {}) for key in to_remove: commands.append("no lldp {0}".format(key)) for key, value in tlv_options.items(): device_option = key.replace("_", "-") if value is False: commands.append("lldp tlv-select {0}".format(device_option)) elif value is True: commands.append("no lldp tlv-select {0}".format(device_option)) return commands
def _state_merged(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 key, desired in want.items(): interface_name = normalize_interface(key) if interface_name in have: extant = have[interface_name] else: extant = dict(name=interface_name) add_config = dict_diff(extant, desired) commands.extend(generate_commands(interface_name, add_config, {})) 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 in want: desired = dict() if key in have: extant = have[key] else: continue del_config = dict_diff(desired, extant) commands.extend(generate_commands(key, {}, del_config)) return commands
def diff_list_of_dicts(w, h): """ 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['member'], h, key='member') or {} d = dict_diff(h_item, w_item) if d: if 'member' not in d.keys(): d['member'] = w_item['member'] diff.append(d) return diff
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 in want.keys(): interface_name = normalize_interface(key) desired = dict(name=interface_name) if interface_name in have: extant = have[interface_name] else: continue del_config = dict_diff(desired, extant) commands.extend(generate_commands(interface_name, {}, del_config)) 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 = [] diff = dict_diff(want, have) wkeys = want.keys() dkeys = diff.keys() for k in wkeys: if k in self.exclude_params and k in dkeys: del diff[k] deleted_commands = self.del_all(diff) merged_commands = self._state_merged(want, have) commands.extend(deleted_commands) if merged_commands: commands.extend(merged_commands) return commands
def _render_bundle_updates(self, want, have): """ The command generator for updates to bundles :rtype: A list :returns: the commands necessary to update bundles """ commands = [] if not have: have = {'name': want['name']} want_copy = deepcopy(want) have_copy = deepcopy(have) want_copy.pop('members', []) have_copy.pop('members', []) bundle_updates = dict_diff(have_copy, want_copy) if bundle_updates: for key, value in iteritems( flatten_dict(remove_empties(bundle_updates))): commands.append(self._compute_commands(key=key, value=value)) return commands