[stable-2.9] Standardize eos resource modules (#61736)

* Fix eos_l3_interfaces case sensitivity

* Unify EOS module notes

* Add normalize_interfaces to eos_l2_interfaces

* Pull normalize_interface into eos_interfaces

* Add normalize_interface to lag_interfaces

* Add normalize_interface to lldp_interfaces

* Add normalize_interface to lacp_interfaces

* more module cleanup

* Add changelog
(cherry picked from commit 7917d4def7)

Co-authored-by: Nathaniel Case <ncase@redhat.com>
This commit is contained in:
Nathaniel Case 2019-09-13 09:35:50 -04:00 committed by Toshio Kuratomi
parent f082d23eec
commit 9d6282e633
23 changed files with 350 additions and 265 deletions

View file

@ -0,0 +1,3 @@
bugfixes:
- Remove case sensitivity on interface names from eos_interfaces, eos_l2_interfaces, eos_l3_interfaces,
eos_lacp_interfaces, eos_lag_interfaces, and eos_lldp_interfaces.

View file

@ -1,6 +1,7 @@
# -*- 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)
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The eos_interfaces class
It is in this file where the current configuration (as dict)
@ -12,10 +13,10 @@ created
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.module_utils.network.common.utils import to_list, param_list_to_dict
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.common.utils import to_list, dict_diff, param_list_to_dict
from ansible.module_utils.network.eos.facts.facts import Facts
from ansible.module_utils.network.eos.utils.utils import normalize_interface
class Interfaces(ConfigBase):
@ -93,148 +94,143 @@ class Interfaces(ConfigBase):
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
state = self._module.params['state']
want = param_list_to_dict(want)
have = param_list_to_dict(have)
state = self._module.params['state']
if state == 'overridden':
commands = state_overridden(want, have)
commands = self._state_overridden(want, have)
elif state == 'deleted':
commands = state_deleted(want, have)
commands = self._state_deleted(want, have)
elif state == 'merged':
commands = state_merged(want, have)
commands = self._state_merged(want, have)
elif state == 'replaced':
commands = state_replaced(want, have)
commands = self._state_replaced(want, have)
return commands
@staticmethod
def _state_replaced(want, have):
""" The command generator when state is replaced
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
commands = []
for key, desired in want.items():
interface_name = normalize_interface(key)
if interface_name in have:
extant = have[interface_name]
else:
extant = dict()
add_config = dict_diff(extant, desired)
del_config = dict_diff(desired, extant)
commands.extend(generate_commands(key, add_config, del_config))
return commands
@staticmethod
def _state_overridden(want, have):
""" The command generator when state is overridden
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
commands = []
for key, extant in have.items():
if key in want:
desired = want[key]
else:
desired = dict()
add_config = dict_diff(extant, desired)
del_config = dict_diff(desired, extant)
commands.extend(generate_commands(key, add_config, del_config))
return commands
@staticmethod
def _state_merged(want, have):
""" The command generator when state is merged
:rtype: A list
:returns: the commands necessary to merge the provided into
the current configuration
"""
commands = []
for key, desired in want.items():
interface_name = normalize_interface(key)
if interface_name in have:
extant = have[interface_name]
else:
extant = dict()
add_config = dict_diff(extant, desired)
commands.extend(generate_commands(key, add_config, {}))
return commands
@staticmethod
def _state_deleted(want, have):
""" The command generator when state is deleted
:rtype: A list
:returns: the commands necessary to remove the current configuration
of the provided objects
"""
commands = []
for key in want:
desired = dict()
if key in have:
extant = have[key]
else:
continue
del_config = dict_diff(desired, extant)
commands.extend(generate_commands(key, {}, del_config))
return commands
def state_replaced(want, have):
""" The command generator when state is replaced
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
commands = _compute_commands(want, have, replace=True, remove=True)
replace = commands['replace']
remove = commands['remove']
commands_by_interface = replace
for interface, commands in remove.items():
commands_by_interface[interface] = replace.get(interface, []) + commands
return _flatten_commands(commands_by_interface)
def state_overridden(want, have):
""" The command generator when state is overridden
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
# Add empty desired state for unspecified interfaces
for key in have:
if key not in want:
want[key] = {}
# Otherwise it's the same as replaced
return state_replaced(want, have)
def state_merged(want, have):
""" The command generator when state is merged
:rtype: A list
:returns: the commands necessary to merge the provided into
the current configuration
"""
commands = _compute_commands(want, have, replace=True)
return _flatten_commands(commands['replace'])
def state_deleted(want, have):
""" The command generator when state is deleted
:rtype: A list
:returns: the commands necessary to remove the current configuration
of the provided objects
"""
commands = _compute_commands(want, have, remove=True)
return _flatten_commands(commands['remove'])
def _compute_commands(want, have, replace=False, remove=False):
replace_params = {}
remove_params = {}
for name, config in want.items():
extant = have.get(name, {})
if remove:
remove_params[name] = dict(set(extant.items()).difference(config.items()))
if replace:
replace_params[name] = dict(set(config.items()).difference(extant.items()))
if remove:
# We won't need to also clear the configuration if we've
# already set it to something
for param in replace_params[name]:
remove_params[name].pop(param, None)
returns = {}
if replace:
returns['replace'] = _replace_config(replace_params)
if remove:
returns['remove'] = _remove_config(remove_params)
return returns
def _remove_config(params):
"""
Generates commands to reset config to defaults based on keys provided.
"""
commands = {}
for interface, config in params.items():
interface_commands = []
for param in config:
if param == 'enabled':
interface_commands.append('no shutdown')
elif param in ('description', 'mtu'):
interface_commands.append('no {0}'.format(param))
elif param == 'speed':
interface_commands.append('speed auto')
if interface_commands:
commands[interface] = interface_commands
return commands
def _replace_config(params):
"""
Generates commands to replace config to new values based on provided dictionary.
"""
commands = {}
for interface, config in params.items():
interface_commands = []
for param, state in config.items():
if param == 'description':
interface_commands.append('description "{0}"'.format(state))
elif param == 'enabled':
interface_commands.append('{0}shutdown'.format('no ' if state else ''))
elif param == 'mtu':
interface_commands.append('mtu {0}'.format(state))
if 'speed' in config:
interface_commands.append('speed {0}{1}'.format(config['speed'], config['duplex']))
if interface_commands:
commands[interface] = interface_commands
return commands
def _flatten_commands(command_dict):
def generate_commands(interface, to_set, to_remove):
commands = []
for interface, interface_commands in command_dict.items():
commands.append('interface {0}'.format(interface))
commands.extend(interface_commands)
for key, value in to_set.items():
if value is None:
continue
if key == "enabled":
commands.append('{0}shutdown'.format('no ' if value else ''))
elif key == "speed":
if value == "auto":
commands.append("{0} {1}".format(key, value))
else:
commands.append('speed {0}{1}'.format(value, to_set['duplex']))
elif key == "duplex":
# duplex is handled with speed
continue
else:
commands.append("{0} {1}".format(key, value))
# Don't try to also remove the same key, if present in to_remove
to_remove.pop(key, None)
for key in to_remove.keys():
if key == "enabled":
commands.append('no shutdown')
elif key == "speed":
commands.append("speed auto")
elif key == "duplex":
# duplex is handled with speed
continue
else:
commands.append("no {0}".format(key))
if commands:
commands.insert(0, "interface {0}".format(interface))
return commands

View file

@ -1,6 +1,7 @@
# -*- 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)
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The eos_l2_interfaces class
It is in this file where the current configuration (as dict)
@ -12,10 +13,10 @@ created
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.common.utils import to_list, param_list_to_dict
from ansible.module_utils.network.eos.facts.facts import Facts
from ansible.module_utils.network.eos.utils.utils import normalize_interface
class L2_interfaces(ConfigBase):
@ -94,6 +95,8 @@ class L2_interfaces(ConfigBase):
to the desired configuration
"""
state = self._module.params['state']
want = param_list_to_dict(want)
have = param_list_to_dict(have)
if state == 'overridden':
commands = self._state_overridden(want, have)
elif state == 'deleted':
@ -113,15 +116,20 @@ class L2_interfaces(ConfigBase):
to the desired configuration
"""
commands = []
for interface in want:
for extant in have:
if extant['name'] == interface['name']:
break
for key, desired in want.items():
interface_name = normalize_interface(key)
if interface_name in have:
extant = have[interface_name]
else:
continue
extant = dict()
intf_commands = set_interface(desired, extant)
intf_commands.extend(clear_interface(desired, extant))
if intf_commands:
commands.append("interface {0}".format(interface_name))
commands.extend(intf_commands)
commands.extend(clear_interface(interface, extant))
commands.extend(set_interface(interface, extant))
return commands
@staticmethod
@ -133,19 +141,19 @@ class L2_interfaces(ConfigBase):
to the desired configuration
"""
commands = []
for extant in have:
for interface in want:
if extant['name'] == interface['name']:
break
for key, extant in have.items():
if key in want:
desired = want[key]
else:
# We didn't find a matching desired state, which means we can
# pretend we recieved an empty desired state.
interface = dict(name=extant['name'])
commands.extend(clear_interface(interface, extant))
continue
desired = dict()
intf_commands = set_interface(desired, extant)
intf_commands.extend(clear_interface(desired, extant))
if intf_commands:
commands.append("interface {0}".format(key))
commands.extend(intf_commands)
commands.extend(clear_interface(interface, extant))
commands.extend(set_interface(interface, extant))
return commands
@staticmethod
@ -157,14 +165,18 @@ class L2_interfaces(ConfigBase):
the current configuration
"""
commands = []
for interface in want:
for extant in have:
if extant['name'] == interface['name']:
break
for key, desired in want.items():
interface_name = normalize_interface(key)
if interface_name in have:
extant = have[interface_name]
else:
continue
extant = dict()
commands.extend(set_interface(interface, extant))
intf_commands = set_interface(desired, extant)
if intf_commands:
commands.append("interface {0}".format(interface_name))
commands.extend(intf_commands)
return commands
@ -177,29 +189,31 @@ class L2_interfaces(ConfigBase):
of the provided objects
"""
commands = []
for interface in want:
for extant in have:
if extant['name'] == interface['name']:
break
for key in want:
desired = dict()
if key in have:
extant = have[key]
else:
continue
# Use an empty configuration, just in case
interface = dict(name=interface['name'])
commands.extend(clear_interface(interface, extant))
intf_commands = clear_interface(desired, extant)
if intf_commands:
commands.append("interface {0}".format(key))
commands.extend(intf_commands)
return commands
def set_interface(want, have):
commands = []
wants_access = want["access"]
wants_access = want.get("access")
if wants_access:
access_vlan = wants_access.get("vlan")
if access_vlan and access_vlan != have.get("access", {}).get("vlan"):
commands.append("switchport access vlan {0}".format(access_vlan))
wants_trunk = want["trunk"]
wants_trunk = want.get("trunk")
if wants_trunk:
has_trunk = have.get("trunk", {})
native_vlan = wants_trunk.get("native_vlan")
@ -210,9 +224,6 @@ def set_interface(want, have):
if allowed_vlans:
allowed_vlans = ','.join(allowed_vlans)
commands.append("switchport trunk allowed vlan {0}".format(allowed_vlans))
if commands:
commands.insert(0, "interface {0}".format(want['name']))
return commands
@ -227,7 +238,4 @@ def clear_interface(want, have):
commands.append("no switchport trunk allowed vlan")
if "native_vlan" in has_trunk and "native_vlan" not in wants_trunk:
commands.append("no switchport trunk native vlan")
if commands:
commands.insert(0, "interface {0}".format(want["name"]))
return commands

View file

@ -13,10 +13,10 @@ created
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.common.utils import to_list, param_list_to_dict
from ansible.module_utils.network.eos.facts.facts import Facts
from ansible.module_utils.network.eos.utils.utils import normalize_interface
class L3_interfaces(ConfigBase):
@ -95,6 +95,8 @@ class L3_interfaces(ConfigBase):
to the desired configuration
"""
state = self._module.params['state']
want = param_list_to_dict(want)
have = param_list_to_dict(have)
if state == 'overridden':
commands = self._state_overridden(want, have)
elif state == 'deleted':
@ -114,18 +116,18 @@ class L3_interfaces(ConfigBase):
to the desired configuration
"""
commands = []
for interface in want:
for extant in have:
if interface["name"] == extant["name"]:
break
for key, desired in want.items():
interface_name = normalize_interface(key)
if interface_name in have:
extant = have[interface_name]
else:
extant = dict(name=interface["name"])
extant = dict()
intf_commands = set_interface(interface, extant)
intf_commands.extend(clear_interface(interface, extant))
intf_commands = set_interface(desired, extant)
intf_commands.extend(clear_interface(desired, extant))
if intf_commands:
commands.append("interface {0}".format(interface["name"]))
commands.append("interface {0}".format(interface_name))
commands.extend(intf_commands)
return commands
@ -139,22 +141,21 @@ class L3_interfaces(ConfigBase):
to the desired configuration
"""
commands = []
for extant in have:
for interface in want:
if extant["name"] == interface["name"]:
break
for key, extant in have.items():
if key in want:
desired = want[key]
else:
interface = dict(name=extant["name"])
if interface.get("ipv4"):
for ipv4 in interface["ipv4"]:
desired = dict()
if desired.get("ipv4"):
for ipv4 in desired["ipv4"]:
if ipv4["secondary"] is None:
del ipv4["secondary"]
intf_commands = set_interface(interface, extant)
intf_commands.extend(clear_interface(interface, extant))
intf_commands = set_interface(desired, extant)
intf_commands.extend(clear_interface(desired, extant))
if intf_commands:
commands.append("interface {0}".format(interface["name"]))
commands.append("interface {0}".format(key))
commands.extend(intf_commands)
return commands
@ -168,17 +169,17 @@ class L3_interfaces(ConfigBase):
the current configuration
"""
commands = []
for interface in want:
for extant in have:
if extant["name"] == interface["name"]:
break
for key, desired in want.items():
interface_name = normalize_interface(key)
if interface_name in have:
extant = have[interface_name]
else:
extant = dict(name=interface["name"])
extant = dict()
intf_commands = set_interface(interface, extant)
intf_commands = set_interface(desired, extant)
if intf_commands:
commands.append("interface {0}".format(interface["name"]))
commands.append("interface {0}".format(interface_name))
commands.extend(intf_commands)
return commands
@ -192,19 +193,17 @@ class L3_interfaces(ConfigBase):
of the provided objects
"""
commands = []
for interface in want:
for extant in have:
if extant["name"] == interface["name"]:
break
for key in want:
desired = dict()
if key in have:
extant = have[key]
else:
continue
# Clearing all args, send empty dictionary
interface = dict(name=interface["name"])
intf_commands = clear_interface(interface, extant)
intf_commands = clear_interface(desired, extant)
if intf_commands:
commands.append("interface {0}".format(interface["name"]))
commands.append("interface {0}".format(key))
commands.extend(intf_commands)
return commands
@ -244,7 +243,7 @@ def clear_interface(want, have):
if not want_ipv4:
commands.append("no ip address")
else:
for address in (have_ipv4 - want_ipv4):
for address in have_ipv4 - want_ipv4:
address = dict(address)
if "secondary" not in address:
address["secondary"] = False

View file

@ -1,4 +1,3 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
@ -17,6 +16,7 @@ __metaclass__ = type
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.common.utils import to_list, dict_diff, param_list_to_dict
from ansible.module_utils.network.eos.facts.facts import Facts
from ansible.module_utils.network.eos.utils.utils import normalize_interface
class Lacp_interfaces(ConfigBase):
@ -33,9 +33,6 @@ class Lacp_interfaces(ConfigBase):
'lacp_interfaces',
]
def __init__(self, module):
super(Lacp_interfaces, self).__init__(module)
def get_lacp_interfaces_facts(self):
""" Get the 'facts' (the current configuration)
@ -120,8 +117,9 @@ class Lacp_interfaces(ConfigBase):
"""
commands = []
for key, desired in want.items():
if key in have:
extant = have[key]
interface_name = normalize_interface(key)
if interface_name in have:
extant = have[interface_name]
else:
extant = dict()
@ -164,8 +162,9 @@ class Lacp_interfaces(ConfigBase):
"""
commands = []
for key, desired in want.items():
if key in have:
extant = have[key]
interface_name = normalize_interface(key)
if interface_name in have:
extant = have[interface_name]
else:
extant = dict()
@ -184,12 +183,12 @@ class Lacp_interfaces(ConfigBase):
of the provided objects
"""
commands = []
for key in want.keys():
for key in want:
desired = dict()
if key in have:
extant = have[key]
else:
extant = dict()
continue
del_config = dict_diff(desired, extant)

