Vyos lldp interfaces (#60931)

* module_utils checkin

Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com>

* vyos lldp_interfaces merging

Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com>

* shippable fix

Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com>

* merge changes

Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com>

* failure added in ignore list

Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com>

* comments incorporated

Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com>

* comments incorporated

Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com>

* test cases updated

Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com>

* remove global commands

Signed-off-by: rohitthakur2590 <rohitthakur2590@outlook.com>
This commit is contained in:
Rohit 2019-08-21 12:30:13 +05:30 committed by GitHub
parent 5f227fe260
commit 8b3ff933af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 1691 additions and 13 deletions

View file

@ -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 <vyos_lldp_global_module>` instead.
* vyos_lldp_interface use :ref:`vyos_lldp_interfaces <vyos_lldp_interfaces_module>` 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 <vmware_cluster_drs_module>`, :ref:`vmware_cluster_ha <vmware_cluster_ha_module>` and :ref:`vmware_cluster_vsan <vmware_cluster_vsan_module>` instead.

View file

@ -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 = {

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -19,8 +19,9 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
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

View file

@ -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 = """

View file

@ -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()

View file

@ -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

View file

@ -0,0 +1,3 @@
---
testcase: "[^_].*"
test_items: []

View file

@ -0,0 +1,2 @@
dependencies:
- prepare_vyos_tests

View file

@ -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

View file

@ -0,0 +1,2 @@
---
- { include: cli.yaml, tags: ['cli'] }

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,8 @@
---
- name: Remove Config
cli_config:
config: "{{ lines }}"
vars:
lines: |
delete service lldp interface
delete service lldp

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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'

View file

@ -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