diff --git a/docs/docsite/rst/porting_guides/porting_guide_2.9.rst b/docs/docsite/rst/porting_guides/porting_guide_2.9.rst index 9da98eb7f98..45cecda9411 100644 --- a/docs/docsite/rst/porting_guides/porting_guide_2.9.rst +++ b/docs/docsite/rst/porting_guides/porting_guide_2.9.rst @@ -98,6 +98,8 @@ The following modules will be removed in Ansible 2.13. Please update update your * vyos_lldp use :ref:`vyos_lldp_global ` instead. +* vyos_lldp_interface use :ref:`vyos_lldp_interfaces ` instead. + The following functionality will be removed in Ansible 2.12. Please update update your playbooks accordingly. * ``vmware_cluster`` DRS, HA and VSAN configuration; use :ref:`vmware_cluster_drs `, :ref:`vmware_cluster_ha ` and :ref:`vmware_cluster_vsan ` instead. diff --git a/lib/ansible/module_utils/network/vyos/argspec/facts/facts.py b/lib/ansible/module_utils/network/vyos/argspec/facts/facts.py index a9be8c40db5..231107a644f 100644 --- a/lib/ansible/module_utils/network/vyos/argspec/facts/facts.py +++ b/lib/ansible/module_utils/network/vyos/argspec/facts/facts.py @@ -24,7 +24,9 @@ class FactsArgs(object): # pylint: disable=R0903 'lag_interfaces', '!lag_interfaces', 'lldp_global', - '!lldp_global' + '!lldp_global', + 'lldp_interfaces', + '!lldp_interfaces' ] argument_spec = { diff --git a/lib/ansible/module_utils/network/vyos/argspec/lldp_interfaces/__init__.py b/lib/ansible/module_utils/network/vyos/argspec/lldp_interfaces/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ansible/module_utils/network/vyos/argspec/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/vyos/argspec/lldp_interfaces/lldp_interfaces.py new file mode 100644 index 00000000000..29558a6c3e3 --- /dev/null +++ b/lib/ansible/module_utils/network/vyos/argspec/lldp_interfaces/lldp_interfaces.py @@ -0,0 +1,107 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# +""" +The arg spec for the vyos_lldp_interfaces module +""" + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +class Lldp_interfacesArgs(object): # pylint: disable=R0903 + """The arg spec for the vyos_lldp_interfaces module + """ + def __init__(self, **kwargs): + pass + + argument_spec = { + 'config': { + 'elements': 'dict', + 'options': { + 'enable': { + 'default': True, + 'type': 'bool' + }, + 'location': { + 'options': { + 'civic_based': { + 'options': { + 'ca_info': { + 'elements': 'dict', + 'options': { + 'ca_type': { + 'type': 'int' + }, + 'ca_value': { + 'type': 'str' + } + }, + 'type': 'list' + }, + 'country_code': { + 'required': True, + 'type': 'str' + } + }, + 'type': 'dict' + }, + 'coordinate_based': { + 'options': { + 'altitude': { + 'type': 'int' + }, + 'datum': { + 'choices': ['WGS84', 'NAD83', 'MLLW'], + 'type': 'str' + }, + 'latitude': { + 'required': True, + 'type': 'str' + }, + 'longitude': { + 'required': True, + 'type': 'str' + } + }, + 'type': 'dict' + }, + 'elin': { + 'type': 'str' + } + }, + 'type': 'dict' + }, + 'name': { + 'required': True, + 'type': 'str' + } + }, + 'type': 'list' + }, + 'state': { + 'choices': ['merged', 'replaced', 'overridden', 'deleted'], + 'default': 'merged', + 'type': 'str' + } + } # pylint: disable=C0301 diff --git a/lib/ansible/module_utils/network/vyos/config/lldp_interfaces/__init__.py b/lib/ansible/module_utils/network/vyos/config/lldp_interfaces/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ansible/module_utils/network/vyos/config/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/vyos/config/lldp_interfaces/lldp_interfaces.py new file mode 100644 index 00000000000..6f5e70279be --- /dev/null +++ b/lib/ansible/module_utils/network/vyos/config/lldp_interfaces/lldp_interfaces.py @@ -0,0 +1,394 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The vyos_lldp_interfaces class +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to it's desired end-state is +created +""" + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +from ansible.module_utils.network.common.cfg.base import ConfigBase +from ansible.module_utils.network.vyos.facts.facts import Facts +from ansible.module_utils.network.common.utils import to_list, dict_diff +from ansible.module_utils.six import iteritems +from ansible.module_utils.network. vyos.utils.utils import search_obj_in_list, \ + search_dict_tv_in_list, key_value_in_dict, is_dict_element_present + + +class Lldp_interfaces(ConfigBase): + """ + The vyos_lldp_interfaces class + """ + + gather_subset = [ + '!all', + '!min', + ] + + gather_network_resources = [ + 'lldp_interfaces', + ] + + params = ['enable', 'location', 'name'] + + def __init__(self, module): + super(Lldp_interfaces, self).__init__(module) + + def get_lldp_interfaces_facts(self): + """ Get the 'facts' (the current configuration) + + :rtype: A dictionary + :returns: The current configuration as a dictionary + """ + facts, _warnings = Facts(self._module).get_facts(self.gather_subset, + self.gather_network_resources) + lldp_interfaces_facts = facts['ansible_network_resources'].get('lldp_interfaces') + if not lldp_interfaces_facts: + return [] + return lldp_interfaces_facts + + def execute_module(self): + """ Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + result = {'changed': False} + commands = list() + warnings = list() + existing_lldp_interfaces_facts = self.get_lldp_interfaces_facts() + commands.extend(self.set_config(existing_lldp_interfaces_facts)) + if commands: + if self._module.check_mode: + resp = self._connection.edit_config(commands, commit=False) + else: + resp = self._connection.edit_config(commands) + result['changed'] = True + + result['commands'] = commands + + if self._module._diff: + result['diff'] = resp['diff'] if result['changed'] else None + + changed_lldp_interfaces_facts = self.get_lldp_interfaces_facts() + result['before'] = existing_lldp_interfaces_facts + if result['changed']: + result['after'] = changed_lldp_interfaces_facts + + result['warnings'] = warnings + return result + + def set_config(self, existing_lldp_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['config'] + have = existing_lldp_interfaces_facts + resp = self.set_state(want, have) + return to_list(resp) + + 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 == 'overridden': + commands.extend(self._state_overridden(want=want, have=have)) + elif state == 'deleted': + if want: + for item in want: + name = item['name'] + have_item = search_obj_in_list(name, have) + commands.extend(self._state_deleted(want=None, have=have_item)) + else: + for have_item in have: + commands.extend(self._state_deleted(want=None, have=have_item)) + else: + for want_item in want: + name = want_item['name'] + have_item = search_obj_in_list(name, have) + if state == 'merged': + commands.extend(self._state_merged(want=want_item, have=have_item)) + else: + commands.extend(self._state_replaced(want=want_item, have=have_item)) + 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: + commands.extend(self._state_deleted(want, have)) + 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 have_item in have: + lldp_name = have_item['name'] + lldp_in_want = search_obj_in_list(lldp_name, want) + if not lldp_in_want: + commands.append( + self._compute_command(have_item['name'], remove=True) + ) + + for want_item in want: + name = want_item['name'] + lldp_in_have = search_obj_in_list(name, have) + commands.extend(self._state_replaced(want_item, lldp_in_have)) + 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 have: + commands.extend(self._render_updates(want, have)) + else: + commands.extend(self._render_set_commands(want)) + 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: + params = Lldp_interfaces.params + for attrib in params: + if attrib == 'location': + commands.extend(self._update_location(have['name'], want, have)) + + elif have: + commands.append( + self._compute_command(have['name'], remove=True) + ) + return commands + + def _render_updates(self, want, have): + commands = [] + lldp_name = have['name'] + commands.extend(self._configure_status(lldp_name, want, have)) + commands.extend(self._add_location(lldp_name, want, have)) + + return commands + + def _render_set_commands(self, want): + commands = [] + have = {} + lldp_name = want['name'] + params = Lldp_interfaces.params + + commands.extend(self._add_location(lldp_name, want, have)) + for attrib in params: + value = want[attrib] + if value: + if attrib == 'location': + commands.extend(self._add_location(lldp_name, want, have)) + elif attrib == 'enable': + if not value: + commands.append( + self._compute_command(lldp_name, value='disable') + ) + else: + commands.append( + self._compute_command(lldp_name) + ) + + return commands + + def _configure_status(self, name, want_item, have_item): + commands = [] + if is_dict_element_present(have_item, 'enable'): + temp_have_item = False + else: + temp_have_item = True + if want_item['enable'] != temp_have_item: + if want_item['enable']: + commands.append( + self._compute_command(name, value='disable', remove=True) + ) + else: + commands.append( + self._compute_command(name, value='disable') + ) + 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 _update_location(self, name, want_item, have_item): + commands = [] + del_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' + for key, value in iteritems(have_dict): + only_in_have = key_value_in_dict(key, value, want_dict) + if not only_in_have: + commands.append( + self._compute_command(del_cmd + location_type, key, str(value), True) + ) + else: + commands.append( + self._compute_command(del_cmd, remove=True) + ) + + elif want_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') + commands.extend(self._update_civic_address(name, want_ca, have_ca)) + else: + commands.append( + self._compute_command(del_cmd, remove=True) + ) + + else: + 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(del_cmd, remove=True) + ) + else: + commands.append( + self._compute_command(del_cmd, remove=True) + ) + return commands + + def _add_civic_address(self, name, want, have): + commands = [] + for item in want: + ca_type = item['ca_type'] + ca_value = item['ca_value'] + obj_in_have = search_dict_tv_in_list(ca_type, ca_value, have, 'ca_type', 'ca_value') + if not obj_in_have: + commands.append( + self._compute_command( + key=name + ' location civic-based ca-type', + attrib=str(ca_type) + ' ca-value', value=ca_value) + ) + return commands + + def _update_civic_address(self, name, want, have): + commands = [] + for item in have: + ca_type = item['ca_type'] + ca_value = item['ca_value'] + in_want = search_dict_tv_in_list(ca_type, ca_value, want, 'ca_type', 'ca_value') + if not in_want: + commands.append( + self._compute_command( + name, 'location civic-based ca-type', str(ca_type), remove=True + ) + ) + return commands + + def _compute_command(self, key, attrib=None, value=None, remove=False): + if remove: + cmd = 'delete service lldp interface ' + else: + cmd = 'set service lldp interface ' + cmd += (key) + if attrib: + cmd += (' ' + attrib) + if value: + cmd += (" '" + value + "'") + return cmd diff --git a/lib/ansible/module_utils/network/vyos/facts/facts.py b/lib/ansible/module_utils/network/vyos/facts/facts.py index 85841a54233..6120eec9cf2 100644 --- a/lib/ansible/module_utils/network/vyos/facts/facts.py +++ b/lib/ansible/module_utils/network/vyos/facts/facts.py @@ -14,6 +14,7 @@ from ansible.module_utils.network.vyos.facts.interfaces.interfaces import Interf from ansible.module_utils.network.vyos.facts.l3_interfaces.l3_interfaces import L3_interfacesFacts from ansible.module_utils.network.vyos.facts.lag_interfaces.lag_interfaces import Lag_interfacesFacts from ansible.module_utils.network.vyos.facts.lldp_global.lldp_global import Lldp_globalFacts +from ansible.module_utils.network.vyos.facts.lldp_interfaces.lldp_interfaces import Lldp_interfacesFacts from ansible.module_utils.network.vyos.facts.legacy.base import Default, Neighbors, Config @@ -26,7 +27,8 @@ FACT_RESOURCE_SUBSETS = dict( interfaces=InterfacesFacts, l3_interfaces=L3_interfacesFacts, lag_interfaces=Lag_interfacesFacts, - lldp_global=Lldp_globalFacts + lldp_global=Lldp_globalFacts, + lldp_interfaces=Lldp_interfacesFacts ) @@ -42,7 +44,6 @@ class Facts(FactsBase): def get_facts(self, legacy_facts_type=None, resource_facts_type=None, data=None): """ Collect the facts for vyos - :param legacy_facts_type: List of legacy facts types :param resource_facts_type: List of resource fact types :param data: previously collected conf diff --git a/lib/ansible/module_utils/network/vyos/facts/lldp_interfaces/__init__.py b/lib/ansible/module_utils/network/vyos/facts/lldp_interfaces/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ansible/module_utils/network/vyos/facts/lldp_interfaces/lldp_interfaces.py b/lib/ansible/module_utils/network/vyos/facts/lldp_interfaces/lldp_interfaces.py new file mode 100644 index 00000000000..62043b3ab9e --- /dev/null +++ b/lib/ansible/module_utils/network/vyos/facts/lldp_interfaces/lldp_interfaces.py @@ -0,0 +1,147 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The vyos lldp_interfaces fact class +It is in this file the configuration is collected from the device +for a given resource, parsed, and the facts tree is populated +based on the configuration. +""" + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +from re import findall, search, M +from copy import deepcopy + +from ansible.module_utils.network.common import utils +from ansible.module_utils.network.vyos.argspec.lldp_interfaces. \ + lldp_interfaces import Lldp_interfacesArgs + + +class Lldp_interfacesFacts(object): + """ The vyos lldp_interfaces fact class + """ + + def __init__(self, module, subspec='config', options='options'): + self._module = module + self.argument_spec = Lldp_interfacesArgs.argument_spec + spec = deepcopy(self.argument_spec) + if subspec: + if options: + facts_argument_spec = spec[subspec][options] + else: + facts_argument_spec = spec[subspec] + else: + facts_argument_spec = spec + + self.generated_spec = utils.generate_dict(facts_argument_spec) + + def populate_facts(self, connection, ansible_facts, data=None): + """ Populate the facts for lldp_interfaces + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + :rtype: dictionary + :returns: facts + """ + if not data: + data = connection.get_config() + + objs = [] + lldp_names = findall(r'^set service lldp interface (\S+)', data, M) + if lldp_names: + for lldp in set(lldp_names): + lldp_regex = r' %s .+$' % lldp + cfg = findall(lldp_regex, data, M) + obj = self.render_config(cfg) + obj['name'] = lldp.strip("'") + if obj: + objs.append(obj) + facts = {} + if objs: + facts['lldp_interfaces'] = objs + ansible_facts['ansible_network_resources'].update(facts) + + ansible_facts['ansible_network_resources'].update(facts) + return ansible_facts + + def render_config(self, 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 = {} + location = {} + + civic_conf = '\n'.join(filter(lambda x: ('civic-based' in x), conf)) + elin_conf = '\n'.join(filter(lambda x: ('elin' in x), conf)) + coordinate_conf = '\n'.join(filter(lambda x: ('coordinate-based' in x), conf)) + disable = '\n'.join(filter(lambda x: ('disable' in x), conf)) + + coordinate_based_conf = self.parse_attribs( + ['altitude', 'datum', 'longitude', 'latitude'], coordinate_conf + ) + elin_based_conf = self.parse_lldp_elin_based(elin_conf) + civic_based_conf = self.parse_lldp_civic_based(civic_conf) + if disable: + config['enable'] = False + if coordinate_conf: + location['coordinate_based'] = coordinate_based_conf + config['location'] = location + elif civic_based_conf: + location['civic_based'] = civic_based_conf + config['location'] = location + elif elin_conf: + location['elin'] = elin_based_conf + config['location'] = location + + return utils.remove_empties(config) + + def parse_attribs(self, attribs, conf): + config = {} + for item in attribs: + value = utils.parse_conf_arg(conf, item) + if value: + value = value.strip("'") + if item == 'altitude': + value = int(value) + config[item] = value + else: + config[item] = None + return utils.remove_empties(config) + + def parse_lldp_civic_based(self, conf): + civic_based = None + if conf: + civic_info_list = [] + civic_add_list = findall(r"^.*civic-based ca-type (.+)", conf, M) + if civic_add_list: + for civic_add in civic_add_list: + ca = civic_add.split(' ') + c_add = {} + c_add['ca_type'] = int(ca[0].strip("'")) + c_add['ca_value'] = ca[2].strip("'") + civic_info_list.append(c_add) + + country_code = search(r'^.*civic-based country-code (.+)', conf, M) + civic_based = {} + civic_based['ca_info'] = civic_info_list + civic_based['country_code'] = country_code.group(1).strip("'") + return civic_based + + def parse_lldp_elin_based(self, conf): + elin_based = None + if conf: + e_num = search(r'^.* elin (.+)', conf, M) + elin_based = e_num.group(1).strip("'") + + return elin_based diff --git a/lib/ansible/module_utils/network/vyos/utils/utils.py b/lib/ansible/module_utils/network/vyos/utils/utils.py index a6593be28bf..294f5f5e138 100644 --- a/lib/ansible/module_utils/network/vyos/utils/utils.py +++ b/lib/ansible/module_utils/network/vyos/utils/utils.py @@ -6,6 +6,7 @@ # utils from __future__ import absolute_import, division, print_function __metaclass__ = type +from ansible.module_utils.six import iteritems def search_obj_in_list(name, lst, key='name'): @@ -117,3 +118,47 @@ def list_diff_want_only(want_list, have_list): else: diff = [i for i in have_list + want_list if i in want_list and i not in have_list] return diff + + +def search_dict_tv_in_list(d_val1, d_val2, lst, key1, key2): + """ + This function return the dict object if it exist in list. + :param d_val1: + :param d_val2: + :param lst: + :param key1: + :param key2: + :return: + """ + obj = next((item for item in lst if item[key1] == d_val1 and item[key2] == d_val2), None) + if obj: + return obj + else: + return None + + +def key_value_in_dict(have_key, have_value, want_dict): + """ + This function checks whether the key and values exist in dict + :param have_key: + :param have_value: + :param want_dict: + :return: + """ + for key, value in iteritems(want_dict): + if key == have_key and value == have_value: + return True + return False + + +def is_dict_element_present(dict, key): + """ + This function checks whether the key is present in dict. + :param dict: + :param key: + :return: + """ + for item in dict: + if item == key: + return True + return False diff --git a/lib/ansible/modules/network/vyos/vyos_lldp_interface.py b/lib/ansible/modules/network/vyos/_vyos_lldp_interface.py similarity index 96% rename from lib/ansible/modules/network/vyos/vyos_lldp_interface.py rename to lib/ansible/modules/network/vyos/_vyos_lldp_interface.py index 57503b92f9b..2d08e4d6aa8 100644 --- a/lib/ansible/modules/network/vyos/vyos_lldp_interface.py +++ b/lib/ansible/modules/network/vyos/_vyos_lldp_interface.py @@ -19,8 +19,9 @@ # along with Ansible. If not, see . # + ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], + 'status': ['deprecated'], 'supported_by': 'network'} @@ -33,19 +34,26 @@ short_description: Manage LLDP interfaces configuration on VyOS network devices description: - This module provides declarative management of LLDP interfaces configuration on VyOS network devices. +deprecated: + removed_in: '2.13' + alternative: vyos_lldp_interfaces + why: Updated modules released with more functionality. notes: - Tested against VYOS 1.1.7 options: name: description: - Name of the interface LLDP should be configured on. + type: str aggregate: description: List of interfaces LLDP should be configured on. + type: list state: description: - State of the LLDP configuration. default: present choices: ['present', 'absent', 'enabled', 'disabled'] + type: str extends_documentation_fragment: vyos """ @@ -89,6 +97,8 @@ commands: - set service lldp eth1 - set service lldp eth2 disable """ + + from copy import deepcopy from ansible.module_utils.basic import AnsibleModule diff --git a/lib/ansible/modules/network/vyos/vyos_facts.py b/lib/ansible/modules/network/vyos/vyos_facts.py index b9b33ee84bc..0dbd91cdee4 100644 --- a/lib/ansible/modules/network/vyos/vyos_facts.py +++ b/lib/ansible/modules/network/vyos/vyos_facts.py @@ -52,7 +52,8 @@ options: specific subset should not be collected. required: false version_added: "2.9" - choices: ['all', 'interfaces', '!interfaces', 'l3_interfaces', '!l3_interfaces', 'lag_interfaces', '!lag_interfaces', 'lldp_global', '!lldp_global'] + choices: ['all', 'interfaces', '!interfaces', 'l3_interfaces', '!l3_interfaces','lag_interfaces', '!lag_interfaces', + 'lldp_global', '!lldp_global','lldp_interfaces', '!lldp_interfaces'] """ EXAMPLES = """ diff --git a/lib/ansible/modules/network/vyos/vyos_lldp_interfaces.py b/lib/ansible/modules/network/vyos/vyos_lldp_interfaces.py new file mode 100644 index 00000000000..8797a4eba15 --- /dev/null +++ b/lib/ansible/modules/network/vyos/vyos_lldp_interfaces.py @@ -0,0 +1,507 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the resource +# module builder playbook. +# +# Do not edit this file manually. +# +# Changes to this file will be over written +# by the resource module builder. +# +# Changes should be made in the model used to +# generate this file or in the resource module +# builder template. +# +############################################# + +""" +The module file for vyos_lldp_interfaces +""" + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +ANSIBLE_METADATA = { + 'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'network' +} + +DOCUMENTATION = """ +--- +module: vyos_lldp_interfaces +version_added: 2.9 +short_description: Manages attributes of lldp interfaces on VyOS devices. +description: This module manages attributes of lldp interfaces on VyOS network devices. +notes: + - Tested against VyOS 1.1.8 (helium). + - This module works with connection C(network_cli) +author: + - Rohit Thakur (@rohitthakur2590) +options: + config: + description: A list of lldp interfaces configurations. + type: list + suboptions: + name: + description: + - Name of the lldp interface. + type: str + required: True + enable: + description: + - to disable lldp on the interface. + type: bool + default: True + location: + description: + - LLDP-MED location data. + type: dict + suboptions: + civic_based: + description: + - Civic-based location data. + type: dict + suboptions: + ca_info: + description: LLDP-MED address info + type: list + suboptions: + ca_type: + description: LLDP-MED Civic Address type. + type: int + required: True + ca_value: + description: LLDP-MED Civic Address value. + type: str + required: True + country_code: + description: Country Code + type: str + required: True + coordinate_based: + description: + - Coordinate-based location. + type: dict + suboptions: + altitude: + description: Altitude in meters. + type: int + datum: + description: Coordinate datum type. + type: str + choices: + - WGS84 + - NAD83 + - MLLW + latitude: + description: Latitude. + type: str + required: True + longitude: + description: Longitude. + type: str + required: True + elin: + description: Emergency Call Service ELIN number (between 10-25 numbers). + type: str + state: + description: + - The state the configuration should be left in. + type: str + choices: + - merged + - replaced + - overridden + - deleted + default: merged + +""" +EXAMPLES = """ +# Using merged +# +# Before state: +# ------------- +# +# vyos@vyos:~$ show configuration commands | grep lldp +# +- name: Merge provided configuration with device configuration + vyos_lldp_interfaces: + config: + - name: 'eth1' + location: + civic_based: + country_code: 'US' + ca_info: + - ca_type: 0 + ca_value: 'ENGLISH' + + - name: 'eth2' + location: + coordinate_based: + altitude: 2200 + datum: 'WGS84' + longitude: '222.267255W' + latitude: '33.524449N' + state: merged +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# before": [] +# +# "commands": [ +# "set service lldp interface eth1 location civic-based country-code 'US'", +# "set service lldp interface eth1 location civic-based ca-type 0 ca-value 'ENGLISH'", +# "set service lldp interface eth1", +# "set service lldp interface eth2 location coordinate-based latitude '33.524449N'", +# "set service lldp interface eth2 location coordinate-based altitude '2200'", +# "set service lldp interface eth2 location coordinate-based datum 'WGS84'", +# "set service lldp interface eth2 location coordinate-based longitude '222.267255W'", +# "set service lldp interface eth2 location coordinate-based latitude '33.524449N'", +# "set service lldp interface eth2 location coordinate-based altitude '2200'", +# "set service lldp interface eth2 location coordinate-based datum 'WGS84'", +# "set service lldp interface eth2 location coordinate-based longitude '222.267255W'", +# "set service lldp interface eth2" +# +# "after": [ +# { +# "location": { +# "coordinate_based": { +# "altitude": 2200, +# "datum": "WGS84", +# "latitude": "33.524449N", +# "longitude": "222.267255W" +# } +# }, +# "name": "eth2" +# }, +# { +# "location": { +# "civic_based": { +# "ca_info": [ +# { +# "ca_type": 0, +# "ca_value": "ENGLISH" +# } +# ], +# "country_code": "US" +# } +# }, +# "name": "eth1" +# } +# ], +# +# After state: +# ------------- +# +# vyos@vyos:~$ show configuration commands | grep lldp +# set service lldp interface eth1 location civic-based ca-type 0 ca-value 'ENGLISH' +# set service lldp interface eth1 location civic-based country-code 'US' +# set service lldp interface eth2 location coordinate-based altitude '2200' +# set service lldp interface eth2 location coordinate-based datum 'WGS84' +# set service lldp interface eth2 location coordinate-based latitude '33.524449N' +# set service lldp interface eth2 location coordinate-based longitude '222.267255W' + + +# Using replaced +# +# Before state: +# ------------- +# +# vyos@vyos:~$ show configuration commands | grep lldp +# set service lldp interface eth1 location civic-based ca-type 0 ca-value 'ENGLISH' +# set service lldp interface eth1 location civic-based country-code 'US' +# set service lldp interface eth2 location coordinate-based altitude '2200' +# set service lldp interface eth2 location coordinate-based datum 'WGS84' +# set service lldp interface eth2 location coordinate-based latitude '33.524449N' +# set service lldp interface eth2 location coordinate-based longitude '222.267255W' +# +- name: Replace device configurations of listed LLDP interfaces with provided configurations + vyos_lldp_interfaces: + config: + - name: 'eth2' + location: + civic_based: + country_code: 'US' + ca_info: + - ca_type: 0 + ca_value: 'ENGLISH' + + - name: 'eth1' + location: + coordinate_based: + altitude: 2200 + datum: 'WGS84' + longitude: '222.267255W' + latitude: '33.524449N' + state: replaced +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# "before": [ +# { +# "location": { +# "coordinate_based": { +# "altitude": 2200, +# "datum": "WGS84", +# "latitude": "33.524449N", +# "longitude": "222.267255W" +# } +# }, +# "name": "eth2" +# }, +# { +# "location": { +# "civic_based": { +# "ca_info": [ +# { +# "ca_type": 0, +# "ca_value": "ENGLISH" +# } +# ], +# "country_code": "US" +# } +# }, +# "name": "eth1" +# } +# ] +# +# "commands": [ +# "delete service lldp interface eth2 location", +# "set service lldp interface eth2 'disable'", +# "set service lldp interface eth2 location civic-based country-code 'US'", +# "set service lldp interface eth2 location civic-based ca-type 0 ca-value 'ENGLISH'", +# "delete service lldp interface eth1 location", +# "set service lldp interface eth1 'disable'", +# "set service lldp interface eth1 location coordinate-based latitude '33.524449N'", +# "set service lldp interface eth1 location coordinate-based altitude '2200'", +# "set service lldp interface eth1 location coordinate-based datum 'WGS84'", +# "set service lldp interface eth1 location coordinate-based longitude '222.267255W'" +# ] +# +# "after": [ +# { +# "location": { +# "civic_based": { +# "ca_info": [ +# { +# "ca_type": 0, +# "ca_value": "ENGLISH" +# } +# ], +# "country_code": "US" +# } +# }, +# "name": "eth2" +# }, +# { +# "location": { +# "coordinate_based": { +# "altitude": 2200, +# "datum": "WGS84", +# "latitude": "33.524449N", +# "longitude": "222.267255W" +# } +# }, +# "name": "eth1" +# } +# ] +# +# After state: +# ------------- +# +# vyos@vyos:~$ show configuration commands | grep lldp +# set service lldp interface eth1 'disable' +# set service lldp interface eth1 location coordinate-based altitude '2200' +# set service lldp interface eth1 location coordinate-based datum 'WGS84' +# set service lldp interface eth1 location coordinate-based latitude '33.524449N' +# set service lldp interface eth1 location coordinate-based longitude '222.267255W' +# set service lldp interface eth2 'disable' +# set service lldp interface eth2 location civic-based ca-type 0 ca-value 'ENGLISH' +# set service lldp interface eth2 location civic-based country-code 'US' + + +# Using overridden +# +# Before state +# -------------- +# +# vyos@vyos:~$ show configuration commands | grep lldp +# set service lldp interface eth1 'disable' +# set service lldp interface eth1 location coordinate-based altitude '2200' +# set service lldp interface eth1 location coordinate-based datum 'WGS84' +# set service lldp interface eth1 location coordinate-based latitude '33.524449N' +# set service lldp interface eth1 location coordinate-based longitude '222.267255W' +# set service lldp interface eth2 'disable' +# set service lldp interface eth2 location civic-based ca-type 0 ca-value 'ENGLISH' +# set service lldp interface eth2 location civic-based country-code 'US' +# +- name: Overrides all device configuration with provided configuration + vyos_lag_interfaces: + config: + - name: 'eth2' + location: + elin: 0000000911 + + state: overridden +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# "before": [ +# { +# "enable": false, +# "location": { +# "civic_based": { +# "ca_info": [ +# { +# "ca_type": 0, +# "ca_value": "ENGLISH" +# } +# ], +# "country_code": "US" +# } +# }, +# "name": "eth2" +# }, +# { +# "enable": false, +# "location": { +# "coordinate_based": { +# "altitude": 2200, +# "datum": "WGS84", +# "latitude": "33.524449N", +# "longitude": "222.267255W" +# } +# }, +# "name": "eth1" +# } +# ] +# +# "commands": [ +# "delete service lldp interface eth2 location", +# "delete service lldp interface eth2 disable", +# "set service lldp interface eth2 location elin 0000000911" +# +# +# "after": [ +# { +# "location": { +# "elin": 0000000911 +# }, +# "name": "eth2" +# } +# ] +# +# +# After state +# ------------ +# +# vyos@vyos# run show configuration commands | grep lldp +# set service lldp interface eth2 location elin '0000000911' + + +# Using deleted +# +# Before state +# ------------- +# +# vyos@vyos# run show configuration commands | grep lldp +# set service lldp interface eth2 location elin '0000000911' +# +- name: Delete lldp interface attributes of given interfaces. + vyos_lag_interfaces: + config: + - name: 'eth2' + state: deleted +# +# +# ------------------------ +# Module Execution Results +# ------------------------ +# + "before": [ + { + "location": { + "elin": 0000000911 + }, + "name": "eth2" + } + ] +# "commands": [ +# "commands": [ +# "delete service lldp interface eth2" +# ] +# +# "after": [] +# After state +# ------------ +# vyos@vyos# run show configuration commands | grep lldp +# set service 'lldp' + + +""" +RETURN = """ +before: + description: The configuration prior to the model invocation. + returned: always + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +after: + description: The resulting configuration model invocation. + returned: when changed + type: list + sample: > + The configuration returned will always be in the same format + of the parameters above. +commands: + description: The set of commands pushed to the remote device. + returned: always + type: list + sample: + - "set service lldp interface eth2 'disable'" + - "delete service lldp interface eth1 location" +""" + + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.network.vyos.argspec.lldp_interfaces.lldp_interfaces import Lldp_interfacesArgs +from ansible.module_utils.network.vyos.config.lldp_interfaces.lldp_interfaces import Lldp_interfaces + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + required_if = [('state', 'merged', ('config',)), + ('state', 'replaced', ('config',)), + ('state', 'overridden', ('config',))] + module = AnsibleModule(argument_spec=Lldp_interfacesArgs.argument_spec, required_if=required_if, + supports_check_mode=True) + + result = Lldp_interfaces(module).execute_module() + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/prepare_vyos_tests/tasks/main.yaml b/test/integration/targets/prepare_vyos_tests/tasks/main.yaml index 93bd1c5e65e..53d86821325 100644 --- a/test/integration/targets/prepare_vyos_tests/tasks/main.yaml +++ b/test/integration/targets/prepare_vyos_tests/tasks/main.yaml @@ -5,6 +5,8 @@ vars: lines: | set interfaces ethernet eth0 address dhcp + set interfaces ethernet eth0 speed auto + set interfaces ethernet eth0 duplex auto set interfaces ethernet eth1 set interfaces ethernet eth2 delete interfaces loopback lo diff --git a/test/integration/targets/vyos_lldp_interfaces/defaults/main.yaml b/test/integration/targets/vyos_lldp_interfaces/defaults/main.yaml new file mode 100644 index 00000000000..164afead284 --- /dev/null +++ b/test/integration/targets/vyos_lldp_interfaces/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: "[^_].*" +test_items: [] diff --git a/test/integration/targets/vyos_lldp_interfaces/meta/main.yaml b/test/integration/targets/vyos_lldp_interfaces/meta/main.yaml new file mode 100644 index 00000000000..f88bce55675 --- /dev/null +++ b/test/integration/targets/vyos_lldp_interfaces/meta/main.yaml @@ -0,0 +1,2 @@ +dependencies: + - prepare_vyos_tests diff --git a/test/integration/targets/vyos_lldp_interfaces/tasks/cli.yaml b/test/integration/targets/vyos_lldp_interfaces/tasks/cli.yaml new file mode 100644 index 00000000000..655e51ee63d --- /dev/null +++ b/test/integration/targets/vyos_lldp_interfaces/tasks/cli.yaml @@ -0,0 +1,19 @@ +--- +- name: Collect all cli test cases + find: + paths: "{{ role_path }}/tests/cli" + patterns: "{{ testcase }}.yaml" + use_regex: true + register: test_cases + delegate_to: localhost + +- name: Set test_items + set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=network_cli) + include: "{{ test_case_to_run }}" + vars: + ansible_connection: network_cli + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run diff --git a/test/integration/targets/vyos_lldp_interfaces/tasks/main.yaml b/test/integration/targets/vyos_lldp_interfaces/tasks/main.yaml new file mode 100644 index 00000000000..415c99d8b12 --- /dev/null +++ b/test/integration/targets/vyos_lldp_interfaces/tasks/main.yaml @@ -0,0 +1,2 @@ +--- +- { include: cli.yaml, tags: ['cli'] } diff --git a/test/integration/targets/vyos_lldp_interfaces/tests/cli/_populate.yaml b/test/integration/targets/vyos_lldp_interfaces/tests/cli/_populate.yaml new file mode 100644 index 00000000000..eec20396745 --- /dev/null +++ b/test/integration/targets/vyos_lldp_interfaces/tests/cli/_populate.yaml @@ -0,0 +1,14 @@ +--- +- name: Setup + cli_config: + config: "{{ lines }}" + vars: + lines: | + set service lldp interface eth1 + set service lldp interface eth1 location civic-based country-code US + set service lldp interface eth1 location civic-based ca-type 0 ca-value ENGLISH + set service lldp interface eth2 + set service lldp interface eth2 location coordinate-based latitude 33.524449N + set service lldp interface eth2 location coordinate-based altitude 2200 + set service lldp interface eth2 location coordinate-based datum WGS84 + set service lldp interface eth2 location coordinate-based longitude 222.267255W diff --git a/test/integration/targets/vyos_lldp_interfaces/tests/cli/_populate_intf.yaml b/test/integration/targets/vyos_lldp_interfaces/tests/cli/_populate_intf.yaml new file mode 100644 index 00000000000..f48509eda5f --- /dev/null +++ b/test/integration/targets/vyos_lldp_interfaces/tests/cli/_populate_intf.yaml @@ -0,0 +1,10 @@ +--- +- name: Setup + cli_config: + config: "{{ lines }}" + vars: + lines: | + set service lldp interface eth2 + set service lldp interface eth2 location civic-based country-code US + set service lldp interface eth2 location civic-based ca-type 0 ca-value ENGLISH + set service lldp interface eth2 disable diff --git a/test/integration/targets/vyos_lldp_interfaces/tests/cli/_remove_config.yaml b/test/integration/targets/vyos_lldp_interfaces/tests/cli/_remove_config.yaml new file mode 100644 index 00000000000..0d28414e9ef --- /dev/null +++ b/test/integration/targets/vyos_lldp_interfaces/tests/cli/_remove_config.yaml @@ -0,0 +1,8 @@ +--- +- name: Remove Config + cli_config: + config: "{{ lines }}" + vars: + lines: | + delete service lldp interface + delete service lldp diff --git a/test/integration/targets/vyos_lldp_interfaces/tests/cli/deleted.yaml b/test/integration/targets/vyos_lldp_interfaces/tests/cli/deleted.yaml new file mode 100644 index 00000000000..86e21a46ced --- /dev/null +++ b/test/integration/targets/vyos_lldp_interfaces/tests/cli/deleted.yaml @@ -0,0 +1,46 @@ +--- +- debug: + msg: "Start vyos_lldp_interfaces deleted integration tests ansible_connection={{ ansible_connection }}" + +- include_tasks: _populate.yaml + +- block: + - name: Delete attributes of given LLDP interfaces. + vyos_lldp_interfaces: &deleted + config: + - name: 'eth1' + - name: 'eth2' + state: deleted + register: result + + - name: Assert that the before dicts were correctly generated + assert: + that: + - "{{ populate | symmetric_difference(result['before']) |length == 0 }}" + + - name: Assert that the correct set of commands were generated + assert: + that: + - "{{ deleted['commands'] | symmetric_difference(result['commands']) |length == 0 }}" + + - name: Assert that the after dicts were correctly generated + assert: + that: + - "{{ deleted['after'] | symmetric_difference(result['after']) |length == 0 }}" + + - name: Delete attributes of given interfaces (IDEMPOTENT) + vyos_lldp_interfaces: *deleted + register: result + + - name: Assert that the previous task was idempotent + assert: + that: + - "result.changed == false" + - "result.commands|length == 0" + + - name: Assert that the before dicts were correctly generated + assert: + that: + - "{{ deleted['after'] | symmetric_difference(result['before']) |length == 0 }}" + always: + - include_tasks: _remove_config.yaml diff --git a/test/integration/targets/vyos_lldp_interfaces/tests/cli/merged.yaml b/test/integration/targets/vyos_lldp_interfaces/tests/cli/merged.yaml new file mode 100644 index 00000000000..97da169e4f6 --- /dev/null +++ b/test/integration/targets/vyos_lldp_interfaces/tests/cli/merged.yaml @@ -0,0 +1,58 @@ +--- +- debug: + msg: "START vyos_lldp_interfaces merged integration tests on connection={{ ansible_connection }}" + +- include_tasks: _remove_config.yaml + +- block: + - name: Merge the provided configuration with the exisiting running configuration + vyos_lldp_interfaces: &merged + config: + - name: 'eth1' + location: + civic_based: + country_code: 'US' + ca_info: + - ca_type: 0 + ca_value: 'ENGLISH' + + - name: 'eth2' + location: + coordinate_based: + altitude: 2200 + datum: 'WGS84' + longitude: '222.267255W' + latitude: '33.524449N' + state: merged + register: result + + - name: Assert that before dicts were correctly generated + assert: + that: "{{ merged['before'] | symmetric_difference(result['before']) |length == 0 }}" + + - name: Assert that correct set of commands were generated + assert: + that: + - "{{ merged['commands'] | symmetric_difference(result['commands']) |length == 0 }}" + + - name: Assert that after dicts was correctly generated + assert: + that: + - "{{ merged['after'] | symmetric_difference(result['after']) |length == 0 }}" + + - name: Merge the provided configuration with the existing running configuration (IDEMPOTENT) + vyos_lldp_interfaces: *merged + register: result + + - name: Assert that the previous task was idempotent + assert: + that: + - "result['changed'] == false" + + - name: Assert that before dicts were correctly generated + assert: + that: + - "{{ merged['after'] | symmetric_difference(result['before']) |length == 0 }}" + + always: + - include_tasks: _remove_config.yaml diff --git a/test/integration/targets/vyos_lldp_interfaces/tests/cli/overridden.yaml b/test/integration/targets/vyos_lldp_interfaces/tests/cli/overridden.yaml new file mode 100644 index 00000000000..5f4c5de5b9f --- /dev/null +++ b/test/integration/targets/vyos_lldp_interfaces/tests/cli/overridden.yaml @@ -0,0 +1,49 @@ +--- +- debug: + msg: "START vyos_lldp_interfaces overridden integration tests on connection={{ ansible_connection }}" + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate_intf.yaml + +- block: + - name: Overrides all device configuration with provided configuration + vyos_lldp_interfaces: &overridden + config: + - name: 'eth2' + location: + elin: '0000000911' + state: overridden + register: result + + - name: Assert that before dicts were correctly generated + assert: + that: + - "{{ populate_intf | symmetric_difference(result['before']) |length == 0 }}" + + - name: Assert that correct commands were generated + assert: + that: + - "{{ overridden['commands'] | symmetric_difference(result['commands']) |length == 0 }}" + + - name: Assert that after dicts were correctly generated + assert: + that: + - "{{ overridden['after'] | symmetric_difference(result['after']) |length == 0 }}" + + - name: Overrides all device configuration with provided configurations (IDEMPOTENT) + vyos_lldp_interfaces: *overridden + register: result + + - name: Assert that the previous task was idempotent + assert: + that: + - "result['changed'] == false" + + - name: Assert that before dicts were correctly generated + assert: + that: + - "{{ overridden['after'] | symmetric_difference(result['before']) |length == 0 }}" + + always: + - include_tasks: _remove_config.yaml diff --git a/test/integration/targets/vyos_lldp_interfaces/tests/cli/replaced.yaml b/test/integration/targets/vyos_lldp_interfaces/tests/cli/replaced.yaml new file mode 100644 index 00000000000..355123844a9 --- /dev/null +++ b/test/integration/targets/vyos_lldp_interfaces/tests/cli/replaced.yaml @@ -0,0 +1,63 @@ +--- +- debug: + msg: "START vyos_lldp_interfaces replaced integration tests on connection={{ ansible_connection }}" + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + - name: Replace device configurations of listed LLDP interfaces with provided configurations + vyos_lldp_interfaces: &replaced + config: + - name: 'eth2' + enable: false + location: + civic_based: + country_code: 'US' + ca_info: + - ca_type: 0 + ca_value: 'ENGLISH' + + - name: 'eth1' + enable: false + location: + coordinate_based: + altitude: 2200 + datum: 'WGS84' + longitude: '222.267255W' + latitude: '33.524449N' + state: replaced + register: result + + - name: Assert that correct set of commands were generated + assert: + that: + - "{{ replaced['commands'] | symmetric_difference(result['commands']) |length == 0 }}" + + - name: Assert that before dicts are correctly generated + assert: + that: + - "{{ populate | symmetric_difference(result['before']) |length == 0 }}" + + - name: Assert that after dict is correctly generated + assert: + that: + - "{{ replaced['after'] | symmetric_difference(result['after']) |length == 0 }}" + + - name: Replace device configurations of listed LLDP interfaces with provided configurarions (IDEMPOTENT) + vyos_lldp_interfaces: *replaced + register: result + + - name: Assert that task was idempotent + assert: + that: + - "result['changed'] == false" + + - name: Assert that before dict is correctly generated + assert: + that: + - "{{ replaced['after'] | symmetric_difference(result['before']) |length == 0 }}" + + always: + - include_tasks: _remove_config.yaml diff --git a/test/integration/targets/vyos_lldp_interfaces/tests/cli/rtt.yaml b/test/integration/targets/vyos_lldp_interfaces/tests/cli/rtt.yaml new file mode 100644 index 00000000000..e6823f1dc63 --- /dev/null +++ b/test/integration/targets/vyos_lldp_interfaces/tests/cli/rtt.yaml @@ -0,0 +1,57 @@ +--- +- debug: + msg: "START vyos_lldp_interfaces round trip integration tests on connection={{ ansible_connection }}" + +- include_tasks: _remove_config.yaml + +- block: + - name: Apply the provided configuration (base config) + vyos_lldp_interfaces: + config: + - name: 'eth1' + location: + civic_based: + country_code: 'US' + ca_info: + - ca_type: 0 + ca_value: 'ENGLISH' + + state: merged + register: base_config + + - name: Gather lldp_interfaces facts + vyos_facts: + gather_subset: + - default + gather_network_resources: + - lldp_interfaces + + - name: Apply the provided configuration (config to be reverted) + vyos_lldp_interfaces: + config: + - name: 'eth2' + location: + coordinate_based: + altitude: 2200 + datum: 'WGS84' + longitude: '222.267255W' + latitude: '33.524449N' + state: merged + register: result + + - name: Assert that changes were applied + assert: + that: "{{ round_trip['after'] | symmetric_difference(result['after']) |length == 0 }}" + + - name: Revert back to base config using facts round trip + vyos_lldp_interfaces: + config: "{{ ansible_facts['network_resources']['lldp_interfaces'] }}" + state: overridden + register: revert + + - name: Assert that config was reverted + assert: + that: "{{ base_config['after'] | symmetric_difference(revert['after']) |length == 0 }}" + + always: + - include_tasks: _remove_config.yaml diff --git a/test/integration/targets/vyos_lldp_interfaces/vars/main.yaml b/test/integration/targets/vyos_lldp_interfaces/vars/main.yaml new file mode 100644 index 00000000000..6f33343c366 --- /dev/null +++ b/test/integration/targets/vyos_lldp_interfaces/vars/main.yaml @@ -0,0 +1,130 @@ +--- +merged: + before: [] + + + commands: + - "set service lldp interface eth1 location civic-based country-code 'US'" + - "set service lldp interface eth1 location civic-based ca-type 0 ca-value 'ENGLISH'" + - "set service lldp interface eth1" + - "set service lldp interface eth2 location coordinate-based latitude '33.524449N'" + - "set service lldp interface eth2 location coordinate-based altitude '2200'" + - "set service lldp interface eth2 location coordinate-based datum 'WGS84'" + - "set service lldp interface eth2 location coordinate-based longitude '222.267255W'" + - "set service lldp interface eth2 location coordinate-based latitude '33.524449N'" + - "set service lldp interface eth2 location coordinate-based altitude '2200'" + - "set service lldp interface eth2 location coordinate-based datum 'WGS84'" + - "set service lldp interface eth2 location coordinate-based longitude '222.267255W'" + - "set service lldp interface eth2" + + after: + - name: 'eth1' + location: + civic_based: + country_code: 'US' + ca_info: + - ca_type: 0 + ca_value: 'ENGLISH' + + - name: 'eth2' + location: + coordinate_based: + altitude: 2200 + datum: 'WGS84' + longitude: '222.267255W' + latitude: '33.524449N' + +populate: + - name: 'eth1' + location: + civic_based: + country_code: 'US' + ca_info: + - ca_type: 0 + ca_value: 'ENGLISH' + + - name: 'eth2' + location: + coordinate_based: + altitude: 2200 + datum: 'WGS84' + longitude: '222.267255W' + latitude: '33.524449N' + +replaced: + commands: + - "delete service lldp interface eth2 location" + - "set service lldp interface eth2 'disable'" + - "set service lldp interface eth2 location civic-based country-code 'US'" + - "set service lldp interface eth2 location civic-based ca-type 0 ca-value 'ENGLISH'" + - "delete service lldp interface eth1 location" + - "set service lldp interface eth1 'disable'" + - "set service lldp interface eth1 location coordinate-based latitude '33.524449N'" + - "set service lldp interface eth1 location coordinate-based altitude '2200'" + - "set service lldp interface eth1 location coordinate-based datum 'WGS84'" + - "set service lldp interface eth1 location coordinate-based longitude '222.267255W'" + + after: + - name: 'eth2' + enable: false + location: + civic_based: + country_code: 'US' + ca_info: + - ca_type: 0 + ca_value: 'ENGLISH' + + - name: 'eth1' + enable: false + location: + coordinate_based: + altitude: 2200 + datum: 'WGS84' + longitude: '222.267255W' + latitude: '33.524449N' + +populate_intf: + - name: 'eth2' + enable: false + location: + civic_based: + country_code: 'US' + ca_info: + - ca_type: 0 + ca_value: 'ENGLISH' + +overridden: + commands: + - "delete service lldp interface eth2 location" + - "delete service lldp interface eth2 'disable'" + - "set service lldp interface eth2 location elin '0000000911'" + + after: + - name: 'eth2' + location: + elin: 0000000911 + +deleted: + commands: + - "delete service lldp interface eth1" + - "delete service lldp interface eth2" + + after: [] + +round_trip: + after: + - name: 'eth1' + location: + civic_based: + country_code: 'US' + ca_info: + - ca_type: 0 + ca_value: 'ENGLISH' + + - name: 'eth2' + location: + coordinate_based: + altitude: 2200 + datum: 'WGS84' + longitude: '222.267255W' + latitude: '33.524449N' diff --git a/test/sanity/ignore.txt b/test/sanity/ignore.txt index ca7184da84e..64720ba49fe 100644 --- a/test/sanity/ignore.txt +++ b/test/sanity/ignore.txt @@ -5096,14 +5096,13 @@ lib/ansible/modules/network/vyos/_vyos_linkagg.py validate-modules:E337 lib/ansible/modules/network/vyos/_vyos_linkagg.py validate-modules:E338 lib/ansible/modules/network/vyos/_vyos_linkagg.py validate-modules:E340 lib/ansible/modules/network/vyos/_vyos_lldp.py validate-modules:E324 -lib/ansible/modules/network/vyos/vyos_lldp_interface.py future-import-boilerplate -lib/ansible/modules/network/vyos/vyos_lldp_interface.py metaclass-boilerplate -lib/ansible/modules/network/vyos/vyos_lldp_interface.py validate-modules:E322 -lib/ansible/modules/network/vyos/vyos_lldp_interface.py validate-modules:E324 -lib/ansible/modules/network/vyos/vyos_lldp_interface.py validate-modules:E326 -lib/ansible/modules/network/vyos/vyos_lldp_interface.py validate-modules:E337 -lib/ansible/modules/network/vyos/vyos_lldp_interface.py validate-modules:E338 -lib/ansible/modules/network/vyos/vyos_lldp_interface.py validate-modules:E340 +lib/ansible/modules/network/vyos/_vyos_lldp_interface.py future-import-boilerplate +lib/ansible/modules/network/vyos/_vyos_lldp_interface.py metaclass-boilerplate +lib/ansible/modules/network/vyos/_vyos_lldp_interface.py validate-modules:E322 +lib/ansible/modules/network/vyos/_vyos_lldp_interface.py validate-modules:E324 +lib/ansible/modules/network/vyos/_vyos_lldp_interface.py validate-modules:E326 +lib/ansible/modules/network/vyos/_vyos_lldp_interface.py validate-modules:E338 +lib/ansible/modules/network/vyos/_vyos_lldp_interface.py validate-modules:E340 lib/ansible/modules/network/vyos/vyos_logging.py future-import-boilerplate lib/ansible/modules/network/vyos/vyos_logging.py metaclass-boilerplate lib/ansible/modules/network/vyos/vyos_logging.py validate-modules:E322