View file

@ -17,6 +17,7 @@ from ansible.module_utils.network.common.utils import to_list, dict_diff
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.eos.facts.facts import Facts
from ansible.module_utils.network.eos.utils.utils import normalize_interface
class Lag_interfaces(ConfigBase):
@ -114,11 +115,12 @@ class Lag_interfaces(ConfigBase):
"""
commands = []
for interface in want:
interface_name = normalize_interface(interface["name"])
for extant in have:
if extant["name"] == interface["name"]:
if extant["name"] == interface_name:
break
else:
extant = dict(name=interface["name"])
extant = dict(name=interface_name)
commands.extend(set_config(interface, extant))
commands.extend(remove_config(interface, extant))
@ -135,18 +137,19 @@ class Lag_interfaces(ConfigBase):
commands = []
for extant in have:
for interface in want:
if interface["name"] == extant["name"]:
if normalize_interface(interface["name"]) == extant["name"]:
break
else:
interface = dict(name=extant["name"])
commands.extend(remove_config(interface, extant))
for interface in want:
interface_name = normalize_interface(interface["name"])
for extant in have:
if extant["name"] == interface["name"]:
if extant["name"] == interface_name:
break
else:
extant = dict(name=interface["name"])
extant = dict(name=interface_name)
commands.extend(set_config(interface, extant))
return commands
@ -160,11 +163,12 @@ class Lag_interfaces(ConfigBase):
"""
commands = []
for interface in want:
interface_name = normalize_interface(interface["name"])
for extant in have:
if extant["name"] == interface["name"]:
if extant["name"] == interface_name:
break
else:
extant = dict(name=interface["name"])
extant = dict(name=interface_name)
commands.extend(set_config(interface, extant))
@ -179,14 +183,15 @@ class Lag_interfaces(ConfigBase):
"""
commands = []
for interface in want:
interface_name = normalize_interface(interface["name"])
for extant in have:
if extant["name"] == interface["name"]:
if extant["name"] == interface_name:
break
else:
continue
extant = dict(name=interface_name)
# Clearing all args, send empty dictionary
interface = dict(name=interface["name"])
interface = dict(name=interface_name)
commands.extend(remove_config(interface, extant))
return commands

View file

@ -1,4 +1,3 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
@ -17,6 +16,7 @@ __metaclass__ = type
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.common.utils import to_list, dict_diff, param_list_to_dict
from ansible.module_utils.network.eos.facts.facts import Facts
from ansible.module_utils.network.eos.utils.utils import normalize_interface
class Lldp_interfaces(ConfigBase):
@ -117,15 +117,16 @@ class Lldp_interfaces(ConfigBase):
"""
commands = []
for key, desired in want.items():
if key in have:
extant = have[key]
interface_name = normalize_interface(key)
if interface_name in have:
extant = have[interface_name]
else:
extant = dict(name=key)
extant = dict(name=interface_name)
add_config = dict_diff(extant, desired)
del_config = dict_diff(desired, extant)
commands.extend(generate_commands(key, add_config, del_config))
commands.extend(generate_commands(interface_name, add_config, del_config))
return commands
@ -161,14 +162,15 @@ class Lldp_interfaces(ConfigBase):
"""
commands = []
for key, desired in want.items():
if key in have:
extant = have[key]
interface_name = normalize_interface(key)
if interface_name in have:
extant = have[interface_name]
else:
extant = dict(name=key)
extant = dict(name=interface_name)
add_config = dict_diff(extant, desired)
commands.extend(generate_commands(key, add_config, {}))
commands.extend(generate_commands(interface_name, add_config, {}))
return commands
@ -182,15 +184,16 @@ class Lldp_interfaces(ConfigBase):
"""
commands = []
for key in want.keys():
desired = dict(name=key)
if key in have:
extant = have[key]
interface_name = normalize_interface(key)
desired = dict(name=interface_name)
if interface_name in have:
extant = have[interface_name]
else:
extant = dict(name=key)
continue
del_config = dict_diff(desired, extant)
commands.extend(generate_commands(key, {}, del_config))
commands.extend(generate_commands(interface_name, {}, del_config))
return commands

