def set_commands(self, want, have): commands = [] h1 = h2 = h3 = {} want = remove_empties(want) vrf_list = [] if have: vrf_list = [h['vrf'] for h in have] if want['vrf'] in vrf_list and have != [{'vrf': '__global__'}]: for x in have: if x['vrf'] == want['vrf']: h1 = x # this has the 'have' dict with same vrf as want if 'address_families' in h1.keys(): afi_list = [h['afi'] for h in h1['address_families']] for af in want['address_families']: if af['afi'] in afi_list: for x in h1['address_families']: if x['afi'] == af['afi']: h2 = x # this has the have dict with same vrf and afi as want dest_list = [h['dest'] for h in h2['routes']] for ro in af['routes']: # q(dest_list) if ro['dest'] in dest_list: for x in h2['routes']: if x['dest'] == ro['dest']: h3 = x # this has the have dict with same vrf, afi and dest as want next_hop_list = [h for h in h3['next_hops']] for nh in ro['next_hops']: if 'interface' in nh.keys(): nh['interface'] = normalize_interface( nh['interface']) if nh not in next_hop_list: # no match for next hop in have commands = self.set_next_hop( want, h2, nh, ro, commands) vrf_list.append(want['vrf']) else: # no match for dest for nh in ro['next_hops']: commands = self.set_next_hop( want, h2, nh, ro, commands) else: # no match for afi for ro in af['routes']: for nh in ro['next_hops']: commands = self.set_next_hop( want, af, nh, ro, commands) else: # no match for vrf vrf_list.append(want['vrf']) for af in want['address_families']: for ro in af['routes']: for nh in ro['next_hops']: commands = self.set_next_hop(want, af, nh, ro, commands) return commands
def execute_module(self): """ Execute the module :rtype: A dictionary :returns: The result from module execution """ result = {'changed': False} commands = list() warnings = list() state = self._module.params['state'] if 'overridden' in state: self._module.fail_json( msg='State <overridden> is invalid for this module.') if 'replaced' in state: self._module.fail_json(msg='State: <replaced> not yet supported') # When state is 'deleted', the module_params should not contain data # under the 'config' key if 'deleted' in state and self._module.params.get('config'): self._module.fail_json( msg='Remove config key from playbook when state is <deleted>') if self._module.params['config'] is None: self._module.params['config'] = {} # Normalize interface name. int = self._module.params['config'].get('source_interface') if int: self._module.params['config'][ 'source_interface'] = normalize_interface(int) existing_telemetry_facts = self.get_telemetry_facts() commands.extend(self.set_config(existing_telemetry_facts)) if commands: if not self._module.check_mode: self.edit_config(commands) # TODO: edit_config is only available for network_cli. Once we # add support for httpapi, we will need to switch to load_config # or add support to httpapi for edit_config # # self._connection.load_config(commands) result['changed'] = True result['commands'] = commands changed_telemetry_facts = self.get_telemetry_facts() result['before'] = existing_telemetry_facts if result['changed']: result['after'] = changed_telemetry_facts result['warnings'] = warnings return result
def populate_structured_neighbors_lldp(self, data): objects = dict() data = data['TABLE_nbor']['ROW_nbor'] if isinstance(data, dict): data = [data] for item in data: local_intf = normalize_interface(item['l_port_id']) objects[local_intf] = list() nbor = dict() nbor['port'] = item['port_id'] nbor['host'] = nbor['sysname'] = item['chassis_id'] objects[local_intf].append(nbor) return objects
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 = existing_interfaces_facts resp = self.set_state(want, have) return to_list(resp)
def set_config(self, existing_lag_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 """ want = self._module.params.get('config') if want: for w in want: w.update(remove_empties(w)) if 'members' in w and w['members']: for item in w['members']: item.update({'member': normalize_interface(item['member'])}) have = existing_lag_interfaces_facts resp = self.set_state(want, have) return to_list(resp)
def get_members(self, id, connection): """ Returns members associated with a channel-group :param name: The channel group :rtype: list :returns: Members """ members = [] data = connection.get('show port-channel summary') match = re.search(r'{0} (.+)(|\n)'.format(id), data) if match: interfaces = re.search(r'Eth\d(.+)$', match.group()) if interfaces: for i in interfaces.group().split(): if get_interface_type(i[:-3]) != 'unknown': members.append(normalize_interface(i[:-3])) return members
def set_config(self, existing_lacp_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: if get_interface_type(w['name']) not in ('portchannel', 'ethernet'): self._module.fail_json(msg='This module works with either portchannel or ethernet') w.update({'name': normalize_interface(w['name'])}) want.append(remove_empties(w)) have = existing_lacp_interfaces_facts resp = self.set_state(want, have) return to_list(resp)
def add_commands(self, want): command = '' params = want.keys() pref = vrf = ip = intf = name = tag = track = '' if 'admin_distance' in params: pref = str(want['admin_distance']) + ' ' if 'track' in params: track = 'track ' + str(want['track']) + ' ' if 'dest_vrf' in params: vrf = 'vrf ' + str(want['dest_vrf']) + ' ' if 'forward_router_address' in params: ip = want['forward_router_address'] + ' ' if 'interface' in params: intf = normalize_interface(want['interface']) + ' ' if 'route_name' in params: name = 'name ' + str(want['route_name']) + ' ' if 'tag' in params: tag = 'tag ' + str(want['tag']) + ' ' command = intf + ip + vrf + name + tag + track + pref return command
def set_config(self, existing_l3_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'])}) if get_interface_type(w['name']) == 'management': self._module.fail_json(msg="The 'management' interface is not allowed to be managed by this module") want.append(remove_empties(w)) have = deepcopy(existing_l3_interfaces_facts) self.init_check_existing(have) resp = self.set_state(want, have) return to_list(resp)
def populate_neighbors(self, data): objects = dict() # if there are no neighbors the show command returns # ERROR: No neighbour information if data.startswith('ERROR'): return dict() regex = re.compile(r'(\S+)\s+(\S+)\s+\d+\s+\w+\s+(\S+)') for item in data.split('\n')[4:-1]: match = regex.match(item) if match: nbor = dict() nbor['host'] = nbor['sysname'] = match.group(1) nbor['port'] = match.group(3) local_intf = normalize_interface(match.group(2)) if local_intf not in objects: objects[local_intf] = [] objects[local_intf].append(nbor) return objects
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) name = conf[0].strip() config['name'] = normalize_interface(name) config['access_groups'] = [] v4 = {'afi': 'ipv4', 'acls': []} v6 = {'afi': 'ipv6', 'acls': []} for c in conf[1:]: if c: acl4 = re.search(r'ip( port)? access-group (\w*) (\w*)', c) acl6 = re.search(r'ipv6( port)? traffic-filter (\w*) (\w*)', c) if acl4: acl = { 'name': acl4.group(2).strip(), 'direction': acl4.group(3).strip() } if acl4.group(1): acl.update({'port': True}) v4['acls'].append(acl) elif acl6: acl = {'name': acl6.group(2), 'direction': acl6.group(3)} if acl6.group(1): acl.update({'port': True}) v6['acls'].append(acl) if len(v4['acls']) > 0: config['access_groups'].append(v4) if len(v6['acls']) > 0: config['access_groups'].append(v6) return utils.remove_empties(config)
def set_config(self, existing_interfaces_facts, default_intf_list): """ 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) for i in want: # 'have' does not include objects from the default_interfaces list. # Add any 'want' names from default_interfaces to the 'have' list. if i['name'] in default_intf_list: have.append({'name': i['name']}) resp = self.set_state(want, have) return to_list(resp)