diff --git a/plugins/module_utils/network/vyos/argspec/lldp_interfaces/lldp_interfaces.py b/plugins/module_utils/network/vyos/argspec/lldp_interfaces/lldp_interfaces.py index 2976fc0..109ea43 100644 --- a/plugins/module_utils/network/vyos/argspec/lldp_interfaces/lldp_interfaces.py +++ b/plugins/module_utils/network/vyos/argspec/lldp_interfaces/lldp_interfaces.py @@ -1,89 +1,98 @@ # # -*- 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", }, + "running_config": {"type": "str"}, "state": { - "choices": ["merged", "replaced", "overridden", "deleted"], + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "rendered", + "gathered", + "parsed", + ], "default": "merged", "type": "str", }, } # pylint: disable=C0301 diff --git a/plugins/module_utils/network/vyos/config/lldp_interfaces/lldp_interfaces.py b/plugins/module_utils/network/vyos/config/lldp_interfaces/lldp_interfaces.py index 377fec9..94e39c3 100644 --- a/plugins/module_utils/network/vyos/config/lldp_interfaces/lldp_interfaces.py +++ b/plugins/module_utils/network/vyos/config/lldp_interfaces/lldp_interfaces.py @@ -1,438 +1,459 @@ # # -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import ( ConfigBase, ) from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import ( Facts, ) from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( to_list, dict_diff, ) from ansible.module_utils.six import iteritems from ansible_collections.vyos.vyos.plugins.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): + def get_lldp_interfaces_facts(self, data=None): """ 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 + self.gather_subset, self.gather_network_resources, data=data ) 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 + commands = list() + + if self.state in self.ACTION_STATES: + existing_lldp_interfaces_facts = self.get_lldp_interfaces_facts() + else: + existing_lldp_interfaces_facts = [] - result["commands"] = commands + if self.state in self.ACTION_STATES or self.state == "rendered": + commands.extend(self.set_config(existing_lldp_interfaces_facts)) - if self._module._diff: - result["diff"] = resp["diff"] if result["changed"] else None + if commands and self.state in self.ACTION_STATES: + if not self._module.check_mode: + self._connection.edit_config(commands) + result["changed"] = True - changed_lldp_interfaces_facts = self.get_lldp_interfaces_facts() - result["before"] = existing_lldp_interfaces_facts - if result["changed"]: - result["after"] = changed_lldp_interfaces_facts + if self.state in self.ACTION_STATES: + result["commands"] = commands + + if self.state in self.ACTION_STATES or self.state == "gathered": + changed_lldp_interfaces_facts = self.get_lldp_interfaces_facts() + elif self.state == "rendered": + result["rendered"] = commands + elif self.state == "parsed": + running_config = self._module.params["running_config"] + if not running_config: + self._module.fail_json( + msg="value of running_config parameter must not be empty for state parsed" + ) + result["parsed"] = self.get_lldp_interfaces_facts( + data=running_config + ) + else: + changed_lldp_interfaces_facts = [] + + if self.state in self.ACTION_STATES: + result["before"] = existing_lldp_interfaces_facts + if result["changed"]: + result["after"] = changed_lldp_interfaces_facts + elif self.state == "gathered": + result["gathered"] = 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 in ("merged", "replaced", "overridden") and not want: + if ( + self.state in ("merged", "replaced", "overridden", "rendered") + and not want + ): self._module.fail_json( msg="value of config parameter must not be empty for state {0}".format( - state + self.state ) ) - if state == "overridden": + if self.state == "overridden": commands.extend(self._state_overridden(want=want, have=have)) - elif state == "deleted": + elif self.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": + if self.state in ("merged", "rendered"): commands.extend( self._state_merged(want=want_item, have=have_item) ) - else: + if self.state == "replaced": 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/plugins/modules/vyos_lldp_interfaces.py b/plugins/modules/vyos_lldp_interfaces.py index 8fe572b..34ceb66 100644 --- a/plugins/modules/vyos_lldp_interfaces.py +++ b/plugins/modules/vyos_lldp_interfaces.py @@ -1,513 +1,683 @@ #!/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 -short_description: Manages attributes of lldp interfaces on VyOS devices. +short_description: LLDP interfaces resource module 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). See L(the VyOS OS Platform Options,../network/user_guide/platform_vyos.html). 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 + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the VyOS device by executing + the command B(show configuration commands | grep lldp). + - The state I(parsed) reads the configuration from C(running_config) option and transforms + it into Ansible structured data as per the resource module's argspec and the value is then + returned in the I(parsed) key within the result. + type: str state: description: - The state of the configuration after module completion. type: str choices: - merged - replaced - overridden - deleted + - rendered + - parsed + - gathered default: merged """ EXAMPLES = """ # Using merged # # Before state: # ------------- # # vyos@vyos:~$ show configuration commands | grep lldp # - name: Merge provided configuration with device configuration - vyos_lldp_interfaces: + vyos.vyos.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: + vyos.vyos.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: + vyos.vyos.vyos_lldp_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: + vyos.vyos.vyos_lldp_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' +# Using gathered +# +# Before state: +# ------------- +# +# vyos@192# run 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: Gather listed lldp interfaces from running configuration + vyos.vyos.vyos_lldp_interfaces: + config: + state: gathered +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# "gathered": [ +# { +# "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@192# run 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 rendered +# +# +- name: Render the commands for provided configuration + vyos.vyos.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: rendered +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# +# "rendered": [ +# "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" +# ] + + +# Using parsed +# +# +- name: Parsed the commands to provide structured configuration. + vyos.vyos.vyos_lldp_interfaces: + running_config: + "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'" + state: parsed +# +# +# ------------------------- +# Module Execution Result +# ------------------------- +# +# +# "parsed": [ +# { +# "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" +# } +# ] + + """ RETURN = """ before: description: The configuration as structured data prior to module invocation. returned: always type: list sample: > The configuration returned will always be in the same format of the parameters above. after: description: The configuration as structured data after module completion. 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_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.lldp_interfaces.lldp_interfaces import ( Lldp_interfacesArgs, ) from ansible_collections.vyos.vyos.plugins.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", "rendered", ("config",)), ("state", "overridden", ("config",)), + ("state", "parsed", ("running_config",)), ] + mutually_exclusive = [("config", "running_config")] + module = AnsibleModule( argument_spec=Lldp_interfacesArgs.argument_spec, required_if=required_if, supports_check_mode=True, + mutually_exclusive=mutually_exclusive, ) result = Lldp_interfaces(module).execute_module() module.exit_json(**result) if __name__ == "__main__": main() diff --git a/tests/integration/targets/vyos_lldp_interfaces/tests/cli/_parsed_config.cfg b/tests/integration/targets/vyos_lldp_interfaces/tests/cli/_parsed_config.cfg new file mode 100644 index 0000000..40c96c4 --- /dev/null +++ b/tests/integration/targets/vyos_lldp_interfaces/tests/cli/_parsed_config.cfg @@ -0,0 +1,6 @@ +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' \ No newline at end of file diff --git a/tests/integration/targets/vyos_lldp_interfaces/tests/cli/empty_config.yaml b/tests/integration/targets/vyos_lldp_interfaces/tests/cli/empty_config.yaml index a5ff0a8..4ef40c9 100644 --- a/tests/integration/targets/vyos_lldp_interfaces/tests/cli/empty_config.yaml +++ b/tests/integration/targets/vyos_lldp_interfaces/tests/cli/empty_config.yaml @@ -1,37 +1,60 @@ --- - debug: msg: START vyos_lldp_interfaces empty_config integration tests on connection={{ ansible_connection }} - name: Merged with empty config should give appropriate error message register: result ignore_errors: true vyos.vyos.vyos_lldp_interfaces: config: state: merged - assert: that: - result.msg == 'value of config parameter must not be empty for state merged' - name: Replaced with empty config should give appropriate error message register: result ignore_errors: true vyos.vyos.vyos_lldp_interfaces: config: state: replaced - assert: that: - result.msg == 'value of config parameter must not be empty for state replaced' - name: Overridden with empty config should give appropriate error message register: result ignore_errors: true vyos.vyos.vyos_lldp_interfaces: config: state: overridden - assert: that: - result.msg == 'value of config parameter must not be empty for state overridden' + +- name: Parsed with empty running_config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_lldp_interfaces: + running_config: + state: parsed + +- assert: + that: + - result.msg == 'value of running_config parameter must not be empty for state + parsed' + +- name: Rendered with empty config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_lldp_interfaces: + config: + state: rendered + +- assert: + that: + - result.msg == 'value of config parameter must not be empty for state rendered' diff --git a/tests/integration/targets/vyos_lldp_interfaces/tests/cli/gathered.yaml b/tests/integration/targets/vyos_lldp_interfaces/tests/cli/gathered.yaml new file mode 100644 index 0000000..d440b53 --- /dev/null +++ b/tests/integration/targets/vyos_lldp_interfaces/tests/cli/gathered.yaml @@ -0,0 +1,34 @@ +--- +- debug: + msg: START vyos_lldp_interfaces gathered integration tests on connection={{ ansible_connection + }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Merge the provided configuration with the exisiting running configuration + register: result + vyos.vyos.vyos_lldp_interfaces: &id001 + config: + state: gathered + + - name: Assert that gathered dicts was correctly generated + assert: + that: + - "{{ populate | symmetric_difference(result['gathered']) |length == 0\ + \ }}" + + - name: Gather the existing running configuration (IDEMPOTENT) + register: result + vyos.vyos.vyos_lldp_interfaces: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result['changed'] == false + always: + + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_lldp_interfaces/tests/cli/parsed.yaml b/tests/integration/targets/vyos_lldp_interfaces/tests/cli/parsed.yaml new file mode 100644 index 0000000..7842152 --- /dev/null +++ b/tests/integration/targets/vyos_lldp_interfaces/tests/cli/parsed.yaml @@ -0,0 +1,41 @@ +--- +- debug: + msg: START vyos_lldp_interfaces parsed integration tests on connection={{ ansible_connection + }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Gather lldp_interfaces facts + register: lldp_interfaces_facts + vyos.vyos.vyos_facts: + gather_subset: + - default + gather_network_resources: + - lldp_interfaces + + - name: Provide the running configuration for parsing (config to be parsed) + register: result + vyos.vyos.vyos_lldp_interfaces: &id001 + running_config: "{{ lookup('file', '_parsed_config.cfg') }}" + state: parsed + + - name: Assert that correct parsing done + assert: + that: "{{ ansible_facts['network_resources']['lldp_interfaces'] | symmetric_difference(result['parsed'])\ + \ |length == 0 }}" + + - name: Gather the existing running configuration (IDEMPOTENT) + register: result + vyos.vyos.vyos_lldp_interfaces: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result['changed'] == false + always: + + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_lldp_interfaces/tests/cli/rendered.yaml b/tests/integration/targets/vyos_lldp_interfaces/tests/cli/rendered.yaml new file mode 100644 index 0000000..6bb9f5a --- /dev/null +++ b/tests/integration/targets/vyos_lldp_interfaces/tests/cli/rendered.yaml @@ -0,0 +1,48 @@ +--- +- debug: + msg: START vyos_lldp_interfaces rendered integration tests on connection={{ ansible_connection + }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate.yaml + +- block: + + - name: Structure provided configuration into device specific commands + register: result + vyos.vyos.vyos_lldp_interfaces: &id001 + 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: rendered + + - name: Assert that correct set of commands were generated + assert: + that: + - "{{ rendered['commands'] | symmetric_difference(result['rendered'])\ + \ |length == 0 }}" + + - name: Structure provided configuration into device specific commands (IDEMPOTENT) + register: result + vyos.vyos.vyos_lldp_interfaces: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result['changed'] == false + always: + + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_lldp_interfaces/vars/main.yaml b/tests/integration/targets/vyos_lldp_interfaces/vars/main.yaml index 3cb684e..506bdf7 100644 --- a/tests/integration/targets/vyos_lldp_interfaces/vars/main.yaml +++ b/tests/integration/targets/vyos_lldp_interfaces/vars/main.yaml @@ -1,114 +1,120 @@ --- 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 +rendered: + 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 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