View file

@ -1,6 +1,7 @@
# -*- 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)
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The eos interfaces fact class
It is in this file the configuration is collected from the device
@ -40,6 +41,7 @@ class InterfacesFacts(object):
""" Populate the facts for interfaces
:param connection: the device connection
:param ansible_facts: Facts dictionary
:param data: previously collected configuration
:rtype: dictionary
:returns: facts
@ -55,9 +57,8 @@ class InterfacesFacts(object):
obj = self.render_config(self.generated_spec, conf)
if obj:
objs.append(obj)
facts = {}
facts = {'interfaces': []}
if objs:
facts['interfaces'] = []
params = utils.validate_config(self.argument_spec, {'config': objs})
for cfg in params['config']:
facts['interfaces'].append(utils.remove_empties(cfg))

View file

@ -1,6 +1,7 @@
# -*- 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)
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The eos l2_interfaces fact class
It is in this file the configuration is collected from the device
@ -39,9 +40,9 @@ class L2_interfacesFacts(object):
def populate_facts(self, connection, ansible_facts, data=None):
""" Populate the facts for l2_interfaces
:param module: the module instance
:param connection: the device connection
:param data: previously collected conf
:param ansible_facts: Facts dictionary
:param data: previously collected configuration
:rtype: dictionary
:returns: facts
"""

View file

@ -40,11 +40,11 @@ class L3_interfacesFacts(object):
def populate_facts(self, connection, ansible_facts, data=None):
""" Populate the facts for l3_interfaces
:param connection: the device connection
:param ansible_facts: Facts dictionary
:param data: previously collected configuration
:rtype: dictionary
:returns: facts
"""
if not data:
data = connection.get('show running-config | section ^interface')

View file

@ -41,7 +41,7 @@ class LacpFacts(object):
""" Populate the facts for lacp
:param connection: the device connection
:param ansible_facts: Facts dictionary
:param data: previously collected conf
:param data: previously collected configuration
:rtype: dictionary
:returns: facts
"""

View file

@ -1,4 +1,3 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
@ -42,7 +41,7 @@ class Lacp_interfacesFacts(object):
""" Populate the facts for lacp_interfaces
:param connection: the device connection
:param ansible_facts: Facts dictionary
:param data: previously collected conf
:param data: previously collected configuration
:rtype: dictionary
:returns: facts
"""

View file

@ -40,6 +40,7 @@ class Lag_interfacesFacts(object):
def populate_facts(self, connection, ansible_facts, data=None):
""" Populate the facts for lag_interfaces
:param connection: the device connection
:param ansible_facts: Facts dictionary
:param data: previously collected configuration
:rtype: dictionary
:returns: facts
@ -69,7 +70,7 @@ class Lag_interfacesFacts(object):
else:
objs[group_name] = obj
objs = list(objs.values())
facts = {}
facts = {'lag_interfaces': []}
if objs:
params = utils.validate_config(self.argument_spec, {'config': objs})
facts['lag_interfaces'] = [utils.remove_empties(cfg) for cfg in params['config']]

View file

@ -1,4 +1,3 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
@ -42,7 +41,7 @@ class Lldp_interfacesFacts(object):
""" Populate the facts for lldp_interfaces
:param connection: the device connection
:param ansible_facts: Facts dictionary
:param data: previously collected conf
:param data: previously collected configuration
:rtype: dictionary
:returns: facts
"""

View file

@ -0,0 +1,54 @@
# -*- 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)
# utils
from __future__ import absolute_import, division, print_function
__metaclass__ = type
def get_interface_number(name):
digits = ''
for char in name:
if char.isdigit() or char in '/.':
digits += char
return digits
def normalize_interface(name):
"""Return the normalized interface name
"""
if not name:
return None
if name.lower().startswith('et'):
if_type = 'Ethernet'
elif name.lower().startswith('lo'):
if_type = 'Loopback'
elif name.lower().startswith('ma'):
if_type = 'Management'
elif name.lower().startswith('po'):
if_type = 'Port-Channel'
elif name.lower().startswith('tu'):
if_type = 'Tunnel'
elif name.lower().startswith('vl'):
if_type = 'Vlan'
elif name.lower().startswith('vx'):
if_type = 'Vxlan'
else:
if_type = None
number_list = name.split(' ')
if len(number_list) == 2:
number = number_list[-1].strip()
else:
number = get_interface_number(name)
if if_type:
proper_interface = if_type + number
else:
proper_interface = name
return proper_interface

View file

@ -1,7 +1,8 @@
#!/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)
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
##############################################
# WARNING #
@ -41,6 +42,10 @@ version_added: 2.9
short_description: Manages interface attributes of Arista EOS interfaces
description: ['This module manages the interface attributes of Arista EOS interfaces.']
author: ['Nathaniel Case (@qalthos)']
notes:
- Tested against Arista EOS 4.20.10M
- This module works with connection C(network_cli). See the
L(EOS Platform Options,../network/user_guide/platform_eos.html).
options:
config:
description: The provided configuration

View file

@ -43,7 +43,7 @@ short_description: 'Manages L3 interface attributes of Arista EOS devices.'
description: 'This module provides declarative management of Layer 3 interfaces on Arista EOS devices.'
author: Nathaniel Case (@qalthos)
notes:
- 'Tested against vEOS v4.20.x'
- Tested against Arista EOS 4.20.10M
- This module works with connection C(network_cli). See the
L(EOS Platform Options,../network/user_guide/platform_eos.html).
options:

View file

@ -43,6 +43,10 @@ short_description: Manage Link Aggregation Control Protocol (LACP) attributes of
description:
- This module manages Link Aggregation Control Protocol (LACP) attributes of interfaces on Arista EOS devices.
author: Nathaniel Case (@Qalthos)
notes:
- Tested against Arista EOS 4.20.10M
- This module works with connection C(network_cli). See the
L(EOS Platform Options,../network/user_guide/platform_eos.html).
options:
config:
description: A dictionary of LACP interfaces options.

View file

@ -44,7 +44,7 @@ short_description: Manages link aggregation groups on Arista EOS devices
description: This module manages attributes of link aggregation groups on Arista EOS devices.
author: Nathaniel Case (@Qalthos)
notes:
- 'Tested against vEOS v4.20.x'
- Tested against Arista EOS 4.20.10M
- This module works with connection C(network_cli). See the
L(EOS Platform Options,../network/user_guide/platform_eos.html).
options:

View file

@ -43,6 +43,10 @@ short_description: Manage Global Link Layer Discovery Protocol (LLDP) settings o
description:
- This module manages Global Link Layer Discovery Protocol (LLDP) settings on Arista EOS devices.
author: Nathaniel Case (@Qalthos)
notes:
- Tested against Arista EOS 4.20.10M
- This module works with connection C(network_cli). See the
L(EOS Platform Options,../network/user_guide/platform_eos.html).
options:
config:
description: The provided global LLDP configuration.

View file

@ -43,6 +43,10 @@ short_description: Manage Link Layer Discovery Protocol (LLDP) attributes of int
description:
- This module manages Link Layer Discovery Protocol (LLDP) attributes of interfaces on Arista EOS devices.
author: Nathaniel Case (@Qalthos)
notes:
- Tested against Arista EOS 4.20.10M
- This module works with connection C(network_cli). See the
L(EOS Platform Options,../network/user_guide/platform_eos.html).
options:
config:
description: A dictionary of LLDP interfaces options.

View file

@ -26,4 +26,4 @@
- assert:
that:
- "'lag_interfaces' not in ansible_facts.network_resources"
- "ansible_facts.network_resources.lag_interfaces == []"