diff options
Diffstat (limited to 'lib/ansible/modules')
29 files changed, 0 insertions, 10846 deletions
diff --git a/lib/ansible/modules/network/eos/_eos_interface.py b/lib/ansible/modules/network/eos/_eos_interface.py deleted file mode 100644 index c6f08ed63f..0000000000 --- a/lib/ansible/modules/network/eos/_eos_interface.py +++ /dev/null @@ -1,486 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2017, Ansible by Red Hat, inc -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['deprecated'], - 'supported_by': 'network'} - - -DOCUMENTATION = """ ---- -module: eos_interface -version_added: "2.5" -author: "Ganesh Nalawade (@ganeshrn)" -short_description: Manage Interface on Arista EOS network devices -description: - - This module provides declarative management of Interfaces - on Arista EOS network devices. -deprecated: - removed_in: "2.13" - alternative: eos_interfaces - why: Updated modules released with more functionality -notes: - - Tested against EOS 4.15 -options: - name: - description: - - Name of the Interface to be configured on remote device. The name of interface - should be in expanded format and not abbreviated. - type: str - required: true - description: - description: - - Description of Interface upto 240 characters. - type: str - enabled: - description: - - Interface link status. If the value is I(True) the interface state will be - enabled, else if value is I(False) interface will be in disable (shutdown) state. - default: True - type: bool - speed: - description: - - This option configures autoneg and speed/duplex/flowcontrol for the interface - given in C(name) option. - type: str - mtu: - description: - - Set maximum transmission unit size in bytes of transmit packet for the interface given - in C(name) option. - type: str - tx_rate: - description: - - Transmit rate in bits per second (bps) for the interface given in C(name) option. - - This is state check parameter only. - - Supports conditionals, see L(Conditionals in Networking Modules,../network/user_guide/network_working_with_command_output.html) - type: str - rx_rate: - description: - - Receiver rate in bits per second (bps) for the interface given in C(name) option. - - This is state check parameter only. - - Supports conditionals, see L(Conditionals in Networking Modules,../network/user_guide/network_working_with_command_output.html) - type: str - neighbors: - description: - - Check the operational state of given interface C(name) for LLDP neighbor. - - The following suboptions are available. - type: list - suboptions: - host: - description: - - "LLDP neighbor host for given interface C(name)." - port: - description: - - "LLDP neighbor port to which given interface C(name) is connected." - aggregate: - description: - - List of Interfaces definitions. Each of the entry in aggregate list should - define name of interface C(name) and other options as required. - type: list - delay: - description: - - Time in seconds to wait before checking for the operational state on remote - device. This wait is applicable for operational state argument which are - I(state) with values C(up)/C(down), I(tx_rate) and I(rx_rate). - default: 10 - type: int - state: - description: - - State of the Interface configuration, C(up) means present and - operationally up and C(down) means present and operationally C(down) - default: present - type: str - choices: ['present', 'absent', 'up', 'down'] -extends_documentation_fragment: eos -""" - -EXAMPLES = """ -- name: configure interface - eos_interface: - name: ethernet1 - description: test-interface - speed: 100full - mtu: 512 - -- name: remove interface - eos_interface: - name: ethernet1 - state: absent - -- name: make interface up - eos_interface: - name: ethernet1 - enabled: True - -- name: make interface down - eos_interface: - name: ethernet1 - enabled: False - -- name: Check intent arguments - eos_interface: - name: ethernet1 - state: up - tx_rate: ge(0) - rx_rate: le(0) - -- name: Check neighbors intent arguments - eos_interface: - name: ethernet1 - neighbors: - - port: eth0 - host: netdev - -- name: Configure interface in disabled state and check if the operational state is disabled or not - eos_interface: - name: ethernet1 - enabled: False - state: down - -- name: Add interface using aggregate - eos_interface: - aggregate: - - { name: ethernet1, mtu: 256, description: test-interface-1 } - - { name: ethernet2, mtu: 516, description: test-interface-2 } - speed: 100full - state: present - -- name: Delete interface using aggregate - eos_interface: - aggregate: - - name: loopback9 - - name: loopback10 - state: absent -""" - -RETURN = """ -commands: - description: The list of configuration mode commands to send to the device. - returned: always, except for the platforms that use Netconf transport to manage the device. - type: list - sample: - - interface ethernet1 - - description test-interface - - speed 100full - - mtu 512 -""" -import re -from copy import deepcopy -from time import sleep - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.common.config import NetworkConfig -from ansible.module_utils.network.common.utils import conditional, remove_default_spec -from ansible.module_utils.network.eos.eos import get_config, load_config, run_commands -from ansible.module_utils.network.eos.eos import eos_argument_spec - - -def validate_mtu(value, module): - if value and not 68 <= int(value) <= 65535: - module.fail_json(msg='mtu must be between 68 and 65535') - - -def validate_param_values(module, obj, param=None): - if param is None: - param = module.params - for key in obj: - # validate the param value (if validator func exists) - validator = globals().get('validate_%s' % key) - if callable(validator): - validator(param.get(key), module) - - -def parse_shutdown(configobj, name): - cfg = configobj['interface %s' % name] - cfg = '\n'.join(cfg.children) - match = re.search(r'shutdown', cfg, re.M) - return bool(match) - - -def parse_config_argument(configobj, name, arg=None): - cfg = configobj['interface %s' % name] - cfg = '\n'.join(cfg.children) - match = re.search(r'%s (.+)$' % arg, cfg, re.M) - if match: - return match.group(1) - - -def search_obj_in_list(name, lst): - for o in lst: - if o['name'] == name: - return o - - return None - - -def add_command_to_interface(interface, cmd, commands): - if interface not in commands: - commands.append(interface) - commands.append(cmd) - - -def map_config_to_obj(module): - config = get_config(module) - configobj = NetworkConfig(indent=3, contents=config) - - match = re.findall(r'^interface (\S+)', config, re.M) - if not match: - return list() - - instances = list() - - for item in set(match): - obj = { - 'name': item.lower(), - 'description': parse_config_argument(configobj, item, 'description'), - 'speed': parse_config_argument(configobj, item, 'speed'), - 'mtu': parse_config_argument(configobj, item, 'mtu'), - 'disable': parse_shutdown(configobj, item), - 'state': 'present' - } - instances.append(obj) - return instances - - -def map_params_to_obj(module): - obj = [] - aggregate = module.params.get('aggregate') - if aggregate: - for item in aggregate: - for key in item: - if item.get(key) is None: - item[key] = module.params[key] - - item['name'] = item['name'].lower() - validate_param_values(module, item, item) - d = item.copy() - - if d['enabled']: - d['disable'] = False - else: - d['disable'] = True - - obj.append(d) - - else: - params = { - 'name': module.params['name'].lower(), - 'description': module.params['description'], - 'speed': module.params['speed'], - 'mtu': module.params['mtu'], - 'state': module.params['state'], - 'delay': module.params['delay'], - 'tx_rate': module.params['tx_rate'], - 'rx_rate': module.params['rx_rate'], - 'neighbors': module.params['neighbors'] - } - - validate_param_values(module, params) - if module.params['enabled']: - params.update({'disable': False}) - else: - params.update({'disable': True}) - - obj.append(params) - return obj - - -def map_obj_to_commands(updates, modules): - commands = list() - want, have = updates - - args = ('speed', 'description', 'mtu') - for w in want: - name = w['name'] - disable = w['disable'] - state = w['state'] - - obj_in_have = search_obj_in_list(name, have) - interface = 'interface ' + name - - if state == 'absent' and obj_in_have: - commands.append('no ' + interface) - - elif state in ('present', 'up', 'down'): - if obj_in_have: - for item in args: - candidate = w.get(item) - running = obj_in_have.get(item) - if candidate != running: - if candidate: - cmd = "{0} {1}".format(item, candidate) - add_command_to_interface(interface, cmd, commands) - - if disable and not obj_in_have.get('disable', False): - add_command_to_interface(interface, 'shutdown', commands) - elif not disable and obj_in_have.get('disable', False): - add_command_to_interface(interface, 'no shutdown', commands) - else: - commands.append(interface) - for item in args: - value = w.get(item) - if value: - commands.append("{0} {1}".format(item, value)) - - if disable: - commands.append('no shutdown') - return commands - - -def check_declarative_intent_params(module, want, result): - failed_conditions = [] - have_neighbors = None - for w in want: - want_state = w.get('state') - want_tx_rate = w.get('tx_rate') - want_rx_rate = w.get('rx_rate') - want_neighbors = w.get('neighbors') - - if want_state not in ('up', 'down') and not want_tx_rate and not want_rx_rate and not want_neighbors: - continue - - if result['changed']: - sleep(w['delay']) - - command = {'command': 'show interfaces %s' % w['name'], 'output': 'text'} - output = run_commands(module, [command]) - - if want_state in ('up', 'down'): - match = re.search(r'%s (\w+)' % 'line protocol is', output[0], re.M) - have_state = None - if match: - have_state = match.group(1) - if have_state is None or not conditional(want_state, have_state.strip()): - failed_conditions.append('state ' + 'eq(%s)' % want_state) - - if want_tx_rate: - match = re.search(r'%s (\d+)' % 'output rate', output[0], re.M) - have_tx_rate = None - if match: - have_tx_rate = match.group(1) - - if have_tx_rate is None or not conditional(want_tx_rate, have_tx_rate.strip(), cast=int): - failed_conditions.append('tx_rate ' + want_tx_rate) - - if want_rx_rate: - match = re.search(r'%s (\d+)' % 'input rate', output[0], re.M) - have_rx_rate = None - if match: - have_rx_rate = match.group(1) - - if have_rx_rate is None or not conditional(want_rx_rate, have_rx_rate.strip(), cast=int): - failed_conditions.append('rx_rate ' + want_rx_rate) - - if want_neighbors: - have_host = [] - have_port = [] - if have_neighbors is None: - command = {'command': 'show lldp neighbors {0}'.format(w['name']), 'output': 'text'} - have_neighbors = run_commands(module, [command]) - - if have_neighbors[0]: - lines = have_neighbors[0].strip().split('\n') - col = None - for index, line in enumerate(lines): - if re.search(r"^Port\s+Neighbor Device ID\s+Neighbor Port ID\s+TTL", line): - col = index - break - - if col and col < len(lines) - 1: - for items in lines[col + 1:]: - value = re.split(r'\s+', items) - try: - have_port.append(value[2]) - have_host.append(value[1]) - except IndexError: - pass - - for item in want_neighbors: - host = item.get('host') - port = item.get('port') - if host and host not in have_host: - failed_conditions.append('host ' + host) - if port and port not in have_port: - failed_conditions.append('port ' + port) - return failed_conditions - - -def main(): - """ main entry point for module execution - """ - neighbors_spec = dict( - host=dict(), - port=dict() - ) - - element_spec = dict( - name=dict(), - description=dict(), - speed=dict(), - mtu=dict(), - enabled=dict(default=True, type='bool'), - tx_rate=dict(), - rx_rate=dict(), - neighbors=dict(type='list', elements='dict', options=neighbors_spec), - delay=dict(default=10, type='int'), - state=dict(default='present', - choices=['present', 'absent', 'up', 'down']) - ) - - aggregate_spec = deepcopy(element_spec) - aggregate_spec['name'] = dict(required=True) - - # remove default in aggregate spec, to handle common arguments - remove_default_spec(aggregate_spec) - - argument_spec = dict( - aggregate=dict(type='list', elements='dict', options=aggregate_spec), - ) - - argument_spec.update(element_spec) - argument_spec.update(eos_argument_spec) - - required_one_of = [['name', 'aggregate']] - mutually_exclusive = [['name', 'aggregate']] - - module = AnsibleModule(argument_spec=argument_spec, - required_one_of=required_one_of, - mutually_exclusive=mutually_exclusive, - supports_check_mode=True) - - warnings = list() - result = {'changed': False} - if warnings: - result['warnings'] = warnings - - want = map_params_to_obj(module) - have = map_config_to_obj(module) - commands = map_obj_to_commands((want, have), module) - result['commands'] = commands - - if commands: - commit = not module.check_mode - response = load_config(module, commands, commit=commit) - if response.get('diff') and module._diff: - result['diff'] = {'prepared': response.get('diff')} - result['session_name'] = response.get('session') - result['changed'] = True - - failed_conditions = check_declarative_intent_params(module, want, result) - - if failed_conditions: - msg = 'One or more conditional statements have not been satisfied' - module.fail_json(msg=msg, failed_conditions=failed_conditions) - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/_eos_l2_interface.py b/lib/ansible/modules/network/eos/_eos_l2_interface.py deleted file mode 100644 index 82c10982f2..0000000000 --- a/lib/ansible/modules/network/eos/_eos_l2_interface.py +++ /dev/null @@ -1,324 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# (c) 2017, Ansible by Red Hat, inc -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['deprecated'], - 'supported_by': 'network'} - -DOCUMENTATION = """ ---- -module: eos_l2_interface -version_added: "2.5" -author: "Ricardo Carrillo Cruz (@rcarrillocruz)" -short_description: Manage L2 interfaces on Arista EOS network devices. -description: - - This module provides declarative management of L2 interfaces - on Arista EOS network devices. -deprecated: - removed_in: "2.13" - alternative: eos_l2_interfaces - why: Updated modules released with more functionality -notes: - - Tested against EOS 4.15 -options: - name: - description: - - Name of the interface - required: true - aliases: ['interface'] - mode: - description: - - Mode in which interface needs to be configured. - choices: ['access','trunk'] - access_vlan: - description: - - Configure given VLAN in access port. - If C(mode=access), used as the access VLAN ID. - native_vlan: - description: - - Native VLAN to be configured in trunk port. - If C(mode=trunk), used as the trunk native VLAN ID. - trunk_allowed_vlans: - description: - - List of allowed VLANs in a given trunk port. - If C(mode=trunk), these are the ONLY VLANs that will be - configured on the trunk, i.e. C(2-10,15). - aliases: ['trunk_vlans'] - aggregate: - description: - - List of Layer-2 interface definitions. - state: - description: - - Manage the state of the Layer-2 Interface configuration. - default: present - choices: ['present','absent', 'unconfigured'] -extends_documentation_fragment: eos -""" - -EXAMPLES = """ -- name: Ensure Ethernet1 does not have any switchport - eos_l2_interface: - name: Ethernet1 - state: absent - -- name: Ensure Ethernet1 is configured for access vlan 20 - eos_l2_interface: - name: Ethernet1 - mode: access - access_vlan: 20 - -- name: Ensure Ethernet1 is a trunk port and ensure 2-50 are being tagged (doesn't mean others aren't also being tagged) - eos_l2_interface: - name: Ethernet1 - mode: trunk - native_vlan: 10 - trunk_allowed_vlans: 2-50 - -- name: Set switchports on aggregate - eos_l2_interface: - aggregate: - - { name: ethernet1, mode: access, access_vlan: 20} - - { name: ethernet2, mode: trunk, native_vlan: 10} -""" - -RETURN = """ -commands: - description: The list of configuration mode commands to send to the device - returned: always. - type: list - sample: - - interface ethernet1 - - switchport access vlan 20 -""" -import re -from copy import deepcopy - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.common.config import NetworkConfig -from ansible.module_utils.network.common.utils import remove_default_spec -from ansible.module_utils.network.eos.eos import get_config, load_config, run_commands -from ansible.module_utils.network.eos.eos import eos_argument_spec - - -def parse_config_argument(configobj, name, arg=None): - cfg = configobj['interface %s' % name] - cfg = '\n'.join(cfg.children) - match = re.search(r'%s (.+)$' % arg, cfg, re.M) - if match: - return match.group(1).strip() - - -def search_obj_in_list(name, lst): - for o in lst: - if o['name'] == name: - return o - - return None - - -def map_obj_to_commands(want, have, module): - commands = list() - - for w in want: - name = w['name'] - state = w['state'] - mode = w['mode'] - access_vlan = w['access_vlan'] - native_vlan = w['native_vlan'] - trunk_allowed_vlans = w['trunk_allowed_vlans'] - - interface = 'interface ' + name - commands.append(interface) - - obj_in_have = search_obj_in_list(name, have) - if not obj_in_have: - module.fail_json(msg='invalid interface {0}'.format(name)) - - if state == 'absent': - if obj_in_have['mode'] == 'access': - commands.append('no switchport access vlan {0}'.format(obj_in_have['access_vlan'])) - - if obj_in_have['mode'] == 'trunk': - commands.append('no switchport mode trunk') - - if obj_in_have['native_vlan']: - commands.append('no switchport trunk native vlan {0}'.format(obj_in_have['native_vlan'])) - - if obj_in_have['trunk_allowed_vlans']: - commands.append('no switchport trunk allowed vlan {0}'.format(obj_in_have['trunk_allowed_vlans'])) - - if obj_in_have['state'] == 'present': - commands.append('no switchport') - else: - if obj_in_have['state'] == 'absent': - commands.append('switchport') - commands.append('switchport mode {0}'.format(mode)) - - if access_vlan: - commands.append('switchport access vlan {0}'.format(access_vlan)) - - if native_vlan: - commands.append('switchport trunk native vlan {0}'.format(native_vlan)) - - if trunk_allowed_vlans: - commands.append('switchport trunk allowed vlan {0}'.format(trunk_allowed_vlans)) - else: - if mode != obj_in_have['mode']: - if obj_in_have['mode'] == 'access': - commands.append('no switchport access vlan {0}'.format(obj_in_have['access_vlan'])) - commands.append('switchport mode trunk') - if native_vlan: - commands.append('switchport trunk native vlan {0}'.format(native_vlan)) - if trunk_allowed_vlans: - commands.append('switchport trunk allowed vlan {0}'.format(trunk_allowed_vlans)) - else: - if obj_in_have['native_vlan']: - commands.append('no switchport trunk native vlan {0}'.format(obj_in_have['native_vlan'])) - commands.append('no switchport mode trunk') - if obj_in_have['trunk_allowed_vlans']: - commands.append('no switchport trunk allowed vlan {0}'.format(obj_in_have['trunk_allowed_vlans'])) - commands.append('no switchport mode trunk') - commands.append('switchport access vlan {0}'.format(access_vlan)) - else: - if mode == 'access': - if access_vlan != obj_in_have['access_vlan']: - commands.append('switchport access vlan {0}'.format(access_vlan)) - else: - if native_vlan != obj_in_have['native_vlan'] and native_vlan: - commands.append('switchport trunk native vlan {0}'.format(native_vlan)) - if trunk_allowed_vlans != obj_in_have['trunk_allowed_vlans'] and trunk_allowed_vlans: - commands.append('switchport trunk allowed vlan {0}'.format(trunk_allowed_vlans)) - - if commands[-1] == interface: - commands.pop(-1) - - return commands - - -def map_config_to_obj(module, warnings): - config = get_config(module, flags=['| section interface']) - configobj = NetworkConfig(indent=3, contents=config) - - match = re.findall(r'^interface (\S+)', config, re.M) - if not match: - return list() - - instances = list() - - for item in set(match): - command = {'command': 'show interfaces {0} switchport | include Switchport'.format(item), - 'output': 'text'} - command_result = run_commands(module, command, check_rc=False) - if "Interface does not exist" in command_result[0]: - warnings.append("Could not gather switchport information for {0}: {1}".format(item, command_result[0])) - continue - - if command_result[0]: - switchport_cfg = command_result[0].split(':')[1].strip() - - if switchport_cfg == 'Enabled': - state = 'present' - else: - state = 'absent' - - obj = { - 'name': item.lower(), - 'state': state, - 'access_vlan': parse_config_argument(configobj, item, 'switchport access vlan'), - 'native_vlan': parse_config_argument(configobj, item, 'switchport trunk native vlan'), - 'trunk_allowed_vlans': parse_config_argument(configobj, item, 'switchport trunk allowed vlan'), - } - if obj['access_vlan']: - obj['mode'] = 'access' - else: - obj['mode'] = 'trunk' - - instances.append(obj) - - return instances - - -def map_params_to_obj(module): - obj = [] - - aggregate = module.params.get('aggregate') - if aggregate: - for item in aggregate: - for key in item: - if item.get(key) is None: - item[key] = module.params[key] - - item['name'] = item['name'].lower() - obj.append(item.copy()) - else: - obj.append({ - 'name': module.params['name'].lower(), - 'mode': module.params['mode'], - 'access_vlan': module.params['access_vlan'], - 'native_vlan': module.params['native_vlan'], - 'trunk_allowed_vlans': module.params['trunk_allowed_vlans'], - 'state': module.params['state'] - }) - - return obj - - -def main(): - """ main entry point for module execution - """ - element_spec = dict( - name=dict(type='str', aliases=['interface']), - mode=dict(choices=['access', 'trunk']), - access_vlan=dict(type='str'), - native_vlan=dict(type='str'), - trunk_allowed_vlans=dict(type='str', aliases=['trunk_vlans']), - state=dict(default='present', - choices=['present', 'absent']) - ) - - aggregate_spec = deepcopy(element_spec) - aggregate_spec['name'] = dict(required=True) - - # remove default in aggregate spec, to handle common arguments - remove_default_spec(aggregate_spec) - - argument_spec = dict( - aggregate=dict(type='list', elements='dict', options=aggregate_spec), - ) - - argument_spec.update(element_spec) - argument_spec.update(eos_argument_spec) - - module = AnsibleModule(argument_spec=argument_spec, - mutually_exclusive=[['access_vlan', 'native_vlan'], - ['access_vlan', 'trunk_allowed_vlans']], - supports_check_mode=True) - - warnings = list() - result = {'changed': False, 'warnings': warnings} - - want = map_params_to_obj(module) - have = map_config_to_obj(module, warnings) - commands = map_obj_to_commands(want, have, module) - result['commands'] = commands - - if commands: - commit = not module.check_mode - response = load_config(module, commands, commit=commit) - if response.get('diff') and module._diff: - result['diff'] = {'prepared': response.get('diff')} - result['session_name'] = response.get('session') - result['changed'] = True - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/_eos_l3_interface.py b/lib/ansible/modules/network/eos/_eos_l3_interface.py deleted file mode 100644 index e6941db908..0000000000 --- a/lib/ansible/modules/network/eos/_eos_l3_interface.py +++ /dev/null @@ -1,302 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2017, Ansible by Red Hat, inc -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['deprecated'], - 'supported_by': 'network'} - -DOCUMENTATION = """ ---- -module: eos_l3_interface -version_added: "2.5" -author: "Ganesh Nalawade (@ganeshrn)" -short_description: Manage L3 interfaces on Arista EOS network devices. -description: - - This module provides declarative management of L3 interfaces - on Arista EOS network devices. -deprecated: - removed_in: "2.13" - alternative: eos_l3_interfaces - why: Updated modules released with more functionality -notes: - - Tested against EOS 4.15 -options: - name: - description: - - Name of the L3 interface to be configured eg. ethernet1 - ipv4: - description: - - IPv4 address to be set for the L3 interface mentioned in I(name) option. - The address format is <ipv4 address>/<mask>, the mask is number - in range 0-32 eg. 192.168.0.1/24 - ipv6: - description: - - IPv6 address to be set for the L3 interface mentioned in I(name) option. - The address format is <ipv6 address>/<mask>, the mask is number - in range 0-128 eg. fd5d:12c9:2201:1::1/64 - - aggregate: - description: - - List of L3 interfaces definitions. Each of the entry in aggregate list should - define name of interface C(name) and a optional C(ipv4) or C(ipv6) address. - state: - description: - - State of the L3 interface configuration. It indicates if the configuration should - be present or absent on remote device. - default: present - choices: ['present', 'absent'] -extends_documentation_fragment: eos -""" - -EXAMPLES = """ -- name: Remove ethernet1 IPv4 and IPv6 address - eos_l3_interface: - name: ethernet1 - state: absent - -- name: Set ethernet1 IPv4 address - eos_l3_interface: - name: ethernet1 - ipv4: 192.168.0.1/24 - -- name: Set ethernet1 IPv6 address - eos_l3_interface: - name: ethernet1 - ipv6: "fd5d:12c9:2201:1::1/64" - -- name: Set interface Vlan1 (SVI) IPv4 address - eos_l3_interface: - name: Vlan1 - ipv4: 192.168.0.5/24 - -- name: Set IP addresses on aggregate - eos_l3_interface: - aggregate: - - { name: ethernet1, ipv4: 192.168.2.10/24 } - - { name: ethernet1, ipv4: 192.168.3.10/24, ipv6: "fd5d:12c9:2201:1::1/64" } - -- name: Remove IP addresses on aggregate - eos_l3_interface: - aggregate: - - { name: ethernet1, ipv4: 192.168.2.10/24 } - - { name: ethernet1, ipv4: 192.168.3.10/24, ipv6: "fd5d:12c9:2201:1::1/64" } - state: absent -""" - -RETURN = """ -commands: - description: The list of configuration mode commands to send to the device - returned: always, except for the platforms that use Netconf transport to manage the device. - type: list - sample: - - interface ethernet1 - - ip address 192.168.0.1/24 - - ipv6 address fd5d:12c9:2201:1::1/64 -""" -import re -from copy import deepcopy - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.common.config import NetworkConfig -from ansible.module_utils.network.common.utils import remove_default_spec -from ansible.module_utils.network.eos.eos import get_config, load_config -from ansible.module_utils.network.eos.eos import eos_argument_spec -from ansible.module_utils.network.common.utils import is_masklen - - -def validate_ipv4(value, module): - if value: - address = value.split('/') - if len(address) != 2: - module.fail_json(msg='address format is <ipv4 address>/<mask>, got invalid format %s' % value) - - if not is_masklen(address[1]): - module.fail_json(msg='invalid value for mask: %s, mask should be in range 0-32' % address[1]) - - -def validate_ipv6(value, module): - if value: - address = value.split('/') - if len(address) != 2: - module.fail_json(msg='address format is <ipv6 address>/<mask>, got invalid format %s' % value) - else: - if not 0 <= int(address[1]) <= 128: - module.fail_json(msg='invalid value for mask: %s, mask should be in range 0-128' % address[1]) - - -def validate_param_values(module, obj, param=None): - if param is None: - param = module.params - for key in obj: - # validate the param value (if validator func exists) - validator = globals().get('validate_%s' % key) - if callable(validator): - validator(param.get(key), module) - - -def parse_config_argument(configobj, name, arg=None): - cfg = configobj['interface %s' % name] - cfg = '\n'.join(cfg.children) - match = re.search(r'%s (.+)$' % arg, cfg, re.M) - if match: - return match.group(1).strip() - - -def search_obj_in_list(name, lst): - for o in lst: - if o['name'] == name: - return o - - return None - - -def map_obj_to_commands(updates, module): - commands = list() - want, have = updates - - for w in want: - name = w['name'] - ipv4 = w['ipv4'] - ipv6 = w['ipv6'] - state = w['state'] - - interface = 'interface ' + name - commands.append(interface) - - obj_in_have = search_obj_in_list(name, have) - if state == 'absent' and obj_in_have: - if obj_in_have['ipv4']: - if ipv4: - commands.append('no ip address {0}'.format(ipv4)) - else: - commands.append('no ip address') - if obj_in_have['ipv6']: - if ipv6: - commands.append('no ipv6 address {0}'.format(ipv6)) - else: - commands.append('no ipv6 address') - - elif state == 'present': - if ipv4: - if obj_in_have is None or obj_in_have['ipv4'] is None or ipv4 != obj_in_have['ipv4']: - commands.append('ip address {0}'.format(ipv4)) - - if ipv6: - if obj_in_have is None or obj_in_have['ipv6'] is None or ipv6.lower() != obj_in_have['ipv6'].lower(): - commands.append('ipv6 address {0}'.format(ipv6)) - - if commands[-1] == interface: - commands.pop(-1) - - return commands - - -def map_config_to_obj(module): - config = get_config(module, flags=['| section interface']) - configobj = NetworkConfig(indent=3, contents=config) - - match = re.findall(r'^interface (\S+)', config, re.M) - if not match: - return list() - - instances = list() - - for item in set(match): - obj = { - 'name': item.lower(), - 'ipv4': parse_config_argument(configobj, item, 'ip address'), - 'ipv6': parse_config_argument(configobj, item, 'ipv6 address'), - 'state': 'present' - } - instances.append(obj) - - return instances - - -def map_params_to_obj(module): - obj = [] - - aggregate = module.params.get('aggregate') - if aggregate: - for item in aggregate: - for key in item: - if item.get(key) is None: - item[key] = module.params[key] - - item['name'] = item['name'].lower() - validate_param_values(module, item, item) - obj.append(item.copy()) - else: - obj.append({ - 'name': module.params['name'].lower(), - 'ipv4': module.params['ipv4'], - 'ipv6': module.params['ipv6'], - 'state': module.params['state'] - }) - - validate_param_values(module, obj) - - return obj - - -def main(): - """ main entry point for module execution - """ - element_spec = dict( - name=dict(), - ipv4=dict(), - ipv6=dict(), - state=dict(default='present', - choices=['present', 'absent']) - ) - - aggregate_spec = deepcopy(element_spec) - aggregate_spec['name'] = dict(required=True) - - # remove default in aggregate spec, to handle common arguments - remove_default_spec(aggregate_spec) - - argument_spec = dict( - aggregate=dict(type='list', elements='dict', options=aggregate_spec), - ) - - argument_spec.update(element_spec) - argument_spec.update(eos_argument_spec) - - required_one_of = [['name', 'aggregate']] - mutually_exclusive = [['name', 'aggregate']] - module = AnsibleModule(argument_spec=argument_spec, - required_one_of=required_one_of, - mutually_exclusive=mutually_exclusive, - supports_check_mode=True) - - warnings = list() - result = {'changed': False} - if warnings: - result['warnings'] = warnings - - want = map_params_to_obj(module) - have = map_config_to_obj(module) - commands = map_obj_to_commands((want, have), module) - result['commands'] = commands - - if commands: - commit = not module.check_mode - response = load_config(module, commands, commit=commit) - if response.get('diff') and module._diff: - result['diff'] = {'prepared': response.get('diff')} - result['session_name'] = response.get('session') - result['changed'] = True - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/_eos_linkagg.py b/lib/ansible/modules/network/eos/_eos_linkagg.py deleted file mode 100644 index 4750413bc0..0000000000 --- a/lib/ansible/modules/network/eos/_eos_linkagg.py +++ /dev/null @@ -1,354 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2017, Ansible by Red Hat, inc -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['deprecated'], - 'supported_by': 'network'} - -DOCUMENTATION = """ ---- -module: eos_linkagg -version_added: "2.5" -author: "Trishna Guha (@trishnaguha)" -short_description: Manage link aggregation groups on Arista EOS network devices -description: - - This module provides declarative management of link aggregation groups - on Arista EOS network devices. -deprecated: - removed_in: "2.13" - alternative: eos_lag_interfaces - why: Updated modules released with more functionality -notes: - - Tested against EOS 4.15 -options: - group: - description: - - Channel-group number for the port-channel - Link aggregation group. Range 1-2000. - mode: - description: - - Mode of the link aggregation group. - choices: ['active', 'on', 'passive'] - members: - description: - - List of members of the link aggregation group. - min_links: - description: - - Minimum number of ports required up - before bringing up the link aggregation group. - aggregate: - description: List of link aggregation definitions. - state: - description: - - State of the link aggregation group. - default: present - choices: ['present', 'absent'] - purge: - description: - - Purge links not defined in the I(aggregate) parameter. - default: no - type: bool -extends_documentation_fragment: eos -""" - -EXAMPLES = """ -- name: create link aggregation group - eos_linkagg: - group: 10 - state: present - -- name: delete link aggregation group - eos_linkagg: - group: 10 - state: absent - -- name: set link aggregation group to members - eos_linkagg: - group: 200 - min_links: 3 - mode: active - members: - - Ethernet0 - - Ethernet1 - -- name: remove link aggregation group from Ethernet0 - eos_linkagg: - group: 200 - min_links: 3 - mode: active - members: - - Ethernet1 - -- name: Create aggregate of linkagg definitions - eos_linkagg: - aggregate: - - { group: 3, mode: on, members: [Ethernet1] } - - { group: 100, mode: passive, min_links: 3, members: [Ethernet2] } - -- name: Remove aggregate of linkagg definitions - eos_linkagg: - aggregate: - - { group: 3, mode: on, members: [Ethernet1] } - - { group: 100, mode: passive, min_links: 3, members: [Ethernet2] } - state: absent -""" - -RETURN = """ -commands: - description: The list of configuration mode commands to send to the device - returned: always, except for the platforms that use Netconf transport to manage the device. - type: list - sample: - - interface port-channel 30 - - port-channel min-links 5 - - interface Ethernet3 - - channel-group 30 mode on - - no interface port-channel 30 -""" - -import re -from copy import deepcopy - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.common.utils import remove_default_spec -from ansible.module_utils.network.eos.eos import get_config, load_config -from ansible.module_utils.network.eos.eos import eos_argument_spec - - -def search_obj_in_list(group, lst): - for o in lst: - if o['group'] == group: - return o - - -def map_obj_to_commands(updates, module): - commands = list() - want, have = updates - purge = module.params['purge'] - - for w in want: - group = w['group'] - mode = w['mode'] - min_links = w['min_links'] - members = w.get('members') or [] - state = w['state'] - del w['state'] - - obj_in_have = search_obj_in_list(group, have) - - if state == 'absent': - if obj_in_have: - commands.append('no interface port-channel {0}'.format(group)) - - elif state == 'present': - cmd = ['interface port-channel {0}'.format(group), - 'end'] - if not obj_in_have: - if not group: - module.fail_json(msg='group is a required option') - commands.extend(cmd) - - if min_links != 'None': - commands.append('port-channel min-links {0}'.format(min_links)) - - if members: - for m in members: - commands.append('interface {0}'.format(m)) - commands.append('channel-group {0} mode {1}'.format(group, mode)) - - else: - if members: - if 'members' not in obj_in_have.keys(): - for m in members: - commands.extend(cmd) - commands.append('interface {0}'.format(m)) - commands.append('channel-group {0} mode {1}'.format(group, mode)) - - elif set(members) != set(obj_in_have['members']): - missing_members = list(set(members) - set(obj_in_have['members'])) - for m in missing_members: - commands.extend(cmd) - commands.append('interface {0}'.format(m)) - commands.append('channel-group {0} mode {1}'.format(group, mode)) - - superfluous_members = list(set(obj_in_have['members']) - set(members)) - for m in superfluous_members: - commands.extend(cmd) - commands.append('interface {0}'.format(m)) - commands.append('no channel-group {0}'.format(group)) - - if purge: - for h in have: - obj_in_want = search_obj_in_list(h['group'], want) - if not obj_in_want: - commands.append('no interface port-channel {0}'.format(h['group'])) - - return commands - - -def map_params_to_obj(module, required_together=None): - obj = [] - - aggregate = module.params.get('aggregate') - if aggregate: - for item in aggregate: - for key in item: - if item.get(key) is None: - item[key] = module.params[key] - - module._check_required_together(required_together, item) - d = item.copy() - d['group'] = str(d['group']) - d['min_links'] = str(d['min_links']) - - obj.append(d) - else: - obj.append({ - 'group': str(module.params['group']), - 'mode': module.params['mode'], - 'min_links': str(module.params['min_links']), - 'members': module.params['members'], - 'state': module.params['state'] - }) - - return obj - - -def parse_mode(group, member, config): - mode = None - - for line in config.strip().split('!'): - match_int = re.findall(r'interface {0}\\b'.format(member), line, re.M) - if match_int: - match = re.search(r'channel-group {0} mode (\S+)'.format(group), line, re.M) - if match: - mode = match.group(1) - - return mode - - -def parse_members(group, config): - members = [] - - for line in config.strip().split('!'): - match_group = re.findall(r'channel-group {0} mode'.format(group), line, re.M) - if match_group: - match = re.search(r'interface (\S+)', line, re.M) - if match: - members.append(match.group(1)) - - return members - - -def get_channel(group, module): - channel = {} - config = get_config(module, flags=['| section channel-group']) - - for line in config.split('\n'): - l = line.strip() - match = re.search(r'interface (\S+)', l, re.M) - - if match: - member = match.group(1) - channel['mode'] = parse_mode(group, member, config) - channel['members'] = parse_members(group, config) - - return channel - - -def parse_min_links(group, config): - min_links = '' - - for line in config.strip().split('!'): - match_pc = re.findall(r'interface Port-Channel{0}\\b'.format(group), line, re.M) - if match_pc: - match = re.search(r'port-channel min-links (\S+)', line, re.M) - if match: - min_links = match.group(1) - - return min_links - - -def map_config_to_obj(module): - objs = list() - config = get_config(module, flags=['| section port-channel']) - - for line in config.split('\n'): - l = line.strip() - match = re.search(r'interface Port-Channel(\S+)', l, re.M) - if match: - obj = {} - group = match.group(1) - obj['group'] = group - obj['min_links'] = parse_min_links(group, config) - obj.update(get_channel(group, module)) - objs.append(obj) - - return objs - - -def main(): - """ main entry point for module execution - """ - element_spec = dict( - group=dict(type='int'), - mode=dict(choices=['active', 'on', 'passive']), - min_links=dict(type='int'), - members=dict(type='list'), - state=dict(default='present', - choices=['present', 'absent']) - ) - - aggregate_spec = deepcopy(element_spec) - aggregate_spec['group'] = dict(required=True) - - # remove default in aggregate spec, to handle common arguments - remove_default_spec(aggregate_spec) - - argument_spec = dict( - aggregate=dict(type='list', elements='dict', options=aggregate_spec), - purge=dict(default=False, type='bool') - ) - - argument_spec.update(element_spec) - argument_spec.update(eos_argument_spec) - - required_one_of = [['group', 'aggregate']] - required_together = [['members', 'mode']] - mutually_exclusive = [['group', 'aggregate']] - module = AnsibleModule(argument_spec=argument_spec, - required_one_of=required_one_of, - required_together=required_together, - mutually_exclusive=mutually_exclusive, - supports_check_mode=True) - - warnings = list() - result = {'changed': False} - if warnings: - result['warnings'] = warnings - - want = map_params_to_obj(module) - have = map_config_to_obj(module) - commands = map_obj_to_commands((want, have), module) - result['commands'] = commands - - if commands: - commit = not module.check_mode - response = load_config(module, commands, commit=commit) - if response.get('diff') and module._diff: - result['diff'] = {'prepared': response.get('diff')} - result['session_name'] = response.get('session') - result['changed'] = True - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/_eos_static_route.py b/lib/ansible/modules/network/eos/_eos_static_route.py deleted file mode 100644 index ad244e4b35..0000000000 --- a/lib/ansible/modules/network/eos/_eos_static_route.py +++ /dev/null @@ -1,291 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2017, Ansible by Red Hat, inc -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['deprecated'], - 'supported_by': 'network'} - -DOCUMENTATION = """ ---- -module: eos_static_route -version_added: "2.5" -author: "Trishna Guha (@trishnaguha)" -short_description: Manage static IP routes on Arista EOS network devices -description: - - This module provides declarative management of static - IP routes on Arista EOS network devices. -deprecated: - removed_in: '2.13' - alternative: eos_static_routes - why: Updated modules with more functionality -notes: - - Tested against EOS 4.15 -options: - address: - description: - - Network address with prefix of the static route. - required: true - aliases: ['prefix'] - next_hop: - description: - - Next hop IP of the static route. - required: true - vrf: - description: - - VRF for static route. - default: default - version_added: 2.9 - admin_distance: - description: - - Admin distance of the static route. - default: 1 - aggregate: - description: List of static route definitions - state: - description: - - State of the static route configuration. - default: present - choices: ['present', 'absent'] -extends_documentation_fragment: eos -""" - -EXAMPLES = """ -- name: configure static route - eos_static_route: - address: 10.0.2.0/24 - next_hop: 10.8.38.1 - admin_distance: 2 -- name: delete static route - eos_static_route: - address: 10.0.2.0/24 - next_hop: 10.8.38.1 - state: absent -- name: configure static routes using aggregate - eos_static_route: - aggregate: - - { address: 10.0.1.0/24, next_hop: 10.8.38.1 } - - { address: 10.0.3.0/24, next_hop: 10.8.38.1 } -- name: Delete static route using aggregate - eos_static_route: - aggregate: - - { address: 10.0.1.0/24, next_hop: 10.8.38.1 } - - { address: 10.0.3.0/24, next_hop: 10.8.38.1 } - state: absent -""" - -RETURN = """ -commands: - description: The list of configuration mode commands to send to the device - returned: always - type: list - sample: - - ip route 10.0.2.0/24 10.8.38.1 3 - - no ip route 10.0.2.0/24 10.8.38.1 -""" - -import re - -from copy import deepcopy - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.common.utils import is_masklen, validate_ip_address -from ansible.module_utils.network.common.utils import remove_default_spec, validate_prefix -from ansible.module_utils.network.eos.eos import get_config, load_config -from ansible.module_utils.network.eos.eos import eos_argument_spec - - -def is_address(value): - if value: - address = value.split('/') - if is_masklen(address[1]) and validate_ip_address(address[0]): - return True - return False - - -def is_hop(value): - if value: - if validate_ip_address(value): - return True - return False - - -def map_obj_to_commands(updates, module): - commands = list() - want, have = updates - - for w in want: - address = w['address'] - next_hop = w['next_hop'] - admin_distance = w['admin_distance'] - vrf = w['vrf'] - state = w['state'] - del w['state'] - - if state == 'absent' and w in have: - if vrf == 'default': - commands.append('no ip route %s %s' % (address, next_hop)) - else: - commands.append('no ip route vrf %s %s %s' % (vrf, address, next_hop)) - elif state == 'present' and w not in have: - if vrf == 'default': - commands.append('ip route %s %s %d' % (address, next_hop, admin_distance)) - else: - commands.append('ip route vrf %s %s %s %d' % (vrf, address, next_hop, admin_distance)) - - return commands - - -def map_params_to_obj(module, required_together=None): - obj = [] - - aggregate = module.params.get('aggregate') - if aggregate: - for item in aggregate: - for key in item: - if item.get(key) is None: - item[key] = module.params[key] - - module._check_required_together(required_together, item) - d = item.copy() - - obj.append(d) - else: - obj.append({ - 'address': module.params['address'].strip(), - 'next_hop': module.params['next_hop'].strip(), - 'admin_distance': module.params['admin_distance'], - 'state': module.params['state'], - 'vrf': module.params['vrf'] - }) - - return obj - - -def map_config_to_obj(module): - objs = [] - - try: - out = get_config(module, flags=['| include ip.route']) - except IndexError: - out = '' - if out: - lines = out.splitlines() - for line in lines: - obj = {} - add_match = re.search(r'ip route ([\d\./]+)', line, re.M) - if add_match: - obj['vrf'] = 'default' - address = add_match.group(1) - if is_address(address): - obj['address'] = address - hop_match = re.search(r'ip route {0} ([\d\./]+)'.format(address), line, re.M) - if hop_match: - hop = hop_match.group(1) - if is_hop(hop): - obj['next_hop'] = hop - dist_match = re.search(r'ip route {0} {1} (\d+)'.format(address, hop), line, re.M) - if dist_match: - distance = dist_match.group(1) - obj['admin_distance'] = int(distance) - else: - obj['admin_distance'] = 1 - - vrf_match = re.search(r'ip route vrf ([\w]+) ([\d\./]+)', line, re.M) - if vrf_match: - vrf = vrf_match.group(1) - obj['vrf'] = vrf - address = vrf_match.group(2) - if is_address(address): - obj['address'] = address - hop_vrf_match = re.search(r'ip route vrf {0} {1} ([\d\./]+)'.format(vrf, address), line, re.M) - if hop_vrf_match: - hop = hop_vrf_match.group(1) - if is_hop(hop): - obj['next_hop'] = hop - dist_vrf_match = re.search(r'ip route vrf {0} {1} {2} (\d+)'.format(vrf, address, hop), line, re.M) - if dist_vrf_match: - distance = dist_vrf_match.group(1) - obj['admin_distance'] = int(distance) - else: - obj['admin_distance'] = 1 - - objs.append(obj) - - return objs - - -def main(): - """ main entry point for module execution - """ - element_spec = dict( - address=dict(type='str', aliases=['prefix']), - next_hop=dict(type='str'), - vrf=dict(type='str', default='default'), - admin_distance=dict(default=1, type='int'), - state=dict(default='present', choices=['present', 'absent']) - ) - - aggregate_spec = deepcopy(element_spec) - aggregate_spec['address'] = dict(required=True) - - # remove default in aggregate spec, to handle common arguments - remove_default_spec(aggregate_spec) - - argument_spec = dict( - aggregate=dict(type='list', elements='dict', options=aggregate_spec), - ) - - argument_spec.update(element_spec) - argument_spec.update(eos_argument_spec) - - required_one_of = [['aggregate', 'address']] - required_together = [['address', 'next_hop']] - mutually_exclusive = [['aggregate', 'address']] - - module = AnsibleModule(argument_spec=argument_spec, - required_one_of=required_one_of, - required_together=required_together, - mutually_exclusive=mutually_exclusive, - supports_check_mode=True) - - address = module.params['address'] - if address is not None: - prefix = address.split('/')[-1] - - if address and prefix: - if '/' not in address or not validate_ip_address(address.split('/')[0]): - module.fail_json(msg='{0} is not a valid IP address'.format(address)) - - if not validate_prefix(prefix): - module.fail_json(msg='Length of prefix should be between 0 and 32 bits') - - warnings = list() - result = {'changed': False} - if warnings: - result['warnings'] = warnings - - want = map_params_to_obj(module) - have = map_config_to_obj(module) - commands = map_obj_to_commands((want, have), module) - result['commands'] = commands - - if commands: - commit = not module.check_mode - response = load_config(module, commands, commit=commit) - if response.get('diff') and module._diff: - result['diff'] = {'prepared': response.get('diff')} - result['session_name'] = response.get('session') - result['changed'] = True - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/_eos_vlan.py b/lib/ansible/modules/network/eos/_eos_vlan.py deleted file mode 100644 index a38cd671d2..0000000000 --- a/lib/ansible/modules/network/eos/_eos_vlan.py +++ /dev/null @@ -1,356 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# (c) 2017, Ansible by Red Hat, inc -# -# This file is part of Ansible by Red Hat -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['deprecated'], - 'supported_by': 'network'} - - -DOCUMENTATION = """ ---- -module: eos_vlan -version_added: "2.4" -author: "Ricardo Carrillo Cruz (@rcarrillocruz)" -short_description: Manage VLANs on Arista EOS network devices -description: - - This module provides declarative management of VLANs - on Arista EOS network devices. -deprecated: - removed_in: "2.13" - alternative: eos_vlans - why: Updated modules released with more functionality -notes: - - Tested against EOS 4.15 -options: - name: - description: - - Name of the VLAN. - vlan_id: - description: - - ID of the VLAN. - required: true - interfaces: - description: - - List of interfaces that should be associated to the VLAN. The name of interface is - case sensitive and should be in expanded format and not abbreviated. - associated_interfaces: - description: - - This is a intent option and checks the operational state of the for given vlan C(name) - for associated interfaces. The name of interface is case sensitive and should be in - expanded format and not abbreviated. If the value in the C(associated_interfaces) - does not match with the operational state of vlan interfaces on device it will result in failure. - version_added: "2.5" - delay: - description: - - Delay the play should wait to check for declarative intent params values. - default: 10 - aggregate: - description: List of VLANs definitions. - purge: - description: - - Purge VLANs not defined in the I(aggregate) parameter. - default: no - type: bool - state: - description: - - State of the VLAN configuration. - default: present - choices: ['present', 'absent', 'active', 'suspend'] -extends_documentation_fragment: eos -""" - -EXAMPLES = """ -- name: Create vlan - eos_vlan: - vlan_id: 4000 - name: vlan-4000 - state: present - -- name: Add interfaces to vlan - eos_vlan: - vlan_id: 4000 - state: present - interfaces: - - Ethernet1 - - Ethernet2 - -- name: Check if interfaces is assigned to vlan - eos_vlan: - vlan_id: 4000 - associated_interfaces: - - Ethernet1 - - Ethernet2 - -- name: Suspend vlan - eos_vlan: - vlan_id: 4000 - state: suspend - -- name: Unsuspend vlan - eos_vlan: - vlan_id: 4000 - state: active - -- name: Create aggregate of vlans - eos_vlan: - aggregate: - - vlan_id: 4000 - - {vlan_id: 4001, name: vlan-4001} -""" - -RETURN = """ -commands: - description: The list of configuration mode commands to send to the device - returned: always - type: list - sample: - - vlan 20 - - name test-vlan -""" -import time - -from copy import deepcopy - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.common.utils import remove_default_spec -from ansible.module_utils.network.eos.eos import load_config, run_commands -from ansible.module_utils.network.eos.eos import eos_argument_spec - - -def search_obj_in_list(vlan_id, lst): - for o in lst: - if o['vlan_id'] == vlan_id: - return o - - -def map_obj_to_commands(updates, module): - commands = list() - want, have = updates - purge = module.params['purge'] - - for w in want: - vlan_id = w['vlan_id'] - state = w['state'] - - obj_in_have = search_obj_in_list(vlan_id, have) - - if state == 'absent': - if obj_in_have: - commands.append('no vlan %s' % w['vlan_id']) - elif state == 'present': - if not obj_in_have: - commands.append('vlan %s' % w['vlan_id']) - if w['name']: - commands.append('name %s' % w['name']) - - if w['interfaces']: - for i in w['interfaces']: - commands.append('interface %s' % i) - commands.append('switchport access vlan %s' % w['vlan_id']) - else: - if w['name'] and w['name'] != obj_in_have['name']: - commands.append('vlan %s' % w['vlan_id']) - commands.append('name %s' % w['name']) - - if w['interfaces']: - if not obj_in_have['interfaces']: - for i in w['interfaces']: - commands.append('vlan %s' % w['vlan_id']) - commands.append('interface %s' % i) - commands.append('switchport access vlan %s' % w['vlan_id']) - elif set(w['interfaces']) != obj_in_have['interfaces']: - missing_interfaces = list(set(w['interfaces']) - set(obj_in_have['interfaces'])) - for i in missing_interfaces: - commands.append('vlan %s' % w['vlan_id']) - commands.append('interface %s' % i) - commands.append('switchport access vlan %s' % w['vlan_id']) - - superfluous_interfaces = list(set(obj_in_have['interfaces']) - set(w['interfaces'])) - for i in superfluous_interfaces: - commands.append('vlan %s' % w['vlan_id']) - commands.append('interface %s' % i) - commands.append('no switchport access vlan %s' % w['vlan_id']) - else: - if not obj_in_have: - commands.append('vlan %s' % w['vlan_id']) - if w['name']: - commands.append('name %s' % w['name']) - commands.append('state %s' % w['state']) - elif (w['name'] and obj_in_have['name'] != w['name']) or obj_in_have['state'] != w['state']: - commands.append('vlan %s' % w['vlan_id']) - - if w['name']: - if obj_in_have['name'] != w['name']: - commands.append('name %s' % w['name']) - - if obj_in_have['state'] != w['state']: - commands.append('state %s' % w['state']) - - if purge: - for h in have: - obj_in_want = search_obj_in_list(h['vlan_id'], want) - if not obj_in_want and h['vlan_id'] != '1': - commands.append('no vlan %s' % h['vlan_id']) - - return commands - - -def map_config_to_obj(module): - objs = [] - vlans = run_commands(module, ['show vlan configured-ports | json']) - - for vlan in vlans[0]['vlans']: - obj = {} - obj['vlan_id'] = vlan - obj['name'] = vlans[0]['vlans'][vlan]['name'] - obj['state'] = vlans[0]['vlans'][vlan]['status'] - obj['interfaces'] = [] - - interfaces = vlans[0]['vlans'][vlan] - - for interface in interfaces['interfaces']: - obj['interfaces'].append(interface) - - if obj['state'] == 'suspended': - obj['state'] = 'suspend' - - objs.append(obj) - - return objs - - -def map_params_to_obj(module): - obj = [] - aggregate = module.params.get('aggregate') - if aggregate: - for item in aggregate: - for key in item: - if item.get(key) is None: - item[key] = module.params[key] - - if item.get('interfaces'): - item['interfaces'] = [intf.replace(" ", "") for intf in item.get('interfaces') if intf] - - if item.get('associated_interfaces'): - item['associated_interfaces'] = [intf.replace(" ", "") for intf in item.get('associated_interfaces') if intf] - - d = item.copy() - d['vlan_id'] = str(d['vlan_id']) - - obj.append(d) - else: - obj.append({ - 'vlan_id': str(module.params['vlan_id']), - 'name': module.params['name'], - 'state': module.params['state'], - 'interfaces': [intf.replace(" ", "") for intf in module.params['interfaces']] if module.params['interfaces'] else [], - 'associated_interfaces': [intf.replace(" ", "") for intf in - module.params['associated_interfaces']] if module.params['associated_interfaces'] else [] - - }) - - return obj - - -def check_declarative_intent_params(want, module, result): - have = None - is_delay = False - - for w in want: - if w.get('associated_interfaces') is None: - continue - - if result['changed'] and not is_delay: - time.sleep(module.params['delay']) - is_delay = True - - if have is None: - have = map_config_to_obj(module) - - for i in w['associated_interfaces']: - obj_in_have = search_obj_in_list(w['vlan_id'], have) - - if obj_in_have and 'interfaces' in obj_in_have and i not in obj_in_have['interfaces']: - module.fail_json(msg="Interface %s not configured on vlan %s" % (i, w['vlan_id'])) - - -def main(): - """ main entry point for module execution - """ - element_spec = dict( - vlan_id=dict(type='int'), - name=dict(), - interfaces=dict(type='list'), - associated_interfaces=dict(type='list'), - delay=dict(default=10, type='int'), - state=dict(default='present', - choices=['present', 'absent', 'active', 'suspend']) - ) - - aggregate_spec = deepcopy(element_spec) - aggregate_spec['vlan_id'] = dict(required=True) - - # remove default in aggregate spec, to handle common arguments - remove_default_spec(aggregate_spec) - - argument_spec = dict( - aggregate=dict(type='list', elements='dict', options=aggregate_spec), - purge=dict(default=False, type='bool') - ) - - argument_spec.update(element_spec) - argument_spec.update(eos_argument_spec) - - required_one_of = [['vlan_id', 'aggregate']] - mutually_exclusive = [['vlan_id', 'aggregate']] - module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True, - required_one_of=required_one_of, - mutually_exclusive=mutually_exclusive) - - warnings = list() - - result = {'changed': False} - - if warnings: - result['warnings'] = warnings - - want = map_params_to_obj(module) - have = map_config_to_obj(module) - - commands = map_obj_to_commands((want, have), module) - result['commands'] = commands - - if commands: - commit = not module.check_mode - response = load_config(module, commands, commit=commit) - if response.get('diff') and module._diff: - result['diff'] = {'prepared': response.get('diff')} - result['session_name'] = response.get('session') - result['changed'] = True - - check_declarative_intent_params(want, module, result) - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_acl_interfaces.py b/lib/ansible/modules/network/eos/eos_acl_interfaces.py deleted file mode 100644 index b9b16c6e5d..0000000000 --- a/lib/ansible/modules/network/eos/eos_acl_interfaces.py +++ /dev/null @@ -1,415 +0,0 @@ -#!/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 eos_acl_interfaces -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network' -} - -DOCUMENTATION = """ ---- -module: eos_acl_interfaces -version_added: "2.10" -short_description: Manage adding and removing Access Control Lists (ACLs) from interfaces on devices running EOS software. -description: - - This module manages adding and removing Access Control Lists (ACLs) from interfaces on devices running EOS software. -author: GomathiSelvi S (@GomathiselviS) -options: - config: - description: A dictionary of ACL options for interfaces. - type: list - elements: dict - suboptions: - name: - description: - - Name/Identifier for the interface. - type: str - required: True - access_groups: - type: list - elements: dict - description: - - Specifies ACLs attached to the interfaces. - suboptions: - afi: - description: - - Specifies the AFI for the ACL(s) to be configured on this interface. - type: str - choices: ['ipv4', 'ipv6'] - required: True - acls: - type: list - description: - - Specifies the ACLs for the provided AFI. - elements: dict - suboptions: - name: - description: - - Specifies the name of the IPv4/IPv4 ACL for the interface. - type: str - required: True - direction: - description: - - Specifies the direction of packets that the ACL will be applied on. - type: str - choices: ['in', 'out'] - required: True - running_config: - description: - - The module, by default, will connect to the remote device and - retrieve the current running-config to use as a base for comparing - against the contents of source. There are times when it is not - desirable to have the task get the current running-config for - every task in a playbook. The I(running_config) argument allows the - implementer to pass in the configuration to use as the base - config for comparison. This value of this option should be the - output received from device by executing command - version_added: "2.10" - type: str - state: - description: - - The state the configuration should be left in. - type: str - choices: - - merged - - replaced - - overridden - - deleted - - gathered - - parsed - - rendered - default: merged -""" -EXAMPLES = """ -# Using Merged - -# Before state: -# ------------- -# -# eos#sh running-config | include interface|access-group -# interface Ethernet1 -# interface Ethernet2 -# interface Ethernet3 - -- name: "Merge module attributes of given access-groups" - eos_acl_interfaces: - config: - - name: Ethernet2 - access_groups: - - afi: ipv4 - acls: - name: acl01 - direction: in - - afi: ipv6 - acls: - name: acl03 - direction: out - state: merged - -# Commands Fired: -# --------------- -# -# interface Ethernet2 -# ip access-group acl01 in -# ipv6 access-group acl03 out - -# After state: -# ------------- -# -# eos#sh running-config | include interface| access-group -# interface Loopback888 -# interface Ethernet1 -# interface Ethernet2 -# ip access-group acl01 in -# ipv6 access-group acl03 out -# interface Ethernet3 - - -# Using Replaced - -# Before state: -# ------------- -# -# eos#sh running-config | include interface|access-group -# interface Ethernet1 -# interface Ethernet2 -# ip access-group acl01 in -# ipv6 access-group acl03 out -# interface Ethernet3 -# ip access-group acl01 in - -- name: "Replace module attributes of given access-groups" - eos_acl_interfaces: - config: - - name: Ethernet2 - access_groups: - - afi: ipv4 - acls: - name: acl01 - direction: out - state: replaced - -# Commands Fired: -# --------------- -# -# interface Ethernet2 -# no ip access-group acl01 in -# no ipv6 access-group acl03 out -# ip access-group acl01 out - -# After state: -# ------------- -# -# eos#sh running-config | include interface| access-group -# interface Loopback888 -# interface Ethernet1 -# interface Ethernet2 -# ip access-group acl01 out -# interface Ethernet3 -# ip access-group acl01 in - - -# Using Overridden - -# Before state: -# ------------- -# -# eos#sh running-config | include interface|access-group -# interface Ethernet1 -# interface Ethernet2 -# ip access-group acl01 in -# ipv6 access-group acl03 out -# interface Ethernet3 -# ip access-group acl01 in - -- name: "Override module attributes of given access-groups" - eos_acl_interfaces: - config: - - name: Ethernet2 - access_groups: - - afi: ipv4 - acls: - name: acl01 - direction: out - state: overridden - -# Commands Fired: -# --------------- -# -# interface Ethernet2 -# no ip access-group acl01 in -# no ipv6 access-group acl03 out -# ip access-group acl01 out -# interface Ethernet3 -# no ip access-group acl01 in - -# After state: -# ------------- -# -# eos#sh running-config | include interface| access-group -# interface Loopback888 -# interface Ethernet1 -# interface Ethernet2 -# ip access-group acl01 out -# interface Ethernet3 - - -# Using Deleted - -# Before state: -# ------------- -# -# eos#sh running-config | include interface|access-group -# interface Ethernet1 -# interface Ethernet2 -# ip access-group acl01 in -# ipv6 access-group acl03 out -# interface Ethernet3 -# ip access-group acl01 out - -- name: "Delete module attributes of given access-groups" - eos_acl_interfaces: - config: - - name: Ethernet2 - access_groups: - - afi: ipv4 - acls: - name: acl01 - direction: in - - afi: ipv6 - acls: - name: acl03 - direction: out - state: deleted - -# Commands Fired: -# --------------- -# -# interface Ethernet2 -# no ip access-group acl01 in -# no ipv6 access-group acl03 out - -# After state: -# ------------- -# -# eos#sh running-config | include interface| access-group -# interface Loopback888 -# interface Ethernet1 -# interface Ethernet2 -# interface Ethernet3 -# ip access-group acl01 out - - -# Before state: -# ------------- -# -# eos#sh running-config | include interface| access-group -# interface Ethernet1 -# interface Ethernet2 -# ip access-group acl01 in -# ipv6 access-group acl03 out -# interface Ethernet3 -# ip access-group acl01 out - -- name: "Delete module attributes of given access-groups from ALL Interfaces" - eos_acl_interfaces: - config: - state: deleted - -# Commands Fired: -# --------------- -# -# interface Ethernet2 -# no ip access-group acl01 in -# no ipv6 access-group acl03 out -# interface Ethernet3 -# no ip access-group acl01 out - -# After state: -# ------------- -# -# eos#sh running-config | include interface| access-group -# interface Loopback888 -# interface Ethernet1 -# interface Ethernet2 -# interface Ethernet3 - -# Before state: -# ------------- -# -# eos#sh running-config | include interface| access-group -# interface Ethernet1 -# interface Ethernet2 -# ip access-group acl01 in -# ipv6 access-group acl03 out -# interface Ethernet3 -# ip access-group acl01 out - -- name: "Delete acls under afi" - eos_acl_interfaces: - config: - - name: Ethernet3 - access_groups: - - afi: "ipv4" - - name: Ethernet2 - access_groups: - - afi: "ipv6" - state: deleted - -# Commands Fired: -# --------------- -# -# interface Ethernet2 -# no ipv6 access-group acl03 out -# interface Ethernet3 -# no ip access-group acl01 out - -# After state: -# ------------- -# -# eos#sh running-config | include interface| access-group -# interface Loopback888 -# interface Ethernet1 -# interface Ethernet2 -# ip access-group acl01 in -# interface Ethernet3 - - -""" -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: - - interface Ethernet2 - - ip access-group acl01 in - - ipv6 access-group acl03 out - - interface Ethernet3 - - ip access-group acl01 out -""" - - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.argspec.acl_interfaces.acl_interfaces import Acl_interfacesArgs -from ansible.module_utils.network.eos.config.acl_interfaces.acl_interfaces import Acl_interfaces - - -def main(): - """ - Main entry point for module execution - - :returns: the result form module invocation - """ - module = AnsibleModule(argument_spec=Acl_interfacesArgs.argument_spec, - supports_check_mode=True) - - result = Acl_interfaces(module).execute_module() - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_acls.py b/lib/ansible/modules/network/eos/eos_acls.py deleted file mode 100644 index 0dffd2c6df..0000000000 --- a/lib/ansible/modules/network/eos/eos_acls.py +++ /dev/null @@ -1,925 +0,0 @@ -#!/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 eos_acls -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network'} - -DOCUMENTATION = """ ---- -module: eos_acls -version_added: '2.10' -short_description: 'Manages IP access-list attributes of Arista EOS interfaces' -description: This module manages the IP access-list attributes of Arista EOS interfaces. -author: Gomathiselvi S (@GomathiselviS) -notes: -- Tested against Arista vEOS v4.20.10M -options: - config: - description: A dictionary of IP access-list options - type: list - elements: dict - suboptions: - afi: - description: - - The Address Family Indicator (AFI) for the Access Control Lists (ACL). - type: str - required: true - choices: ['ipv4', 'ipv6'] - acls: - description: - - A list of Access Control Lists (ACL). - type: list - elements: dict - suboptions: - standard: - description: standard access-list or not - type: bool - default: False - name: - description: Name of the acl-list - type: str - required: true - aces: - description: Filtering data - type: list - elements: dict - suboptions: - sequence: - description: sequence number for the ordered list of rules - type: int - remark: - description: Specify a comment - type: str - fragment_rules: - description: Add fragment rules - type: bool - grant: - description: Action to be applied on the rule - type: str - choices: ['permit', 'deny'] - line: - description: For fact gathering, any ACE that is not fully parsed, while show up as a value of this attribute. - type: str - aliases: ['ace'] - protocol: - description: - - Specify the protocol to match. - - Refer to vendor documentation for valid values. - type: str - vlan: - description: Vlan options - type: str - protocol_options: - description: All the possible sub options for the protocol chosen. - type: dict - suboptions: - tcp: - description: Options for tcp protocol. - type: dict - suboptions: - flags: - description: Match TCP packet flags - type: dict - suboptions: - ack: - description: Match on the ACK bit - type: bool - established: - description: Match established connections - type: bool - fin: - description: Match on the FIN bit - type: bool - psh: - description: Match on the PSH bit - type: bool - rst: - description: Match on the RST bit - type: bool - syn: - description: Match on the SYN bit - type: bool - urg: - description: Match on the URG bit - type: bool - icmp: - description: - - Internet Control Message Protocol settings. - type: dict - suboptions: - administratively_prohibited: - description: Administratively prohibited - type: bool - alternate_address: - description: Alternate address - type: bool - conversion_error: - description: Datagram conversion - type: bool - dod_host_prohibited: - description: Host prohibited - type: bool - dod_net_prohibited: - description: Net prohibited - type: bool - echo: - description: Echo (ping) - type: bool - echo_reply: - description: Echo reply - type: bool - general_parameter_problem: - description: Parameter problem - type: bool - host_isolated: - description: Host isolated - type: bool - host_precedence_unreachable: - description: Host unreachable for precedence - type: bool - host_redirect: - description: Host redirect - type: bool - host_tos_redirect: - description: Host redirect for TOS - type: bool - host_tos_unreachable: - description: Host unreachable for TOS - type: bool - host_unknown: - description: Host unknown - type: bool - host_unreachable: - description: Host unreachable - type: bool - information_reply: - description: Information replies - type: bool - information_request: - description: Information requests - type: bool - mask_reply: - description: Mask replies - type: bool - mask_request: - description: Mask requests - type: bool - message_code: - description: ICMP message code - type: int - message_type: - description: ICMP message type - type: int - mobile_redirect: - description: Mobile host redirect - type: bool - net_redirect: - description: Network redirect - type: bool - net_tos_redirect: - description: Net redirect for TOS - type: bool - net_tos_unreachable: - description: Network unreachable for TOS - type: bool - net_unreachable: - description: Net unreachable - type: bool - network_unknown: - description: Network unknown - type: bool - no_room_for_option: - description: Parameter required but no room - type: bool - option_missing: - description: Parameter required but not present - type: bool - packet_too_big: - description: Fragmentation needed and DF set - type: bool - parameter_problem: - description: All parameter problems - type: bool - port_unreachable: - description: Port unreachable - type: bool - precedence_unreachable: - description: Precedence cutoff - type: bool - protocol_unreachable: - description: Protocol unreachable - type: bool - reassembly_timeout: - description: Reassembly timeout - type: bool - redirect: - description: All redirects - type: bool - router_advertisement: - description: Router discovery advertisements - type: bool - router_solicitation: - description: Router discovery solicitations - type: bool - source_quench: - description: Source quenches - type: bool - source_route_failed: - description: Source route failed - type: bool - time_exceeded: - description: All time exceededs - type: bool - timestamp_reply: - description: Timestamp replies - type: bool - timestamp_request: - description: Timestamp requests - type: bool - traceroute: - description: Traceroute - type: bool - ttl_exceeded: - description: TTL exceeded - type: bool - unreachable: - description: All unreachables - type: bool - message_num: - description: icmp msg type number. - type: int - icmpv6: - description: Options for icmpv6. - type: dict - suboptions: - address_unreachable: - description: address unreachable - type: bool - beyond_scope: - description: beyond_scope - type: bool - echo_reply: - description: echo_reply - type: bool - echo_request: - description: echo reques - type: bool - erroneous_header: - description: erroneous header - type: bool - fragment_reassembly_exceeded: - description: fragment_reassembly_exceeded - type: bool - hop_limit_exceeded: - description: hop limit exceeded - type: bool - neighbor_advertisement: - description: neighbor advertisement - type: bool - neighbor_solicitation: - description: neighbor_solicitation - type: bool - no_admin: - description: no admin - type: bool - no_route: - description: no route - type: bool - packet_too_big: - description: packet too big - type: bool - parameter_problem: - description: parameter problem - type: bool - port_unreachable: - description: port unreachable - type: bool - redirect_message: - description: redirect message - type: bool - reject_route: - description: reject route - type: bool - router_advertisement: - description: router_advertisement - type: bool - router_solicitation: - description: router_solicitation - type: bool - source_address_failed: - description: source_address_failed - type: bool - source_routing_error: - description: source_routing_error - type: bool - time_exceeded: - description: time_exceeded - type: bool - unreachable: - description: unreachable - type: bool - unrecognized_ipv6_option: - description: unrecognized_ipv6_option - type: bool - unrecognized_next_header: - description: unrecognized_next_header - type: bool - ip: - description : Internet Protocol. - type: dict - suboptions: - nexthop_group: - description: Nexthop-group name. - type: str - ipv6: - description : Internet V6 Protocol. - type: dict - suboptions: - nexthop_group: - description: Nexthop-group name. - type: str - source: - description: The packet's source address - type: dict - suboptions: - address: - description: dotted decimal notation of IP address - type: str - wildcard_bits: - description: Source wildcard bits - type: str - subnet_address: - description: A subnet address - type: str - host: - description: Host IP address - type: str - any: - description: Rule matches all source addresses - type: bool - port_protocol: - description: Specify source port/protocoli, along with operator. (comes with tcp/udp). - type: dict - destination: - description: The packet's destination address - type: dict - suboptions: - address: - description: dotted decimal notation of IP address - type: str - wildcard_bits: - description: Source wildcard bits - type: str - subnet_address: - description: A subnet address - type: str - host: - description: Host IP address - type: str - any: - description: Rule matches all source addresses - type: bool - port_protocol: - description: Specify dest port/protocol, along with operator . (comes with tcp/udp). - type: dict - ttl: - description: Compares the TTL (time-to-live) value in the packet to a specified value - type: dict - suboptions: - eq: - description: Match a single TTL value - type: int - lt: - description: Match TTL lesser than this number - type: int - gt: - description: Match TTL greater than this number - type: int - neq: - description: Match TTL not equal to this value - type: int - fragments: - description: Match non-head fragment packets - type: bool - log: - description: Log matches against this rule - type: bool - tracked: - description: Match packets in existing ICMP/UDP/TCP connections - type: bool - hop_limit: - description: Hop limit value. - type: dict - running_config: - description: - - The module, by default, will connect to the remote device and - retrieve the current running-config to use as a base for comparing - against the contents of source. There are times when it is not - desirable to have the task get the current running-config for - every task in a playbook. The I(running_config) argument allows the - implementer to pass in the configuration to use as the base - config for comparison. This value of this option should be the - output received from device by executing command - version_added: "2.10" - type: str - - state: - description: - - The state the configuration should be left in. - type: str - choices: - ['deleted', 'merged', 'overridden', 'replaced', 'gathered', 'rendered', 'parsed'] - default: - merged -""" -EXAMPLES = """ -# Using merged - -# Before state: -# ------------- -# show running-config | section access-list -# ip access-list test1 -# 10 permit ip 10.10.10.0/24 any ttl eq 200 -# 20 permit ip 10.30.10.0/24 host 10.20.10.1 -# 30 deny tcp host 10.10.20.1 eq finger www any syn log -# 40 permit ip any any -# ipv6 access-list test2 -# 10 deny icmpv6 any any reject-route hop-limit eq 20 - -- name: Merge provided configuration with device configuration - eos_acls: - config: - - afi: "ipv4" - acls: - - name: test1 - aces: - - sequence: 35 - grant: "deny" - protocol: "ospf" - source: - subnet_address: 20.0.0.0/8 - destnation: - any: true - state: merged - -# After state: -# ------------ -# -# show running-config | section access-list -# ip access-list test1 -# 10 permit ip 10.10.10.0/24 any ttl eq 200 -# 20 permit ip 10.30.10.0/24 host 10.20.10.1 -# 30 deny tcp host 10.10.20.1 eq finger www any syn log -# 35 deny ospf 20.0.0.0/8 any -# 40 permit ip any any -# ipv6 access-list test2 -# 10 deny icmpv6 any any reject-route hop-limit eq 20 - -# Using merged - -# Before state: -# ------------- -# show running-config | section access-list -# ip access-list test1 -# 10 permit ip 10.10.10.0/24 any ttl eq 200 -# 20 permit ip 10.30.10.0/24 host 10.20.10.1 -# 30 deny tcp host 10.10.20.1 eq finger www any syn log -# 40 permit ip any any -# ipv6 access-list test2 -# 10 deny icmpv6 any any reject-route hop-limit eq 20 - -- name: Merge to update the given configuration with an existing ace - eos_acls: - config: - - afi: "ipv4" - acls: - - name: test1 - aces: - - sequence: 35 - log : true - ttl: - eq: 33 - state: merged - -# After state: -# ------------ -# -# show running-config | section access-list -# ip access-list test1 -# 10 permit ip 10.10.10.0/24 any ttl eq 200 -# 20 permit ip 10.30.10.0/24 host 10.20.10.1 -# 30 deny tcp host 10.10.20.1 eq finger www any syn log -# 35 deny ospf 20.0.0.0/8 any ttl eq 33 log -# 40 permit ip any any -# ipv6 access-list test2 -# 10 deny icmpv6 any any reject-route hop-limit eq 20 - -# Using replaced - -# Before state: -# ------------- -# show running-config | section access-list -# ip access-list test1 -# 10 permit ip 10.10.10.0/24 any ttl eq 200 -# 20 permit ip 10.30.10.0/24 host 10.20.10.1 -# 30 deny tcp host 10.10.20.1 eq finger www any syn log -# 40 permit ip any any -# ! -# ip access-list test3 -# 10 permit ip 35.33.0.0/16 any log -# ! -# ipv6 access-list test2 -# 10 deny icmpv6 any any reject-route hop-limit eq 20 - - - -- name: Replace device configuration with provided configuration - eos_acls: - config: - - afi: "ipv4" - acls: - - name: test1 - aces: - - sequence: 35 - grant: "permit" - protocol: "ospf" - source: - subnet_address: 20.0.0.0/8 - destination: - any: true - state: replaced - -# After state: -# ------------ -# -# show running-config | section access-list -# ip access-list test1 -# 35 permit ospf 20.0.0.0/8 any -# ! -# ip access-list test3 -# 10 permit ip 35.33.0.0/16 any log -# ! -# ipv6 access-list test2 -# 10 deny icmpv6 any any reject-route hop-limit eq 20 - - -# Using overridden - -# Before state: -# ------------- -# show running-config | section access-list -# ip access-list test1 -# 10 permit ip 10.10.10.0/24 any ttl eq 200 -# 20 permit ip 10.30.10.0/24 host 10.20.10.1 -# 30 deny tcp host 10.10.20.1 eq finger www any syn log -# 40 permit ip any any -# ! -# ip access-list test3 -# 10 permit ip 35.33.0.0/16 any log -# ! -# ipv6 access-list test2 -# 10 deny icmpv6 any any reject-route hop-limit eq 20 - - - -- name: override device configuration with provided configuration - eos_acls: - config: - - afi: "ipv4" - acls: - - name: test1 - aces: - - sequence: 35 - action: "permit" - protocol: "ospf" - source: - subnet_address: 20.0.0.0/8 - destination: - any: true - state: overridden - -# After state: -# ------------ -# -# show running-config | section access-list -# ip access-list test1 -# 35 permit ospf 20.0.0.0/8 any -# ! - - -# Using deleted - -# Before state: -# ------------- -# show running-config | section access-list -# ip access-list test1 -# 10 permit ip 10.10.10.0/24 any ttl eq 200 -# 20 permit ip 10.30.10.0/24 host 10.20.10.1 -# 30 deny tcp host 10.10.20.1 eq finger www any syn log -# 40 permit ip any any -# ! -# ipv6 access-list test2 -# 10 deny icmpv6 any any reject-route hop-limit eq 20 - - -- name: Delete provided configuration - eos_acls: - config: - - afi: "ipv4" - acls: - - name: test1 - aces: - - sequence: 30 - state: deleted - -# After state: -# ------------ -# -# show running-config | section access-list -# ip access-list test1 -# 10 permit ip 10.10.10.0/24 any ttl eq 200 -# 20 permit ip 10.30.10.0/24 host 10.20.10.1 -# 40 permit ip any any -# ! -# ipv6 access-list test2 -# 10 deny icmpv6 any any reject-route hop-limit eq 20 - - - -# Before state: -# ------------- -# show running-config | section access-list -# ip access-list test1 -# 10 permit ip 10.10.10.0/24 any ttl eq 200 -# 20 permit ip 10.30.10.0/24 host 10.20.10.1 -# 30 deny tcp host 10.10.20.1 eq finger www any syn log -# 40 permit ip any any -# ipv6 access-list test2 -# 10 deny icmpv6 any any reject-route hop-limit eq 20 - -# ! - -- name: Delete provided configuration - eos_acls: - config: - - afi: "ipv4" - acls: - - name: test1 - state: deleted - -# After state: -# ------------ -# -# show running-config | section access-list - -# ipv6 access-list test2 -# 10 deny icmpv6 any any reject-route hop-limit eq 20 - - -# using gathered - -# ip access-list test1 -# 35 deny ospf 20.0.0.0/8 any -# ip access-list test2 -# 40 permit vlan 55 0xE2 icmpv6 any any log - -- name: Gather the exisitng condiguration - eos_acls: - state: gathered - -# returns: - - -# eos_acls: -# config: -# - afi: "ipv4" -# acls: -# - name: test1 -# aces: -# - sequence: 35 -# grant: "deny" -# protocol: "ospf" -# source: -# subnet_address: 20.0.0.0/8 -# destination: -# any: true -# - afi: "ipv6" -# acls: -# - name: test2 -# aces: -# - sequence: 40 -# grant: "permit" -# vlan: "55 0xE2" -# protocol: "icmpv6" -# log: true -# source: -# any: true -# destination: -# any: true - - -# using rendered - -- name: Delete provided configuration - eos_acls: - config: - - afi: "ipv4" - acls: - - name: test1 - aces: - - sequence: 35 - grant: "deny" - protocol: "ospf" - source: - subnet_address: 20.0.0.0/8 - destination: - any: true - - afi: "ipv6" - acls: - - name: test2 - aces: - - sequence: 40 - grant: "permit" - vlan: "55 0xE2" - protocol: "icmpv6" - log: true - source: - any: true - destination: - any: true - state: rendered - -# returns: - -# ip access-list test1 -# 35 deny ospf 20.0.0.0/8 any -# ip access-list test2 -# 40 permit vlan 55 0xE2 icmpv6 any any log - - -# Using Parsed - -# parsed_acls.cfg - -# ipv6 access-list standard test2 -# 10 permit any log -# ! -# ip access-list test1 -# 35 deny ospf 20.0.0.0/8 any -# 45 remark Run by ansible -# 55 permit tcp any any -# ! - -- name: parse configs - eos_acls: - running_config: "{{ lookup('file', './parsed_acls.cfg') }}" - state: parsed - -# returns -# "parsed": [ -# { -# "acls": [ -# { -# "aces": [ -# { -# "destination": { -# "any": true -# }, -# "grant": "deny", -# "protocol": "ospf", -# "sequence": 35, -# "source": { -# "subnet_address": "20.0.0.0/8" -# } -# }, -# { -# "remark": "Run by ansible", -# "sequence": 45 -# }, -# { -# "destination": { -# "any": true -# }, -# "grant": "permit", -# "protocol": "tcp", -# "sequence": 55, -# "source": { -# "any": true -# } -# } -# ], -# "name": "test1" -# } -# ], -# "afi": "ipv4" -# }, -# { -# "acls": [ -# { -# "aces": [ -# { -# "grant": "permit", -# "log": true, -# "sequence": 10, -# "source": { -# "any": true -# } -# } -# ], -# "name": "test2", -# "standard": true -# } -# ], -# "afi": "ipv6" -# } -# ] - -""" -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: - - ipv6 access-list standard test2 - - 10 permit any log - - ip access-list test1 - - 35 deny ospf 20.0.0.0/8 any - - 45 remark Run by ansible - - 55 permit tcp any any -""" - - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.argspec.acls.acls import AclsArgs -from ansible.module_utils.network.eos.config.acls.acls import Acls - - -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',)), - ('state', 'rendered', ('config',)), - ('state', 'parsed', ('running_config',))] - mutually_exclusive = [('config', 'running_config')] - - module = AnsibleModule(argument_spec=AclsArgs.argument_spec, - required_if=required_if, - supports_check_mode=True, - mutually_exclusive=mutually_exclusive) - - result = Acls(module).execute_module() - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_banner.py b/lib/ansible/modules/network/eos/eos_banner.py deleted file mode 100644 index c716d192b6..0000000000 --- a/lib/ansible/modules/network/eos/eos_banner.py +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/python -# -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network'} - - -DOCUMENTATION = """ ---- -module: eos_banner -version_added: "2.3" -author: "Peter Sprygada (@privateip)" -short_description: Manage multiline banners on Arista EOS devices -description: - - This will configure both login and motd banners on remote devices - running Arista EOS. It allows playbooks to add or remote - banner text from the active running configuration. -extends_documentation_fragment: eos -notes: - - Tested against EOS 4.15 -options: - banner: - description: - - Specifies which banner that should be - configured on the remote device. - required: true - choices: ['login', 'motd'] - text: - description: - - The banner text that should be - present in the remote device running configuration. This argument - accepts a multiline string. Requires I(state=present). - state: - description: - - Specifies whether or not the configuration is - present in the current devices active running configuration. - default: present - choices: ['present', 'absent'] -""" - -EXAMPLES = """ -- name: configure the login banner - eos_banner: - banner: login - text: | - this is my login banner - that contains a multiline - string - state: present - -- name: remove the motd banner - eos_banner: - banner: motd - state: absent -""" - -RETURN = """ -commands: - description: The list of configuration mode commands to send to the device - returned: always - type: list - sample: - - banner login - - this is my login banner - - that contains a multiline - - string - - EOF -session_name: - description: The EOS config session name used to load the configuration - returned: if changes - type: str - sample: ansible_1479315771 -""" -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.eos import load_config, run_commands -from ansible.module_utils.network.eos.eos import eos_argument_spec, is_local_eapi -from ansible.module_utils.six import string_types -from ansible.module_utils._text import to_text - - -def map_obj_to_commands(updates, module): - commands = list() - want, have = updates - state = module.params['state'] - - if state == 'absent' and have.get('text'): - if isinstance(have['text'], string_types): - commands.append('no banner %s' % module.params['banner']) - elif have['text'].get('loginBanner') or have['text'].get('motd'): - commands.append({'cmd': 'no banner %s' % module.params['banner']}) - - elif state == 'present': - if isinstance(have['text'], string_types): - if want['text'] != have['text']: - commands.append('banner %s' % module.params['banner']) - commands.extend(want['text'].strip().split('\n')) - commands.append('EOF') - else: - have_text = have['text'].get('loginBanner') or have['text'].get('motd') - if have_text: - have_text = have_text.strip() - - if to_text(want['text']) != have_text or not have_text: - # For EAPI we need to construct a dict with cmd/input - # key/values for the banner - commands.append({'cmd': 'banner %s' % module.params['banner'], - 'input': want['text'].strip('\n')}) - - return commands - - -def map_config_to_obj(module): - output = run_commands(module, ['show banner %s' % module.params['banner']]) - obj = {'banner': module.params['banner'], 'state': 'absent'} - if output: - if is_local_eapi(module): - # On EAPI we need to extract the banner text from dict key - # 'loginBanner' - if module.params['banner'] == 'login': - banner_response_key = 'loginBanner' - else: - banner_response_key = 'motd' - if isinstance(output[0], dict) and banner_response_key in output[0].keys(): - obj['text'] = output[0] - else: - obj['text'] = output[0] - obj['state'] = 'present' - return obj - - -def map_params_to_obj(module): - text = module.params['text'] - if text: - text = to_text(text).strip() - - return { - 'banner': module.params['banner'], - 'text': text, - 'state': module.params['state'] - } - - -def main(): - """ main entry point for module execution - """ - argument_spec = dict( - banner=dict(required=True, choices=['login', 'motd']), - text=dict(), - state=dict(default='present', choices=['present', 'absent']) - ) - - argument_spec.update(eos_argument_spec) - - required_if = [('state', 'present', ('text',))] - - module = AnsibleModule(argument_spec=argument_spec, - required_if=required_if, - supports_check_mode=True) - - warnings = list() - - result = {'changed': False} - if warnings: - result['warnings'] = warnings - want = map_params_to_obj(module) - have = map_config_to_obj(module) - - commands = map_obj_to_commands((want, have), module) - result['commands'] = commands - - if commands: - commit = not module.check_mode - response = load_config(module, commands, commit=commit) - if response.get('diff') and module._diff: - result['diff'] = {'prepared': response.get('diff')} - result['session_name'] = response.get('session') - result['changed'] = True - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_bgp.py b/lib/ansible/modules/network/eos/eos_bgp.py deleted file mode 100644 index 547524eba4..0000000000 --- a/lib/ansible/modules/network/eos/eos_bgp.py +++ /dev/null @@ -1,394 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# (c) 2019, Ansible by Red Hat, inc -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -# - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network'} - - -DOCUMENTATION = """ ---- -module: eos_bgp -version_added: "2.8" -author: "Nilashish Chakraborty (@NilashishC)" -short_description: Configure global BGP protocol settings on Arista EOS. -description: - - This module provides configuration management of global BGP parameters - on Arista EOS devices. -notes: - - Tested against Arista vEOS Version 4.15.9M. -options: - config: - description: - - Specifies the BGP related configuration. - suboptions: - bgp_as: - description: - - Specifies the BGP Autonomous System (AS) number to configure on the device. - type: int - required: true - router_id: - description: - - Configures the BGP routing process router-id value. - default: null - log_neighbor_changes: - description: - - Enable/disable logging neighbor up/down and reset reason. - type: bool - neighbors: - description: - - Specifies BGP neighbor related configurations. - suboptions: - neighbor: - description: - - Neighbor router address. - required: True - remote_as: - description: - - Remote AS of the BGP neighbor to configure. - type: int - required: True - update_source: - description: - - Source of the routing updates. - password: - description: - - Password to authenticate the BGP peer connection. - description: - description: - - Neighbor specific description. - ebgp_multihop: - description: - - Specifies the maximum hop count for EBGP neighbors not on directly connected networks. - - The range is from 1 to 255. - type: int - peer_group: - description: - - Name of the peer group that the neighbor is a member of. - timers: - description: - - Specifies BGP neighbor timer related configurations. - suboptions: - keepalive: - description: - - Frequency (in seconds) with which the device sends keepalive messages to its peer. - - The range is from 0 to 3600. - type: int - required: True - holdtime: - description: - - Interval (in seconds) after not receiving a keepalive message that device declares a peer dead. - - The range is from 3 to 7200. - - Setting this value to 0 will not send keep-alives (hold forever). - type: int - required: True - route_reflector_client: - description: - - Specify a neighbor as a route reflector client. - type: bool - remove_private_as: - description: - - Remove the private AS number from outbound updates. - type: bool - enabled: - description: - - Administratively shutdown or enable a neighbor. - maximum_prefix: - description: - - Maximum number of prefixes to accept from this peer. - - The range is from 0 to 4294967294. - type: int - redistribute: - description: - - Specifies the redistribute information from another routing protocol. - suboptions: - protocol: - description: - - Specifies the protocol for configuring redistribute information. - required: True - route_map: - description: - - Specifies the route map reference. - networks: - description: - - Specify Networks to announce via BGP. - - For operation replace, this option is mutually exclusive with networks option under address_family. - - For operation replace, if the device already has an address family activated, this option is not allowed. - suboptions: - prefix: - description: - - Network ID to announce via BGP. - required: True - masklen: - description: - - Subnet mask length for the Network to announce(e.g, 8, 16, 24, etc.). - route_map: - description: - - Route map to modify the attributes. - address_family: - description: - - Specifies BGP address family related configurations. - suboptions: - afi: - description: - - Type of address family to configure. - choices: - - ipv4 - - ipv6 - required: True - redistribute: - description: - - Specifies the redistribute information from another routing protocol. - suboptions: - protocol: - description: - - Specifies the protocol for configuring redistribute information. - required: True - route_map: - description: - - Specifies the route map reference. - networks: - description: - - Specify Networks to announce via BGP. - - For operation replace, this option is mutually exclusive with root level networks option. - suboptions: - prefix: - description: - - Network ID to announce via BGP. - required: True - masklen: - description: - - Subnet mask length for the Network to announce(e.g, 8, 16, 24, etc.). - route_map: - description: - - Route map to modify the attributes. - neighbors: - description: - - Specifies BGP neighbor related configurations in Address Family configuration mode. - suboptions: - neighbor: - description: - - Neighbor router address. - required: True - activate: - description: - - Enable the Address Family for this Neighbor. - type: bool - default_originate: - description: - - Originate default route to this neighbor. - type: bool - graceful_restart: - description: - - Enable/disable graceful restart mode for this neighbor. - type: bool - weight: - description: - - Assign weight for routes learnt from this neighbor. - - The range is from 0 to 65535 - type: int - operation: - description: - - Specifies the operation to be performed on the BGP process configured on the device. - - In case of merge, the input configuration will be merged with the existing BGP configuration on the device. - - In case of replace, if there is a diff between the existing configuration and the input configuration, the - existing configuration will be replaced by the input configuration for every option that has the diff. - - In case of override, all the existing BGP configuration will be removed from the device and replaced with - the input configuration. - - In case of delete the existing BGP configuration will be removed from the device. - default: merge - choices: ['merge', 'replace', 'override', 'delete'] -""" - -EXAMPLES = """ -- name: configure global bgp as 64496 - eos_bgp: - config: - bgp_as: 64496 - router_id: 192.0.2.1 - log_neighbor_changes: True - neighbors: - - neighbor: 203.0.113.5 - remote_as: 64511 - timers: - keepalive: 300 - holdtime: 360 - - neighbor: 198.51.100.2 - remote_as: 64498 - networks: - - prefix: 198.51.100.0 - route_map: RMAP_1 - - prefix: 192.0.2.0 - masklen: 23 - address_family: - - afi: ipv4 - safi: unicast - redistribute: - - protocol: isis - route_map: RMAP_1 - operation: merge - -- name: Configure BGP neighbors - eos_bgp: - config: - bgp_as: 64496 - neighbors: - - neighbor: 192.0.2.10 - remote_as: 64496 - description: IBGP_NBR_1 - ebgp_multihop: 100 - timers: - keepalive: 300 - holdtime: 360 - - - neighbor: 192.0.2.15 - remote_as: 64496 - description: IBGP_NBR_2 - ebgp_multihop: 150 - operation: merge - -- name: Configure root-level networks for BGP - eos_bgp: - config: - bgp_as: 64496 - networks: - - prefix: 203.0.113.0 - masklen: 27 - route_map: RMAP_1 - - - prefix: 203.0.113.32 - masklen: 27 - route_map: RMAP_2 - operation: merge - -- name: Configure BGP neighbors under address family mode - eos_bgp: - config: - bgp_as: 64496 - address_family: - - afi: ipv4 - neighbors: - - neighbor: 203.0.113.10 - activate: yes - default_originate: True - - - neighbor: 192.0.2.15 - activate: yes - graceful_restart: True - operation: merge - -- name: remove bgp as 64496 from config - eos_bgp: - config: - bgp_as: 64496 - operation: delete -""" - -RETURN = """ -commands: - description: The list of configuration mode commands to send to the device - returned: always - type: list - sample: - - router bgp 64496 - - bgp router-id 192.0.2.1 - - bgp log-neighbor-changes - - neighbor 203.0.113.5 remote-as 64511 - - neighbor 203.0.113.5 timers 300 360 - - neighbor 198.51.100.2 remote-as 64498 - - network 198.51.100.0 route-map RMAP_1 - - network 192.0.2.0 mask 255.255.254.0 - - address-family ipv4 - - redistribute isis route-map RMAP_1 - - exit-address-family -""" -from ansible.module_utils._text import to_text -from ansible.module_utils.network.eos.providers.module import NetworkModule -from ansible.module_utils.network.eos.providers.cli.config.bgp.process import REDISTRIBUTE_PROTOCOLS - - -def main(): - """ main entry point for module execution - """ - network_spec = { - 'prefix': dict(required=True), - 'masklen': dict(type='int'), - 'route_map': dict(), - } - - redistribute_spec = { - 'protocol': dict(choices=REDISTRIBUTE_PROTOCOLS, required=True), - 'route_map': dict(), - } - - timer_spec = { - 'keepalive': dict(type='int', required=True), - 'holdtime': dict(type='int', required=True), - } - - neighbor_spec = { - 'neighbor': dict(required=True), - 'remote_as': dict(type='int', required=True), - 'update_source': dict(), - 'password': dict(no_log=True), - 'enabled': dict(type='bool'), - 'description': dict(), - 'ebgp_multihop': dict(type='int'), - 'timers': dict(type='dict', options=timer_spec), - 'peer_group': dict(), - 'maximum_prefix': dict(type='int'), - 'route_reflector_client': dict(type='int'), - 'remove_private_as': dict(type='bool') - } - - af_neighbor_spec = { - 'neighbor': dict(required=True), - 'activate': dict(type='bool'), - 'default_originate': dict(type='bool'), - 'graceful_restart': dict(type='bool'), - 'weight': dict(type='int'), - } - - address_family_spec = { - 'afi': dict(choices=['ipv4', 'ipv6'], required=True), - 'networks': dict(type='list', elements='dict', options=network_spec), - 'redistribute': dict(type='list', elements='dict', options=redistribute_spec), - 'neighbors': dict(type='list', elements='dict', options=af_neighbor_spec), - } - - config_spec = { - 'bgp_as': dict(type='int', required=True), - 'router_id': dict(), - 'log_neighbor_changes': dict(type='bool'), - 'neighbors': dict(type='list', elements='dict', options=neighbor_spec), - 'address_family': dict(type='list', elements='dict', options=address_family_spec), - 'redistribute': dict(type='list', elements='dict', options=redistribute_spec), - 'networks': dict(type='list', elements='dict', options=network_spec) - } - - argument_spec = { - 'config': dict(type='dict', options=config_spec), - 'operation': dict(default='merge', choices=['merge', 'replace', 'override', 'delete']) - } - - module = NetworkModule(argument_spec=argument_spec, - supports_check_mode=True) - - try: - result = module.edit_config(config_filter='| section bgp') - except Exception as exc: - module.fail_json(msg=to_text(exc)) - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_command.py b/lib/ansible/modules/network/eos/eos_command.py deleted file mode 100644 index 0db5c26a74..0000000000 --- a/lib/ansible/modules/network/eos/eos_command.py +++ /dev/null @@ -1,248 +0,0 @@ -#!/usr/bin/python -# -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network'} - - -DOCUMENTATION = """ ---- -module: eos_command -version_added: "2.1" -author: "Peter Sprygada (@privateip)" -short_description: Run arbitrary commands on an Arista EOS device -description: - - Sends an arbitrary set of commands to an EOS node and returns the results - read from the device. This module includes an - argument that will cause the module to wait for a specific condition - before returning or timing out if the condition is not met. -extends_documentation_fragment: eos -notes: - - Tested against EOS 4.15 -options: - commands: - description: - - The commands to send to the remote EOS device over the - configured provider. The resulting output from the command - is returned. If the I(wait_for) argument is provided, the - module is not returned until the condition is satisfied or - the number of I(retries) has been exceeded. - required: true - wait_for: - description: - - Specifies what to evaluate from the output of the command - and what conditionals to apply. This argument will cause - the task to wait for a particular conditional to be true - before moving forward. If the conditional is not true - by the configured retries, the task fails. - Note - With I(wait_for) the value in C(result['stdout']) can be accessed - using C(result), that is to access C(result['stdout'][0]) use C(result[0]) See examples. - aliases: ['waitfor'] - version_added: "2.2" - match: - description: - - The I(match) argument is used in conjunction with the - I(wait_for) argument to specify the match policy. Valid - values are C(all) or C(any). If the value is set to C(all) - then all conditionals in the I(wait_for) must be satisfied. If - the value is set to C(any) then only one of the values must be - satisfied. - default: all - choices: ['any', 'all'] - version_added: "2.2" - retries: - description: - - Specifies the number of retries a command should be tried - before it is considered failed. The command is run on the - target device every retry and evaluated against the I(wait_for) - conditionals. - default: 10 - interval: - description: - - Configures the interval in seconds to wait between retries - of the command. If the command does not pass the specified - conditional, the interval indicates how to long to wait before - trying the command again. - default: 1 -""" - -EXAMPLES = """ -- name: run show version on remote devices - eos_command: - commands: show version - -- name: run show version and check to see if output contains Arista - eos_command: - commands: show version - wait_for: result[0] contains Arista - -- name: run multiple commands on remote nodes - eos_command: - commands: - - show version - - show interfaces - -- name: run multiple commands and evaluate the output - eos_command: - commands: - - show version - - show interfaces - wait_for: - - result[0] contains Arista - - result[1] contains Loopback0 - -- name: run commands and specify the output format - eos_command: - commands: - - command: show version - output: json - -- name: using cli transport, check whether the switch is in maintenance mode - eos_command: - commands: show maintenance - wait_for: result[0] contains 'Under Maintenance' - -- name: using cli transport, check whether the switch is in maintenance mode using json output - eos_command: - commands: show maintenance | json - wait_for: result[0].units.System.state eq 'underMaintenance' - -- name: "using eapi transport check whether the switch is in maintenance, - with 8 retries and 2 second interval between retries" - eos_command: - commands: show maintenance - wait_for: result[0]['units']['System']['state'] eq 'underMaintenance' - interval: 2 - retries: 8 - provider: - transport: eapi -""" - -RETURN = """ -stdout: - description: The set of responses from the commands - returned: always apart from low level errors (such as action plugin) - type: list - sample: ['...', '...'] -stdout_lines: - description: The value of stdout split into a list - returned: always apart from low level errors (such as action plugin) - type: list - sample: [['...', '...'], ['...'], ['...']] -failed_conditions: - description: The list of conditionals that have failed - returned: failed - type: list - sample: ['...', '...'] -""" -import time - -from ansible.module_utils._text import to_text -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.common.parsing import Conditional -from ansible.module_utils.network.common.utils import transform_commands, to_lines -from ansible.module_utils.network.eos.eos import run_commands -from ansible.module_utils.network.eos.eos import eos_argument_spec - - -def parse_commands(module, warnings): - commands = transform_commands(module) - - if module.check_mode: - for item in list(commands): - if not item['command'].startswith('show'): - warnings.append( - 'Only show commands are supported when using check mode, not ' - 'executing %s' % item['command'] - ) - commands.remove(item) - - return commands - - -def to_cli(obj): - cmd = obj['command'] - if obj.get('output') == 'json': - cmd += ' | json' - return cmd - - -def main(): - """entry point for module execution - """ - argument_spec = dict( - commands=dict(type='list', required=True), - - wait_for=dict(type='list', aliases=['waitfor']), - match=dict(default='all', choices=['all', 'any']), - - retries=dict(default=10, type='int'), - interval=dict(default=1, type='int') - ) - - argument_spec.update(eos_argument_spec) - - module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True) - - warnings = list() - result = {'changed': False, 'warnings': warnings} - commands = parse_commands(module, warnings) - wait_for = module.params['wait_for'] or list() - - try: - conditionals = [Conditional(c) for c in wait_for] - except AttributeError as exc: - module.fail_json(msg=to_text(exc)) - - retries = module.params['retries'] - interval = module.params['interval'] - match = module.params['match'] - - while retries > 0: - responses = run_commands(module, commands) - - for item in list(conditionals): - if item(responses): - if match == 'any': - conditionals = list() - break - conditionals.remove(item) - - if not conditionals: - break - - time.sleep(interval) - retries -= 1 - - if conditionals: - failed_conditions = [item.raw for item in conditionals] - msg = 'One or more conditional statements have not been satisfied' - module.fail_json(msg=msg, failed_conditions=failed_conditions) - - result.update({ - 'stdout': responses, - 'stdout_lines': list(to_lines(responses)), - }) - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_config.py b/lib/ansible/modules/network/eos/eos_config.py deleted file mode 100644 index 6aef5f9e87..0000000000 --- a/lib/ansible/modules/network/eos/eos_config.py +++ /dev/null @@ -1,516 +0,0 @@ -#!/usr/bin/python -# -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network'} - - -DOCUMENTATION = """ ---- -module: eos_config -version_added: "2.1" -author: "Peter Sprygada (@privateip)" -short_description: Manage Arista EOS configuration sections -description: - - Arista EOS configurations use a simple block indent file syntax - for segmenting configuration into sections. This module provides - an implementation for working with EOS configuration sections in - a deterministic way. This module works with either CLI or eAPI - transports. -extends_documentation_fragment: eos -notes: - - Tested against EOS 4.15 - - Abbreviated commands are NOT idempotent, see - L(Network FAQ,../network/user_guide/faq.html#why-do-the-config-modules-always-return-changed-true-with-abbreviated-commands). -options: - lines: - description: - - The ordered set of commands that should be configured in the - section. The commands must be the exact same commands as found - in the device running-config. Be sure to note the configuration - command syntax as some commands are automatically modified by the - device config parser. - aliases: ['commands'] - parents: - description: - - The ordered set of parents that uniquely identify the section or hierarchy - the commands should be checked against. If the parents argument - is omitted, the commands are checked against the set of top - level or global commands. - src: - description: - - The I(src) argument provides a path to the configuration file - to load into the remote system. The path can either be a full - system path to the configuration file if the value starts with / - or relative to the root of the implemented role or playbook. - This argument is mutually exclusive with the I(lines) and - I(parents) arguments. It can be a Jinja2 template as well. - src file must have same indentation as a live switch config. - Arista EOS device config has 3 spaces indentation. - version_added: "2.2" - before: - description: - - The ordered set of commands to push on to the command stack if - a change needs to be made. This allows the playbook designer - the opportunity to perform configuration commands prior to pushing - any changes without affecting how the set of commands are matched - against the system. - after: - description: - - The ordered set of commands to append to the end of the command - stack if a change needs to be made. Just like with I(before) this - allows the playbook designer to append a set of commands to be - executed after the command set. - match: - description: - - Instructs the module on the way to perform the matching of - the set of commands against the current device config. If - match is set to I(line), commands are matched line by line. If - match is set to I(strict), command lines are matched with respect - to position. If match is set to I(exact), command lines - must be an equal match. Finally, if match is set to I(none), the - module will not attempt to compare the source configuration with - the running configuration on the remote device. - default: line - choices: ['line', 'strict', 'exact', 'none'] - replace: - description: - - Instructs the module on the way to perform the configuration - on the device. If the replace argument is set to I(line) then - the modified lines are pushed to the device in configuration - mode. If the replace argument is set to I(block) then the entire - command block is pushed to the device in configuration mode if any - line is not correct. - default: line - choices: ['line', 'block', 'config'] - backup: - description: - - This argument will cause the module to create a full backup of - the current C(running-config) from the remote device before any - changes are made. If the C(backup_options) value is not given, - the backup file is written to the C(backup) folder in the playbook - root directory or role root directory, if playbook is part of an - ansible role. If the directory does not exist, it is created. - type: bool - default: 'no' - version_added: "2.2" - running_config: - description: - - The module, by default, will connect to the remote device and - retrieve the current running-config to use as a base for comparing - against the contents of source. There are times when it is not - desirable to have the task get the current running-config for - every task in a playbook. The I(running_config) argument allows the - implementer to pass in the configuration to use as the base - config for this module. - type: str - aliases: ['config'] - version_added: "2.4" - defaults: - description: - - The I(defaults) argument will influence how the running-config - is collected from the device. When the value is set to true, - the command used to collect the running-config is append with - the all keyword. When the value is set to false, the command - is issued without the all keyword - type: bool - default: 'no' - version_added: "2.2" - save_when: - description: - - When changes are made to the device running-configuration, the - changes are not copied to non-volatile storage by default. Using - this argument will change that before. If the argument is set to - I(always), then the running-config will always be copied to the - startup-config and the I(modified) flag will always be set to - True. If the argument is set to I(modified), then the running-config - will only be copied to the startup-config if it has changed since - the last save to startup-config. If the argument is set to - I(never), the running-config will never be copied to the - startup-config. If the argument is set to I(changed), then the running-config - will only be copied to the startup-config if the task has made a change. - I(changed) was added in Ansible 2.5. - default: never - choices: ['always', 'never', 'modified', 'changed'] - version_added: "2.4" - diff_against: - description: - - When using the C(ansible-playbook --diff) command line argument - the module can generate diffs against different sources. - - When this option is configure as I(startup), the module will return - the diff of the running-config against the startup-config. - - When this option is configured as I(intended), the module will - return the diff of the running-config against the configuration - provided in the C(intended_config) argument. - - When this option is configured as I(running), the module will - return the before and after diff of the running-config with respect - to any changes made to the device configuration. - - When this option is configured as C(session), the diff returned will - be based on the configuration session. - default: session - choices: ['startup', 'running', 'intended', 'session'] - version_added: "2.4" - diff_ignore_lines: - description: - - Use this argument to specify one or more lines that should be - ignored during the diff. This is used for lines in the configuration - that are automatically updated by the system. This argument takes - a list of regular expressions or exact line matches. - version_added: "2.4" - intended_config: - description: - - The C(intended_config) provides the master configuration that - the node should conform to and is used to check the final - running-config against. This argument will not modify any settings - on the remote device and is strictly used to check the compliance - of the current device's configuration against. When specifying this - argument, the task should also modify the C(diff_against) value and - set it to I(intended). - type: str - version_added: "2.4" - backup_options: - description: - - This is a dict object containing configurable options related to backup file path. - The value of this option is read only when C(backup) is set to I(yes), if C(backup) is set - to I(no) this option will be silently ignored. - suboptions: - filename: - description: - - The filename to be used to store the backup configuration. If the filename - is not given it will be generated based on the hostname, current time and date - in format defined by <hostname>_config.<current-date>@<current-time> - dir_path: - description: - - This option provides the path ending with directory name in which the backup - configuration file will be stored. If the directory does not exist it will be first - created and the filename is either the value of C(filename) or default filename - as described in C(filename) options description. If the path value is not given - in that case a I(backup) directory will be created in the current working directory - and backup configuration will be copied in C(filename) within I(backup) directory. - type: path - type: dict - version_added: "2.8" -""" - -EXAMPLES = """ -- name: configure top level settings - eos_config: - lines: hostname {{ inventory_hostname }} - -- name: load an acl into the device - eos_config: - lines: - - 10 permit ip host 192.0.2.1 any log - - 20 permit ip host 192.0.2.2 any log - - 30 permit ip host 192.0.2.3 any log - - 40 permit ip host 192.0.2.4 any log - parents: ip access-list test - before: no ip access-list test - replace: block - -- name: load configuration from file - eos_config: - src: eos.cfg - -- name: render a Jinja2 template onto an Arista switch - eos_config: - backup: yes - src: eos_template.j2 - -- name: diff the running config against a master config - eos_config: - diff_against: intended - intended_config: "{{ lookup('file', 'master.cfg') }}" - -- name: for idempotency, use full-form commands - eos_config: - lines: - # - shut - - shutdown - # parents: int eth1 - parents: interface Ethernet1 - -- name: configurable backup path - eos_config: - src: eos_template.j2 - backup: yes - backup_options: - filename: backup.cfg - dir_path: /home/user -""" - -RETURN = """ -commands: - description: The set of commands that will be pushed to the remote device - returned: always - type: list - sample: ['hostname switch01', 'interface Ethernet1', 'no shutdown'] -updates: - description: The set of commands that will be pushed to the remote device - returned: always - type: list - sample: ['hostname switch01', 'interface Ethernet1', 'no shutdown'] -backup_path: - description: The full path to the backup file - returned: when backup is yes - type: str - sample: /playbooks/ansible/backup/eos_config.2016-07-16@22:28:34 -filename: - description: The name of the backup file - returned: when backup is yes and filename is not specified in backup options - type: str - sample: eos_config.2016-07-16@22:28:34 -shortname: - description: The full path to the backup file excluding the timestamp - returned: when backup is yes and filename is not specified in backup options - type: str - sample: /playbooks/ansible/backup/eos_config -date: - description: The date extracted from the backup file name - returned: when backup is yes - type: str - sample: "2016-07-16" -time: - description: The time extracted from the backup file name - returned: when backup is yes - type: str - sample: "22:28:34" -""" -from ansible.module_utils._text import to_text -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.connection import ConnectionError -from ansible.module_utils.network.common.config import NetworkConfig, dumps -from ansible.module_utils.network.eos.eos import get_config, load_config, get_connection -from ansible.module_utils.network.eos.eos import run_commands -from ansible.module_utils.network.eos.eos import eos_argument_spec - - -def get_candidate(module): - candidate = '' - if module.params['src']: - candidate = module.params['src'] - elif module.params['lines']: - candidate_obj = NetworkConfig(indent=3) - parents = module.params['parents'] or list() - candidate_obj.add(module.params['lines'], parents=parents) - candidate = dumps(candidate_obj, 'raw') - return candidate - - -def get_running_config(module, config=None, flags=None): - contents = module.params['running_config'] - if not contents: - if config: - contents = config - else: - contents = get_config(module, flags=flags) - return contents - - -def save_config(module, result): - result['changed'] = True - if not module.check_mode: - cmd = {'command': 'copy running-config startup-config', 'output': 'text'} - run_commands(module, [cmd]) - else: - module.warn('Skipping command `copy running-config startup-config` ' - 'due to check_mode. Configuration not copied to ' - 'non-volatile storage') - - -def main(): - """ main entry point for module execution - """ - backup_spec = dict( - filename=dict(), - dir_path=dict(type='path') - ) - argument_spec = dict( - src=dict(type='path'), - - lines=dict(aliases=['commands'], type='list'), - parents=dict(type='list'), - - before=dict(type='list'), - after=dict(type='list'), - - match=dict(default='line', choices=['line', 'strict', 'exact', 'none']), - replace=dict(default='line', choices=['line', 'block', 'config']), - - defaults=dict(type='bool', default=False), - backup=dict(type='bool', default=False), - backup_options=dict(type='dict', options=backup_spec), - - save_when=dict(choices=['always', 'never', 'modified', 'changed'], default='never'), - - diff_against=dict(choices=['startup', 'session', 'intended', 'running'], default='session'), - diff_ignore_lines=dict(type='list'), - - running_config=dict(aliases=['config']), - intended_config=dict(), - ) - - argument_spec.update(eos_argument_spec) - - mutually_exclusive = [('lines', 'src'), - ('parents', 'src')] - - required_if = [('match', 'strict', ['lines']), - ('match', 'exact', ['lines']), - ('replace', 'block', ['lines']), - ('replace', 'config', ['src']), - ('diff_against', 'intended', ['intended_config'])] - - module = AnsibleModule(argument_spec=argument_spec, - mutually_exclusive=mutually_exclusive, - required_if=required_if, - supports_check_mode=True) - - warnings = list() - - result = {'changed': False} - if warnings: - result['warnings'] = warnings - - diff_ignore_lines = module.params['diff_ignore_lines'] - config = None - contents = None - flags = ['all'] if module.params['defaults'] else [] - connection = get_connection(module) - - # Refuse to diff_against: session if sessions are disabled - if module.params['diff_against'] == 'session' and not connection.supports_sessions: - module.fail_json(msg="Cannot diff against sessions when sessions are disabled. Please change diff_against to another value") - - if module.params['backup'] or (module._diff and module.params['diff_against'] == 'running'): - contents = get_config(module, flags=flags) - config = NetworkConfig(indent=1, contents=contents) - if module.params['backup']: - result['__backup__'] = contents - - if any((module.params['src'], module.params['lines'])): - match = module.params['match'] - replace = module.params['replace'] - path = module.params['parents'] - - candidate = get_candidate(module) - running = get_running_config(module, contents, flags=flags) - - try: - response = connection.get_diff(candidate=candidate, running=running, diff_match=match, diff_ignore_lines=diff_ignore_lines, path=path, - diff_replace=replace) - except ConnectionError as exc: - module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) - - config_diff = response['config_diff'] - - if config_diff: - commands = config_diff.split('\n') - - if module.params['before']: - commands[:0] = module.params['before'] - - if module.params['after']: - commands.extend(module.params['after']) - - result['commands'] = commands - result['updates'] = commands - - replace = module.params['replace'] == 'config' - commit = not module.check_mode - - response = load_config(module, commands, replace=replace, commit=commit) - - result['changed'] = True - - if module.params['diff_against'] == 'session': - if 'diff' in response: - result['diff'] = {'prepared': response['diff']} - else: - result['changed'] = False - - if 'session' in response: - result['session'] = response['session'] - - running_config = module.params['running_config'] - startup_config = None - - if module.params['save_when'] == 'always': - save_config(module, result) - elif module.params['save_when'] == 'modified': - output = run_commands(module, [{'command': 'show running-config', 'output': 'text'}, - {'command': 'show startup-config', 'output': 'text'}]) - - running_config = NetworkConfig(indent=3, contents=output[0], ignore_lines=diff_ignore_lines) - startup_config = NetworkConfig(indent=3, contents=output[1], ignore_lines=diff_ignore_lines) - - if running_config.sha1 != startup_config.sha1: - save_config(module, result) - - elif module.params['save_when'] == 'changed' and result['changed']: - save_config(module, result) - - if module._diff: - if not running_config: - output = run_commands(module, {'command': 'show running-config', 'output': 'text'}) - contents = output[0] - else: - contents = running_config - - # recreate the object in order to process diff_ignore_lines - running_config = NetworkConfig(indent=3, contents=contents, ignore_lines=diff_ignore_lines) - - if module.params['diff_against'] == 'running': - if module.check_mode: - module.warn("unable to perform diff against running-config due to check mode") - contents = None - else: - contents = config.config_text - - elif module.params['diff_against'] == 'startup': - if not startup_config: - output = run_commands(module, {'command': 'show startup-config', 'output': 'text'}) - contents = output[0] - else: - contents = startup_config.config_text - - elif module.params['diff_against'] == 'intended': - contents = module.params['intended_config'] - - if contents is not None: - base_config = NetworkConfig(indent=3, contents=contents, ignore_lines=diff_ignore_lines) - - if running_config.sha1 != base_config.sha1: - if module.params['diff_against'] == 'intended': - before = running_config - after = base_config - elif module.params['diff_against'] in ('startup', 'running'): - before = base_config - after = running_config - - result.update({ - 'changed': True, - 'diff': {'before': str(before), 'after': str(after)} - }) - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_eapi.py b/lib/ansible/modules/network/eos/eos_eapi.py deleted file mode 100644 index 2a67c57e94..0000000000 --- a/lib/ansible/modules/network/eos/eos_eapi.py +++ /dev/null @@ -1,435 +0,0 @@ -#!/usr/bin/python -# -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network'} - - -DOCUMENTATION = """ ---- -module: eos_eapi -version_added: "2.1" -author: "Peter Sprygada (@privateip)" -short_description: Manage and configure Arista EOS eAPI. -requirements: - - "EOS v4.12 or greater" -description: - - Use to enable or disable eAPI access, and set the port and state - of http, https, local_http and unix-socket servers. - - When enabling eAPI access the default is to enable HTTP on port - 80, enable HTTPS on port 443, disable local HTTP, and disable - Unix socket server. Use the options listed below to override the - default configuration. - - Requires EOS v4.12 or greater. -extends_documentation_fragment: eos -options: - http: - description: - - The C(http) argument controls the operating state of the HTTP - transport protocol when eAPI is present in the running-config. - When the value is set to True, the HTTP protocol is enabled and - when the value is set to False, the HTTP protocol is disabled. - By default, when eAPI is first configured, the HTTP protocol is - disabled. - type: bool - default: 'no' - aliases: ['enable_http'] - http_port: - description: - - Configures the HTTP port that will listen for connections when - the HTTP transport protocol is enabled. This argument accepts - integer values in the valid range of 1 to 65535. - default: 80 - https: - description: - - The C(https) argument controls the operating state of the HTTPS - transport protocol when eAPI is present in the running-config. - When the value is set to True, the HTTPS protocol is enabled and - when the value is set to False, the HTTPS protocol is disabled. - By default, when eAPI is first configured, the HTTPS protocol is - enabled. - type: bool - default: 'yes' - aliases: ['enable_https'] - https_port: - description: - - Configures the HTTP port that will listen for connections when - the HTTP transport protocol is enabled. This argument accepts - integer values in the valid range of 1 to 65535. - default: 443 - local_http: - description: - - The C(local_http) argument controls the operating state of the - local HTTP transport protocol when eAPI is present in the - running-config. When the value is set to True, the HTTP protocol - is enabled and restricted to connections from localhost only. When - the value is set to False, the HTTP local protocol is disabled. - - Note is value is independent of the C(http) argument - type: bool - default: 'no' - aliases: ['enable_local_http'] - local_http_port: - description: - - Configures the HTTP port that will listen for connections when - the HTTP transport protocol is enabled. This argument accepts - integer values in the valid range of 1 to 65535. - default: 8080 - socket: - description: - - The C(socket) argument controls the operating state of the UNIX - Domain Socket used to receive eAPI requests. When the value - of this argument is set to True, the UDS will listen for eAPI - requests. When the value is set to False, the UDS will not be - available to handle requests. By default when eAPI is first - configured, the UDS is disabled. - type: bool - default: 'no' - aliases: ['enable_socket'] - timeout: - description: - - The time (in seconds) to wait for the eAPI configuration to be - reflected in the running-config. - type: int - default: 30 - vrf: - description: - - The C(vrf) argument will configure eAPI to listen for connections - in the specified VRF. By default, eAPI transports will listen - for connections in the global table. This value requires the - VRF to already be created otherwise the task will fail. - default: default - version_added: "2.2" - config: - description: - - The module, by default, will connect to the remote device and - retrieve the current running-config to use as a base for comparing - against the contents of source. There are times when it is not - desirable to have the task get the current running-config for - every task in a playbook. The I(config) argument allows the - implementer to pass in the configuration to use as the base - config for comparison. - version_added: "2.2" - state: - description: - - The C(state) argument controls the operational state of eAPI - on the remote device. When this argument is set to C(started), - eAPI is enabled to receive requests and when this argument is - C(stopped), eAPI is disabled and will not receive requests. - default: started - choices: ['started', 'stopped'] -""" - -EXAMPLES = """ -- name: Enable eAPI access with default configuration - eos_eapi: - state: started - -- name: Enable eAPI with no HTTP, HTTPS at port 9443, local HTTP at port 80, and socket enabled - eos_eapi: - state: started - http: false - https_port: 9443 - local_http: yes - local_http_port: 80 - socket: yes - -- name: Shutdown eAPI access - eos_eapi: - state: stopped -""" - -RETURN = """ -commands: - description: The list of configuration mode commands to send to the device - returned: always - type: list - sample: - - management api http-commands - - protocol http port 81 - - no protocol https -urls: - description: Hash of URL endpoints eAPI is listening on per interface - returned: when eAPI is started - type: dict - sample: {'Management1': ['http://172.26.10.1:80']} -session_name: - description: The EOS config session name used to load the configuration - returned: when changed is True - type: str - sample: ansible_1479315771 -""" -import re -import time - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.eos import run_commands, load_config -from ansible.module_utils.six import iteritems -from ansible.module_utils.network.eos.eos import eos_argument_spec - - -def check_transport(module): - transport = (module.params['provider'] or {}).get('transport') - - if transport == 'eapi': - module.fail_json(msg='eos_eapi module is only supported over cli transport') - - -def validate_http_port(value, module): - if not 1 <= value <= 65535: - module.fail_json(msg='http_port must be between 1 and 65535') - - -def validate_https_port(value, module): - if not 1 <= value <= 65535: - module.fail_json(msg='http_port must be between 1 and 65535') - - -def validate_local_http_port(value, module): - if not 1 <= value <= 65535: - module.fail_json(msg='http_port must be between 1 and 65535') - - -def validate_vrf(value, module): - out = run_commands(module, ['show vrf']) - configured_vrfs = [] - lines = out[0].strip().splitlines()[3:] - for l in lines: - if not l: - continue - splitted_line = re.split(r'\s{2,}', l.strip()) - if len(splitted_line) > 2: - configured_vrfs.append(splitted_line[0]) - - configured_vrfs.append('default') - if value not in configured_vrfs: - module.fail_json(msg='vrf `%s` is not configured on the system' % value) - - -def map_obj_to_commands(updates, module, warnings): - commands = list() - want, have = updates - - def needs_update(x): - return want.get(x) is not None and (want.get(x) != have.get(x)) - - def add(cmd): - if 'management api http-commands' not in commands: - commands.insert(0, 'management api http-commands') - commands.append(cmd) - - if any((needs_update('http'), needs_update('http_port'))): - if want['http'] is False: - add('no protocol http') - else: - if have['http'] is False and want['http'] in (False, None): - warnings.append('protocol http is not enabled, not configuring http port value') - else: - port = want['http_port'] or 80 - add('protocol http port %s' % port) - - if any((needs_update('https'), needs_update('https_port'))): - if want['https'] is False: - add('no protocol https') - else: - if have['https'] is False and want['https'] in (False, None): - warnings.append('protocol https is not enabled, not configuring https port value') - else: - port = want['https_port'] or 443 - add('protocol https port %s' % port) - - if any((needs_update('local_http'), needs_update('local_http_port'))): - if want['local_http'] is False: - add('no protocol http localhost') - else: - if have['local_http'] is False and want['local_http'] in (False, None): - warnings.append('protocol local_http is not enabled, not configuring local_http port value') - else: - port = want['local_http_port'] or 8080 - add('protocol http localhost port %s' % port) - - if any((needs_update('socket'), needs_update('socket'))): - if want['socket'] is False: - add('no protocol unix-socket') - else: - add('protocol unix-socket') - if needs_update('state'): - if want['state'] == 'stopped': - add('shutdown') - elif want['state'] == 'started': - add('no shutdown') - - if needs_update('vrf'): - add('vrf %s' % want['vrf']) - # switching operational vrfs here - # need to add the desired state as well - if want['state'] == 'stopped': - add('shutdown') - elif want['state'] == 'started': - add('no shutdown') - - return commands - - -def parse_state(data): - if data[0]['enabled']: - return 'started' - else: - return 'stopped' - - -def map_config_to_obj(module): - out = run_commands(module, ['show management api http-commands | json']) - return { - 'http': out[0]['httpServer']['configured'], - 'http_port': out[0]['httpServer']['port'], - 'https': out[0]['httpsServer']['configured'], - 'https_port': out[0]['httpsServer']['port'], - 'local_http': out[0]['localHttpServer']['configured'], - 'local_http_port': out[0]['localHttpServer']['port'], - 'socket': out[0]['unixSocketServer']['configured'], - 'vrf': out[0]['vrf'] or "default", - 'state': parse_state(out) - } - - -def map_params_to_obj(module): - obj = { - 'http': module.params['http'], - 'http_port': module.params['http_port'], - 'https': module.params['https'], - 'https_port': module.params['https_port'], - 'local_http': module.params['local_http'], - 'local_http_port': module.params['local_http_port'], - 'socket': module.params['socket'], - 'vrf': module.params['vrf'], - 'state': module.params['state'] - } - - for key, value in iteritems(obj): - if value: - validator = globals().get('validate_%s' % key) - if validator: - validator(value, module) - - return obj - - -def verify_state(updates, module): - want, have = updates - - invalid_state = [('http', 'httpServer'), - ('https', 'httpsServer'), - ('local_http', 'localHttpServer'), - ('socket', 'unixSocketServer')] - - timeout = module.params["timeout"] - state = module.params['state'] - - while invalid_state: - out = run_commands(module, ['show management api http-commands | json']) - for index, item in enumerate(invalid_state): - want_key, eapi_key = item - if want[want_key] is not None: - if want[want_key] == out[0][eapi_key]['running']: - del invalid_state[index] - elif state == 'stopped': - if not out[0][eapi_key]['running']: - del invalid_state[index] - else: - del invalid_state[index] - time.sleep(1) - timeout -= 1 - if timeout == 0: - module.fail_json(msg='timeout expired before eapi running state changed') - - -def collect_facts(module, result): - out = run_commands(module, ['show management api http-commands | json']) - facts = dict(eos_eapi_urls=dict()) - for each in out[0]['urls']: - intf, url = each.split(' : ') - key = str(intf).strip() - if key not in facts['eos_eapi_urls']: - facts['eos_eapi_urls'][key] = list() - facts['eos_eapi_urls'][key].append(str(url).strip()) - result['ansible_facts'] = facts - - -def main(): - """ main entry point for module execution - """ - argument_spec = dict( - http=dict(aliases=['enable_http'], type='bool'), - http_port=dict(type='int'), - - https=dict(aliases=['enable_https'], type='bool'), - https_port=dict(type='int'), - - local_http=dict(aliases=['enable_local_http'], type='bool'), - local_http_port=dict(type='int'), - - socket=dict(aliases=['enable_socket'], type='bool'), - timeout=dict(type="int", default=30), - - vrf=dict(default='default'), - - config=dict(), - state=dict(default='started', choices=['stopped', 'started']), - ) - - argument_spec.update(eos_argument_spec) - - module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True) - - check_transport(module) - - result = {'changed': False} - - warnings = list() - if module.params['config']: - warnings.append('config parameter is no longer necessary and will be ignored') - - want = map_params_to_obj(module) - have = map_config_to_obj(module) - - commands = map_obj_to_commands((want, have), module, warnings) - result['commands'] = commands - - if commands: - commit = not module.check_mode - response = load_config(module, commands, commit=commit) - if response.get('diff') and module._diff: - result['diff'] = {'prepared': response.get('diff')} - result['session_name'] = response.get('session') - result['changed'] = True - - if result['changed']: - verify_state((want, have), module) - - collect_facts(module, result) - - if warnings: - result['warnings'] = warnings - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_facts.py b/lib/ansible/modules/network/eos/eos_facts.py deleted file mode 100644 index a410c5640d..0000000000 --- a/lib/ansible/modules/network/eos/eos_facts.py +++ /dev/null @@ -1,208 +0,0 @@ -#!/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) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network'} - - -DOCUMENTATION = """ ---- -module: eos_facts -version_added: "2.2" -author: - - "Peter Sprygada (@privateip)" - - "Nathaniel Case (@Qalthos)" -short_description: Collect facts from remote devices running Arista EOS -description: - - Collects facts from Arista devices running the EOS operating - system. This module places the facts gathered in the fact tree keyed by the - respective resource name. The facts module will always collect a - base set of facts from the device and can enable or disable - collection of additional facts. -extends_documentation_fragment: eos -options: - gather_subset: - description: - - When supplied, this argument will restrict the facts collected - to a given subset. Possible values for this argument include - all, hardware, config, and interfaces. Can specify a list of - values to include a larger subset. Values can also be used - with an initial C(M(!)) to specify that a specific subset should - not be collected. - required: false - type: list - default: '!config' - gather_network_resources: - description: - - When supplied, this argument will restrict the facts collected - to a given subset. Possible values for this argument include - all and the resources like interfaces, vlans etc. - Can specify a list of values to include a larger subset. Values - can also be used with an initial C(M(!)) to specify that a - specific subset should not be collected. Values can also be used - with an initial C(M(!)) to specify that a specific subset should - not be collected. - Valid subsets are 'all', 'interfaces', 'l2_interfaces', 'l3_interfaces', - 'lacp', 'lacp_interfaces', 'lag_interfaces', 'lldp_global', 'lldp_interfaces', - 'vlans', 'acls'. - required: false - type: list - version_added: "2.9" -""" - -EXAMPLES = """ -- name: Gather all legacy facts -- eos_facts: - gather_subset: all - -- name: Gather only the config and default facts - eos_facts: - gather_subset: - - config - -- name: Do not gather hardware facts - eos_facts: - gather_subset: - - "!hardware" - -- name: Gather legacy and resource facts - eos_facts: - gather_subset: all - gather_network_resources: all - -- name: Gather only the interfaces resource facts and no legacy facts -- eos_facts: - gather_subset: - - '!all' - - '!min' - gather_network_resources: - - interfaces - -- name: Gather all resource facts and minimal legacy facts - eos_facts: - gather_subset: min - gather_network_resources: all -""" - -RETURN = """ -ansible_net_gather_subset: - description: The list of fact subsets collected from the device - returned: always - type: list - -ansible_net_gather_network_resources: - description: The list of fact for network resource subsets collected from the device - returned: when the resource is configured - type: list - -# default -ansible_net_model: - description: The model name returned from the device - returned: always - type: str -ansible_net_serialnum: - description: The serial number of the remote device - returned: always - type: str -ansible_net_version: - description: The operating system version running on the remote device - returned: always - type: str -ansible_net_hostname: - description: The configured hostname of the device - returned: always - type: str -ansible_net_image: - description: The image file the device is running - returned: always - type: str -ansible_net_fqdn: - description: The fully qualified domain name of the device - returned: always - type: str -ansible_net_api: - description: The name of the transport - returned: always - type: str -ansible_net_python_version: - description: The Python version Ansible controller is using - returned: always - type: str - -# hardware -ansible_net_filesystems: - description: All file system names available on the device - returned: when hardware is configured - type: list -ansible_net_memfree_mb: - description: The available free memory on the remote device in Mb - returned: when hardware is configured - type: int -ansible_net_memtotal_mb: - description: The total memory on the remote device in Mb - returned: when hardware is configured - type: int - -# config -ansible_net_config: - description: The current active config from the device - returned: when config is configured - type: str - -# interfaces -ansible_net_all_ipv4_addresses: - description: All IPv4 addresses configured on the device - returned: when interfaces is configured - type: list -ansible_net_all_ipv6_addresses: - description: All IPv6 addresses configured on the device - returned: when interfaces is configured - type: list -ansible_net_interfaces: - description: A hash of all interfaces running on the system - returned: when interfaces is configured - type: dict -ansible_net_neighbors: - description: The list of LLDP neighbors from the remote device - returned: when interfaces is configured - type: dict -""" - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.argspec.facts.facts import FactsArgs -from ansible.module_utils.network.eos.facts.facts import Facts -from ansible.module_utils.network.eos.eos import eos_argument_spec - - -def main(): - """ - Main entry point for module execution - - :returns: ansible_facts - """ - argument_spec = FactsArgs.argument_spec - argument_spec.update(eos_argument_spec) - - module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True) - - warnings = [] - if module.params["gather_subset"] == "!config": - warnings.append('default value for `gather_subset` will be changed to `min` from `!config` v2.11 onwards') - - result = Facts(module).get_facts() - - ansible_facts, additional_warnings = result - warnings.extend(additional_warnings) - - module.exit_json(ansible_facts=ansible_facts, warnings=warnings) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_interfaces.py b/lib/ansible/modules/network/eos/eos_interfaces.py deleted file mode 100644 index d8f4e56c82..0000000000 --- a/lib/ansible/modules/network/eos/eos_interfaces.py +++ /dev/null @@ -1,298 +0,0 @@ -#!/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 eos_interfaces -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network'} - - -DOCUMENTATION = """ ---- -module: eos_interfaces -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 - type: list - suboptions: - name: - description: - - Full name of the interface, e.g. GigabitEthernet1. - type: str - required: true - description: - description: - - Interface description - type: str - duplex: - description: - - Interface link status. Applicable for Ethernet interfaces only. - - Values other than C(auto) must also set I(speed). - - Ignored when I(speed) is set above C(1000). - type: str - enabled: - default: true - description: - - Administrative state of the interface. - - Set the value to C(true) to administratively enable the interface or C(false) - to disable it. - type: bool - mtu: - description: - - MTU for a specific interface. Must be an even number between 576 and 9216. - Applicable for Ethernet interfaces only. - type: int - speed: - description: - - Interface link speed. Applicable for Ethernet interfaces only. - type: str - state: - choices: - - merged - - replaced - - overridden - - deleted - default: merged - description: - - The state of the configuration after module completion. - type: str - -""" - -EXAMPLES = """ ---- - -# Using merged - -# Before state: -# ------------- -# -# veos#show running-config | section interface -# interface Ethernet1 -# description "Interface 1" -# ! -# interface Ethernet2 -# ! -# interface Management1 -# description "Management interface" -# ip address dhcp -# ! - -- name: Merge provided configuration with device configuration - eos_interfaces: - config: - - name: Ethernet1 - enabled: True - - name: Ethernet2 - description: 'Configured by Ansible' - enabled: False - state: merged - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# description "Interface 1" -# ! -# interface Ethernet2 -# description "Configured by Ansible" -# shutdown -# ! -# interface Management1 -# description "Management interface" -# ip address dhcp -# ! - -# Using replaced - -# Before state: -# ------------- -# -# veos#show running-config | section interface -# interface Ethernet1 -# description "Interface 1" -# ! -# interface Ethernet2 -# ! -# interface Management1 -# description "Management interface" -# ip address dhcp -# ! - -- name: Replaces device configuration of listed interfaces with provided configuration - eos_interfaces: - config: - - name: Ethernet1 - enabled: True - - name: Ethernet2 - description: 'Configured by Ansible' - enabled: False - state: replaced - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# ! -# interface Ethernet2 -# description "Configured by Ansible" -# shutdown -# ! -# interface Management1 -# description "Management interface" -# ip address dhcp -# ! - -# Using overridden - -# Before state: -# ------------- -# -# veos#show running-config | section interface -# interface Ethernet1 -# description "Interface 1" -# ! -# interface Ethernet2 -# ! -# interface Management1 -# description "Management interface" -# ip address dhcp -# ! - -- name: Overrides all device configuration with provided configuration - eos_interfaces: - config: - - name: Ethernet1 - enabled: True - - name: Ethernet2 - description: 'Configured by Ansible' - enabled: False - state: overridden - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# ! -# interface Ethernet2 -# description "Configured by Ansible" -# shutdown -# ! -# interface Management1 -# ip address dhcp -# ! - -# Using deleted - -# Before state: -# ------------- -# -# veos#show running-config | section interface -# interface Ethernet1 -# description "Interface 1" -# ! -# interface Ethernet2 -# ! -# interface Management1 -# description "Management interface" -# ip address dhcp -# ! - -- name: Delete or return interface parameters to default settings - eos_interfaces: - config: - - name: Ethernet1 - state: deleted - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# ! -# interface Ethernet2 -# ! -# interface Management1 -# description "Management interface" -# ip address dhcp -# ! -""" - -RETURN = """ -before: - description: The configuration as structured data prior to module invocation. - returned: always - type: dict - 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: dict - 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: ['interface Ethernet2', 'shutdown', 'speed 10full'] -""" - - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.argspec.interfaces.interfaces import InterfacesArgs -from ansible.module_utils.network.eos.config.interfaces.interfaces import Interfaces - - -def main(): - """ - Main entry point for module execution - - :returns: the result form module invocation - """ - module = AnsibleModule(argument_spec=InterfacesArgs.argument_spec, - supports_check_mode=True) - - result = Interfaces(module).execute_module() - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_l2_interfaces.py b/lib/ansible/modules/network/eos/eos_l2_interfaces.py deleted file mode 100644 index 7429086ff1..0000000000 --- a/lib/ansible/modules/network/eos/eos_l2_interfaces.py +++ /dev/null @@ -1,312 +0,0 @@ -#!/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 eos_l2_interfaces -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network' -} - -DOCUMENTATION = """ ---- -module: eos_l2_interfaces -version_added: 2.9 -short_description: Manages Layer-2 interface attributes of Arista EOS devices -description: This module provides declarative management of Layer-2 interface 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 Layer-2 interface options - type: list - elements: dict - suboptions: - name: - description: - - Full name of interface, e.g. Ethernet1. - type: str - required: True - access: - description: - - Switchport mode access command to configure the interface as a layer 2 access. - type: dict - suboptions: - vlan: - description: - - Configure given VLAN in access port. It's used as the access VLAN ID. - type: int - trunk: - description: - - Switchport mode trunk command to configure the interface as a Layer 2 trunk. - type: dict - suboptions: - native_vlan: - description: - - Native VLAN to be configured in trunk port. It is used as the trunk native VLAN ID. - type: int - trunk_allowed_vlans: - description: - - List of allowed VLANs in a given trunk port. These are the only VLANs that will be - configured on the trunk. - type: list - mode: - description: - - Mode in which interface needs to be configured. - - Access mode is not shown in interface facts, so idempotency will not be - maintained for switchport mode access and every time the output will come - as changed=True. - version_added: '2.10' - type: str - choices: ['access', 'trunk'] - state: - choices: - - merged - - replaced - - overridden - - deleted - default: merged - description: - - The state of the configuration after module completion - type: str -""" - -EXAMPLES = """ ---- - -# Using merged - -# Before state: -# ------------- -# -# veos#show running-config | section interface -# interface Ethernet1 -# switchport access vlan 20 -# ! -# interface Ethernet2 -# switchport trunk native vlan 20 -# switchport mode trunk -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config -# ! - -- name: Merge provided configuration with device configuration. - eos_l2_interfaces: - config: - - name: Ethernet1 - trunk: - native_vlan: 10 - - name: Ethernet2 - access: - vlan: 30 - state: merged - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# switchport trunk native vlan 10 -# switchport mode trunk -# ! -# interface Ethernet2 -# switchport access vlan 30 -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config -# ! - -# Using replaced - -# Before state: -# ------------- -# -# veos2#show running-config | s int -# interface Ethernet1 -# switchport access vlan 20 -# ! -# interface Ethernet2 -# switchport trunk native vlan 20 -# switchport mode trunk -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config -# ! - -- name: Replace device configuration of specified L2 interfaces with provided configuration. - eos_l2_interfaces: - config: - - name: Ethernet1 - trunk: - native_vlan: 20 - trunk_vlans: 5-10, 15 - state: replaced - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# switchport trunk native vlan 20 -# switchport trunk allowed vlan 5-10,15 -# switchport mode trunk -# ! -# interface Ethernet2 -# switchport trunk native vlan 20 -# switchport mode trunk -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config -# ! - -# Using overridden - -# Before state: -# ------------- -# -# veos#show running-config | section interface -# interface Ethernet1 -# switchport access vlan 20 -# ! -# interface Ethernet2 -# switchport trunk native vlan 20 -# switchport mode trunk -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config -# ! - -- name: Override device configuration of all L2 interfaces on device with provided configuration. - eos_l2_interfaces: - config: - - name: Ethernet2 - access: - vlan: 30 - state: overridden - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# ! -# interface Ethernet2 -# switchport access vlan 30 -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config -# ! - -# Using deleted - -# Before state: -# ------------- -# -# veos#show running-config | section interface -# interface Ethernet1 -# switchport access vlan 20 -# ! -# interface Ethernet2 -# switchport trunk native vlan 20 -# switchport mode trunk -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config -# ! - -- name: Delete EOS L2 interfaces as in given arguments. - eos_l2_interfaces: - config: - - name: Ethernet1 - - name: Ethernet2 - state: deleted - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# ! -# interface Ethernet2 -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config -""" - -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: ['interface Ethernet2', 'switchport access vlan 20'] -""" - - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.argspec.l2_interfaces.l2_interfaces import L2_interfacesArgs -from ansible.module_utils.network.eos.config.l2_interfaces.l2_interfaces import L2_interfaces - - -def main(): - """ - Main entry point for module execution - - :returns: the result form module invocation - """ - module = AnsibleModule(argument_spec=L2_interfacesArgs.argument_spec, - supports_check_mode=True) - - result = L2_interfaces(module).execute_module() - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_l3_interfaces.py b/lib/ansible/modules/network/eos/eos_l3_interfaces.py deleted file mode 100644 index 38f8077c0e..0000000000 --- a/lib/ansible/modules/network/eos/eos_l3_interfaces.py +++ /dev/null @@ -1,305 +0,0 @@ -#!/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 eos_l3_interfaces -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network', -} - -DOCUMENTATION = """ ---- -module: eos_l3_interfaces -version_added: 2.9 -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 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 Layer 3 interface options - type: list - elements: dict - suboptions: - name: - description: - - Full name of the interface, i.e. Ethernet1. - type: str - required: True - ipv4: - description: - - List of IPv4 addresses to be set for the Layer 3 interface mentioned in I(name) option. - type: list - elements: dict - suboptions: - address: - description: - - IPv4 address to be set in the format <ipv4 address>/<mask> - eg. 192.0.2.1/24, or C(dhcp) to query DHCP for an IP address. - type: str - secondary: - description: - - Whether or not this address is a secondary address. - type: bool - default: False - ipv6: - description: - - List of IPv6 addresses to be set for the Layer 3 interface mentioned in I(name) option. - type: list - elements: dict - suboptions: - address: - description: - - IPv6 address to be set in the address format is <ipv6 address>/<mask> - eg. 2001:db8:2201:1::1/64 or C(auto-config) to use SLAAC to chose an address. - type: str - state: - description: - - The state of the configuration after module completion - type: str - choices: - - merged - - replaced - - overridden - - deleted - default: merged -""" - -EXAMPLES = """ ---- - -# Using deleted - -# Before state: -# ------------- -# -# veos#show running-config | section interface -# interface Ethernet1 -# ip address 192.0.2.12/24 -# ! -# interface Ethernet2 -# ipv6 address 2001:db8::1/64 -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config - -- name: Delete L3 attributes of given interfaces. - eos_l3_interfaces: - config: - - name: Ethernet1 - - name: Ethernet2 - state: deleted - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# ! -# interface Ethernet2 -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config - - -# Using merged - -# Before state: -# ------------- -# -# veos#show running-config | section interface -# interface Ethernet1 -# ip address 192.0.2.12/24 -# ! -# interface Ethernet2 -# ipv6 address 2001:db8::1/64 -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config - -- name: Merge provided configuration with device configuration. - eos_l3_interfaces: - config: - - name: Ethernet1 - ipv4: - address: 198.51.100.14/24 - - name: Ethernet2 - ipv4: - address: 203.0.113.27/24 - state: merged - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# ip address 198.51.100.14/24 -# ! -# interface Ethernet2 -# ip address 203.0.113.27/24 -# ipv6 address 2001:db8::1/64 -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config - - -# Using overridden - -# Before state: -# ------------- -# -# veos#show running-config | section interface -# interface Ethernet1 -# ip address 192.0.2.12/24 -# ! -# interface Ethernet2 -# ipv6 address 2001:db8::1/64 -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config - -- name: Override device configuration of all L2 interfaces on device with provided configuration. - eos_l3_interfaces: - config: - - name: Ethernet1 - ipv6: - address: 2001:db8:feed::1/96 - - name: Management1 - ipv4: - address: dhcp - ipv6: auto-config - state: overridden - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# ipv6 address 2001:db8:feed::1/96 -# ! -# interface Ethernet2 -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config - - -# Using replaced - -# Before state: -# ------------- -# -# veos#show running-config | section interface -# interface Ethernet1 -# ip address 192.0.2.12/24 -# ! -# interface Ethernet2 -# ipv6 address 2001:db8::1/64 -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config - -- name: Replace device configuration of specified L2 interfaces with provided configuration. - eos_l3_interfaces: - config: - - name: Ethernet2 - ipv4: - address: 203.0.113.27/24 - state: replaced - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# ip address 192.0.2.12/24 -# ! -# interface Ethernet2 -# ip address 203.0.113.27/24 -# ! -# interface Management1 -# ip address dhcp -# ipv6 address auto-config - - -""" -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: ['interface Ethernet2', 'ip address 192.0.2.12/24'] -""" - - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.argspec.l3_interfaces.l3_interfaces import L3_interfacesArgs -from ansible.module_utils.network.eos.config.l3_interfaces.l3_interfaces import L3_interfaces - - -def main(): - """ - Main entry point for module execution - - :returns: the result form module invocation - """ - module = AnsibleModule(argument_spec=L3_interfacesArgs.argument_spec, - supports_check_mode=True) - - result = L3_interfaces(module).execute_module() - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_lacp.py b/lib/ansible/modules/network/eos/eos_lacp.py deleted file mode 100644 index f19bcf85d1..0000000000 --- a/lib/ansible/modules/network/eos/eos_lacp.py +++ /dev/null @@ -1,178 +0,0 @@ -#!/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 eos_lacp -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network' -} - -DOCUMENTATION = """ ---- -module: eos_lacp -version_added: 2.9 -short_description: Manage Global Link Aggregation Control Protocol (LACP) on Arista EOS devices. -description: - - This module manages Global Link Aggregation Control Protocol (LACP) 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: LACP global options. - type: dict - suboptions: - system: - description: LACP system options. - type: dict - suboptions: - priority: - description: - - The system priority to use in LACP negotiations. - - Lower value is higher priority. - - Refer to vendor documentation for valid values. - type: int - state: - description: - - The state of the configuration after module completion. - type: str - choices: - - merged - - replaced - - deleted - default: merged -""" -EXAMPLES = """ -# Using merged - -# Before state: -# ------------- -# veos# show running-config | include lacp -# lacp system-priority 10 - -- name: Merge provided global LACP attributes with device attributes - eos_lacp: - config: - system: - priority: 20 - state: merged - -# After state: -# ------------ -# veos# show running-config | include lacp -# lacp system-priority 20 -# - - -# Using replaced - -# Before state: -# ------------- -# veos# show running-config | include lacp -# lacp system-priority 10 - -- name: Replace device global LACP attributes with provided attributes - eos_lacp: - config: - system: - priority: 20 - state: replaced - -# After state: -# ------------ -# veos# show running-config | include lacp -# lacp system-priority 20 -# - - -# Using deleted - -# Before state: -# ------------- -# veos# show running-config | include lacp -# lacp system-priority 10 - -- name: Delete global LACP attributes - eos_lacp: - state: deleted - -# After state: -# ------------ -# veos# show running-config | include lacp -# - - -""" -RETURN = """ -before: - description: The configuration as structured data prior to module invocation. - returned: always - type: dict - 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: dict - 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: ['lacp system-priority 10'] -""" - - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.argspec.lacp.lacp import LacpArgs -from ansible.module_utils.network.eos.config.lacp.lacp import Lacp - - -def main(): - """ - Main entry point for module execution - - :returns: the result form module invocation - """ - module = AnsibleModule(argument_spec=LacpArgs.argument_spec, - supports_check_mode=True) - - result = Lacp(module).execute_module() - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_lacp_interfaces.py b/lib/ansible/modules/network/eos/eos_lacp_interfaces.py deleted file mode 100644 index 246c3ed5a2..0000000000 --- a/lib/ansible/modules/network/eos/eos_lacp_interfaces.py +++ /dev/null @@ -1,254 +0,0 @@ -#!/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 eos_lacp_interfaces -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network' -} - -DOCUMENTATION = """ ---- -module: eos_lacp_interfaces -version_added: 2.9 -short_description: Manage Link Aggregation Control Protocol (LACP) attributes of interfaces on Arista EOS devices. -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. - type: list - elements: dict - suboptions: - name: - description: - - Full name of the interface (i.e. Ethernet1). - type: str - port_priority: - description: - - LACP port priority for the interface. Range 1-65535. - type: int - rate: - description: - - Rate at which PDUs are sent by LACP. - At fast rate LACP is transmitted once every 1 second. - At normal rate LACP is transmitted every 30 seconds after the link is bundled. - type: str - choices: ['fast', 'normal'] - state: - description: - - The state of the configuration after module completion. - type: str - choices: - - merged - - replaced - - overridden - - deleted - default: merged -""" -EXAMPLES = """ -# Using merged -# -# -# ------------ -# Before state -# ------------ -# -# -# veos#show run | section ^interface -# interface Ethernet1 -# lacp port-priority 30 -# interface Ethernet2 -# lacp rate fast - -- name: Merge provided configuration with device configuration - eos_lacp_interfaces: - config: - - name: Ethernet1 - rate: fast - - name: Ethernet2 - rate: normal - state: merged - -# -# ----------- -# After state -# ----------- -# -# veos#show run | section ^interface -# interface Ethernet1 -# lacp port-priority 30 -# lacp rate fast -# interface Ethernet2 - - -# Using replaced -# -# -# ------------ -# Before state -# ------------ -# -# -# veos#show run | section ^interface -# interface Ethernet1 -# lacp port-priority 30 -# interface Ethernet2 -# lacp rate fast - -- name: Replace existing LACP configuration of specified interfaces with provided configuration - eos_lacp_interfaces: - config: - - name: Ethernet1 - rate: fast - state: replaced - -# -# ----------- -# After state -# ----------- -# -# veos#show run | section ^interface -# interface Ethernet1 -# lacp rate fast -# interface Ethernet2 -# lacp rate fast - - -# Using overridden -# -# -# ------------ -# Before state -# ------------ -# -# -# veos#show run | section ^interface -# interface Ethernet1 -# lacp port-priority 30 -# interface Ethernet2 -# lacp rate fast - -- name: Override the LACP configuration of all the interfaces with provided configuration - eos_lacp_interfaces: - config: - - name: Ethernet1 - rate: fast - state: overridden - -# -# ----------- -# After state -# -# -# veos#show run | section ^interface -# interface Ethernet1 -# lacp rate fast -# interface Ethernet2 - - -# Using deleted -# -# -# ------------ -# Before state -# ------------ -# -# -# veos#show run | section ^interface -# interface Ethernet1 -# lacp port-priority 30 -# interface Ethernet2 -# lacp rate fast - -- name: Delete LACP attributes of given interfaces (or all interfaces if none specified). - eos_lacp_interfaces: - state: deleted - -# -# ----------- -# After state -# ----------- -# -# veos#show run | section ^interface -# interface Ethernet1 -# interface Ethernet2 - - -""" -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: ['interface Ethernet1', 'lacp rate fast'] -""" - - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.argspec.lacp_interfaces.lacp_interfaces import Lacp_interfacesArgs -from ansible.module_utils.network.eos.config.lacp_interfaces.lacp_interfaces import Lacp_interfaces - - -def main(): - """ - Main entry point for module execution - - :returns: the result form module invocation - """ - module = AnsibleModule(argument_spec=Lacp_interfacesArgs.argument_spec, - supports_check_mode=True) - - result = Lacp_interfaces(module).execute_module() - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_lag_interfaces.py b/lib/ansible/modules/network/eos/eos_lag_interfaces.py deleted file mode 100644 index a82102e29b..0000000000 --- a/lib/ansible/modules/network/eos/eos_lag_interfaces.py +++ /dev/null @@ -1,251 +0,0 @@ -#!/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 eos_lag_interfaces -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network' -} - -DOCUMENTATION = """ ---- -module: eos_lag_interfaces -version_added: 2.9 -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 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 list of link aggregation group configurations. - type: list - elements: dict - suboptions: - name: - description: - - Name of the port-channel interface of the link aggregation group (LAG) e.g., Port-Channel5. - type: str - required: True - members: - description: - - Ethernet interfaces that are part of the group. - type: list - elements: dict - suboptions: - member: - description: - - Name of ethernet interface that is a member of the LAG. - type: str - mode: - description: - - LAG mode for this interface. - type: str - choices: - - active - - "on" - - passive - state: - description: - - The state of the configuration after module completion. - type: str - choices: - - merged - - replaced - - overridden - - deleted - default: merged -""" - -EXAMPLES = """ ---- - -# Using merged - -# Before state: -# ------------- -# -# veos#show running-config | section interface -# interface Ethernet1 -# channel group 5 mode on -# interface Ethernet2 - -- name: Merge provided LAG attributes with existing device configuration - eos_lag_interfaces: - config: - - name: 5 - members: - - member: Ethernet2 - mode: on - state: merged - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# channel group 5 mode on -# interface Ethernet2 -# channel group 5 mode on - - -# Using replaced - -# Before state: -# ------------- -# -# veos#show running-config | section interface -# interface Ethernet1 -# channel group 5 mode on -# interface Ethernet2 - -- name: Replace all device configuration of specified LAGs with provided configuration - eos_lag_interfaces: - config: - - name: 5 - members: - - member: Ethernet2 - mode: on - state: replaced - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# interface Ethernet2 -# channel group 5 mode on - - -# Using overridden - -# Before state: -# ------------- -# -# veos#show running-config | section interface -# interface Ethernet1 -# channel group 5 mode on -# interface Ethernet2 - -- name: Override all device configuration of all LAG attributes with provided configuration - eos_lag_interfaces: - config: - - name: 10 - members: - - member: Ethernet2 - mode: on - state: overridden - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# interface Ethernet2 -# channel group 10 mode on - - -# Using deleted - -# Before state: -# ------------- -# -# veos#show running-config | section interface -# interface Ethernet1 -# channel group 5 mode on -# interface Ethernet2 -# channel group 5 mode on - -- name: Delete LAG attributes of the given interfaces. - eos_lag_interfaces: - config: - - name: 5 - members: - - member: Ethernet1 - state: deleted - -# After state: -# ------------ -# -# veos#show running-config | section interface -# interface Ethernet1 -# interface Ethernet2 -# channel group 5 mode on - - -""" - -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: ['command 1', 'command 2', 'command 3'] -""" - - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.argspec.lag_interfaces.lag_interfaces import Lag_interfacesArgs -from ansible.module_utils.network.eos.config.lag_interfaces.lag_interfaces import Lag_interfaces - - -def main(): - """ - Main entry point for module execution - - :returns: the result form module invocation - """ - module = AnsibleModule(argument_spec=Lag_interfacesArgs.argument_spec, - supports_check_mode=True) - - result = Lag_interfaces(module).execute_module() - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_lldp.py b/lib/ansible/modules/network/eos/eos_lldp.py deleted file mode 100644 index 0b556a1efd..0000000000 --- a/lib/ansible/modules/network/eos/eos_lldp.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# (c) 2017, Ansible by Red Hat, inc -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network'} - - -DOCUMENTATION = """ ---- -module: eos_lldp -version_added: "2.5" -author: "Ganesh Nalawade (@ganeshrn)" -short_description: Manage LLDP configuration on Arista EOS network devices -description: - - This module provides declarative management of LLDP service - on Arista EOS network devices. -notes: - - Tested against EOS 4.15 -options: - state: - description: - - State of the LLDP configuration. If value is I(present) lldp will be enabled - else if it is I(absent) it will be disabled. - default: present - choices: ['present', 'absent'] -extends_documentation_fragment: eos -""" - -EXAMPLES = """ -- name: Enable LLDP service - eos_lldp: - state: present - -- name: Disable LLDP service - eos_lldp: - state: absent -""" - -RETURN = """ -commands: - description: The list of configuration mode commands to send to the device - returned: always, except for the platforms that use Netconf transport to manage the device. - type: list - sample: - - lldp run -""" -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.eos import get_config, load_config -from ansible.module_utils.network.eos.eos import eos_argument_spec - - -def has_lldp(module): - config = get_config(module, flags=['| section lldp']) - - is_lldp_enable = False - if "no lldp run" not in config: - is_lldp_enable = True - - return is_lldp_enable - - -def main(): - """ main entry point for module execution - """ - argument_spec = dict( - state=dict(default='present', - choices=['present', 'absent', - 'enabled', 'disabled']) - ) - - argument_spec.update(eos_argument_spec) - - module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True) - - warnings = list() - - result = {'changed': False} - - if warnings: - result['warnings'] = warnings - - HAS_LLDP = has_lldp(module) - - commands = [] - - if module.params['state'] == 'absent' and HAS_LLDP: - commands.append('no lldp run') - elif module.params['state'] == 'present' and not HAS_LLDP: - commands.append('lldp run') - - result['commands'] = commands - - if commands: - commit = not module.check_mode - response = load_config(module, commands, commit=commit) - if response.get('diff') and module._diff: - result['diff'] = {'prepared': response.get('diff')} - result['session_name'] = response.get('session') - result['changed'] = True - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_lldp_global.py b/lib/ansible/modules/network/eos/eos_lldp_global.py deleted file mode 100644 index e9799a0cd6..0000000000 --- a/lib/ansible/modules/network/eos/eos_lldp_global.py +++ /dev/null @@ -1,246 +0,0 @@ -#!/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 eos_lldp_global -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network' -} - -DOCUMENTATION = """ ---- -module: eos_lldp_global -version_added: 2.9 -short_description: Manage Global Link Layer Discovery Protocol (LLDP) settings on Arista EOS devices. -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. - type: dict - suboptions: - holdtime: - description: - - Specifies the holdtime (in sec) to be sent in packets. - type: int - reinit: - description: - - Specifies the delay (in sec) for LLDP initialization on any interface. - type: int - timer: - description: - - Specifies the rate at which LLDP packets are sent (in sec). - type: int - tlv_select: - description: - - Specifies the LLDP TLVs to enable or disable. - type: dict - suboptions: - link_aggregation: - description: - - Enable or disable link aggregation TLV. - type: bool - management_address: - description: - - Enable or disable management address TLV. - type: bool - max_frame_size: - description: - - Enable or disable maximum frame size TLV. - type: bool - port_description: - description: - - Enable or disable port description TLV. - type: bool - system_capabilities: - description: - - Enable or disable system capabilities TLV. - type: bool - system_description: - description: - - Enable or disable system description TLV. - type: bool - system_name: - description: - - Enable or disable system name TLV. - type: bool - state: - description: - - The state of the configuration after module completion. - type: str - choices: - - merged - - replaced - - deleted - default: merged -""" -EXAMPLES = """ -# Using merged -# -# ------------ -# Before State -# ------------ -# -# veos# show run | section lldp -# lldp timer 3000 -# lldp holdtime 100 -# lldp reinit 5 -# no lldp tlv-select management-address -# no lldp tlv-select system-description - -- name: Merge provided LLDP configuration with the existing configuration - eos_lldp_global: - config: - holdtime: 100 - tlv_select: - management_address: False - port_description: False - system_description: True - state: merged - -# ----------- -# After state -# ----------- -# -# veos# show run | section lldp -# lldp timer 3000 -# lldp holdtime 100 -# lldp reinit 5 -# no lldp tlv-select management-address -# no lldp tlv-select port-description - - -# Using replaced -# -# ------------ -# Before State -# ------------ -# -# veos# show run | section lldp -# lldp timer 3000 -# lldp holdtime 100 -# lldp reinit 5 -# no lldp tlv-select management-address -# no lldp tlv-select system-description - -- name: Replace existing LLDP device configuration with provided configuration - eos_lldp_global: - config: - holdtime: 100 - tlv_select: - management_address: False - port_description: False - system_description: True - state: replaced - -# ----------- -# After state -# ----------- -# -# veos# show run | section lldp -# lldp holdtime 100 -# no lldp tlv-select management-address -# no lldp tlv-select port-description - - -# Using deleted -# -# ------------ -# Before State -# ------------ -# -# veos# show run | section lldp -# lldp timer 3000 -# lldp holdtime 100 -# lldp reinit 5 -# no lldp tlv-select management-address -# no lldp tlv-select system-description - -- name: Delete existing LLDP configurations from the device - eos_lldp_global: - state: deleted - -# ----------- -# After state -# ----------- -# -# veos# show run | section ^lldp - - -""" -RETURN = """ -before: - description: The configuration as structured data prior to module invocation. - returned: always - type: dict - 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: dict - 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: ['lldp holdtime 100', 'no lldp timer', 'lldp tlv-select system-description'] -""" - - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.argspec.lldp_global.lldp_global import Lldp_globalArgs -from ansible.module_utils.network.eos.config.lldp_global.lldp_global import Lldp_global - - -def main(): - """ - Main entry point for module execution - - :returns: the result form module invocation - """ - module = AnsibleModule(argument_spec=Lldp_globalArgs.argument_spec, - supports_check_mode=True) - - result = Lldp_global(module).execute_module() - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_lldp_interfaces.py b/lib/ansible/modules/network/eos/eos_lldp_interfaces.py deleted file mode 100644 index 09e3178849..0000000000 --- a/lib/ansible/modules/network/eos/eos_lldp_interfaces.py +++ /dev/null @@ -1,252 +0,0 @@ -#!/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 eos_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: eos_lldp_interfaces -version_added: 2.9 -short_description: Manage Link Layer Discovery Protocol (LLDP) attributes of interfaces on Arista EOS devices. -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. - type: list - elements: dict - suboptions: - name: - description: - - Full name of the interface (i.e. Ethernet1). - type: str - receive: - description: - - Enable/disable LLDP RX on an interface. - type: bool - transmit: - description: - - Enable/disable LLDP TX on an interface. - type: bool - state: - description: - - The state of the configuration after module completion. - type: str - choices: - - merged - - replaced - - overridden - - deleted - default: merged -""" -EXAMPLES = """ -# Using merged -# -# -# ------------ -# Before state -# ------------ -# -# -# veos#show run | section ^interface -# interface Ethernet1 -# no lldp receive -# interface Ethernet2 -# no lldp transmit - -- name: Merge provided configuration with running configuration - eos_lldp_interfaces: - config: - - name: Ethernet1 - transmit: False - - name: Ethernet2 - transmit: False - state: merged - -# -# ------------ -# After state -# ------------ -# -# veos#show run | section ^interface -# interface Ethernet1 -# no lldp transmit -# no lldp receive -# interface Ethernet2 -# no lldp transmit - - -# Using replaced -# -# -# ------------ -# Before state -# ------------ -# -# -# veos#show run | section ^interface -# interface Ethernet1 -# no lldp receive -# interface Ethernet2 -# no lldp transmit - -- name: Replace existing LLDP configuration of specified interfaces with provided configuration - eos_lldp_interfaces: - config: - - name: Ethernet1 - transmit: False - state: replaced - -# -# ------------ -# After state -# ------------ -# -# veos#show run | section ^interface -# interface Ethernet1 -# no lldp transmit -# interface Ethernet2 -# no lldp transmit - - -# Using overridden -# -# -# ------------ -# Before state -# ------------ -# -# -# veos#show run | section ^interface -# interface Ethernet1 -# no lldp receive -# interface Ethernet2 -# no lldp transmit - -- name: Override the LLDP configuration of all the interfaces with provided configuration - eos_lldp_interfaces: - config: - - name: Ethernet1 - transmit: False - state: overridden - -# -# ------------ -# After state -# ------------ -# -# veos#show run | section ^interface -# interface Ethernet1 -# no lldp transmit -# interface Ethernet2 - - -# Using deleted -# -# -# ------------ -# Before state -# ------------ -# -# -# veos#show run | section ^interface -# interface Ethernet1 -# no lldp receive -# interface Ethernet2 -# no lldp transmit - -- name: Delete LLDP configuration of specified interfaces (or all interfaces if none are specified) - eos_lldp_interfaces: - state: deleted - -# -# ------------ -# After state -# ------------ -# -# veos#show run | section ^interface -# interface Ethernet1 -# interface Ethernet2 - - -""" -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: ['interface Ethernet1', 'no lldp transmit'] -""" - - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.argspec.lldp_interfaces.lldp_interfaces import Lldp_interfacesArgs -from ansible.module_utils.network.eos.config.lldp_interfaces.lldp_interfaces import Lldp_interfaces - - -def main(): - """ - Main entry point for module execution - - :returns: the result form module invocation - """ - module = AnsibleModule(argument_spec=Lldp_interfacesArgs.argument_spec, - supports_check_mode=True) - - result = Lldp_interfaces(module).execute_module() - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_logging.py b/lib/ansible/modules/network/eos/eos_logging.py deleted file mode 100644 index cdedcf5b01..0000000000 --- a/lib/ansible/modules/network/eos/eos_logging.py +++ /dev/null @@ -1,412 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2017, Ansible by Red Hat, inc -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network'} - -DOCUMENTATION = """ ---- -module: eos_logging -version_added: "2.4" -author: "Trishna Guha (@trishnaguha)" -short_description: Manage logging on network devices -description: - - This module provides declarative management of logging - on Arista Eos devices. -notes: - - Tested against EOS 4.15 -options: - dest: - description: - - Destination of the logs. - choices: ['on', 'host', 'console', 'monitor', 'buffered'] - name: - description: - - The hostname or IP address of the destination. - - Required when I(dest=host). - size: - description: - - Size of buffer. The acceptable value is in range from 10 to - 2147483647 bytes. - facility: - description: - - Set logging facility. - level: - description: - - Set logging severity levels. - choices: ['emergencies', 'alerts', 'critical', 'errors', - 'warnings', 'notifications', 'informational', 'debugging'] - aggregate: - description: List of logging definitions. - state: - description: - - State of the logging configuration. - default: present - choices: ['present', 'absent'] -extends_documentation_fragment: eos -""" - -EXAMPLES = """ -- name: configure host logging - eos_logging: - dest: host - name: 172.16.0.1 - state: present - -- name: remove host logging configuration - eos_logging: - dest: host - name: 172.16.0.1 - state: absent - -- name: configure console logging level and facility - eos_logging: - dest: console - facility: local7 - level: debugging - state: present - -- name: enable logging to all - eos_logging: - dest : on - -- name: configure buffer size - eos_logging: - dest: buffered - size: 5000 - -- name: Configure logging using aggregate - eos_logging: - aggregate: - - { dest: console, level: warnings } - - { dest: buffered, size: 480000 } - state: present -""" - -RETURN = """ -commands: - description: The list of configuration mode commands to send to the device - returned: always - type: list - sample: - - logging facility local7 - - logging host 172.16.0.1 -""" - -import re - - -from copy import deepcopy -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.common.utils import remove_default_spec -from ansible.module_utils.network.eos.eos import get_config, load_config -from ansible.module_utils.network.eos.eos import eos_argument_spec - - -DEST_GROUP = ['on', 'host', 'console', 'monitor', 'buffered'] -LEVEL_GROUP = ['emergencies', 'alerts', 'critical', 'errors', - 'warnings', 'notifications', 'informational', - 'debugging'] - - -def validate_size(value, module): - if value: - if not int(10) <= value <= int(2147483647): - module.fail_json(msg='size must be between 10 and 2147483647') - else: - return value - - -def map_obj_to_commands(updates, module): - commands = list() - want, have = updates - - for w in want: - dest = w['dest'] - name = w['name'] - size = w['size'] - facility = w['facility'] - level = w['level'] - state = w['state'] - del w['state'] - - if state == 'absent' and w in have: - if dest: - if dest == 'host': - commands.append('no logging host {0}'.format(name)) - - elif dest in DEST_GROUP: - commands.append('no logging {0}'.format(dest)) - - else: - module.fail_json(msg='dest must be among console, monitor, buffered, host, on') - - if facility: - commands.append('no logging facility {0}'.format(facility)) - - if state == 'present' and w not in have: - if facility: - present = False - - # Iterate over every dictionary in the 'have' list to check if - # similar configuration for facility exists or not - - for entry in have: - if not entry['dest'] and entry['facility'] == facility: - present = True - - if not present: - commands.append('logging facility {0}'.format(facility)) - - if dest == 'host': - commands.append('logging host {0}'.format(name)) - - elif dest == 'on': - commands.append('logging on') - - elif dest == 'buffered' and size: - - present = False - - # Deals with the following two cases: - # Case 1: logging buffered <size> <level> - # logging buffered <same-size> - # - # Case 2: Same buffered logging configuration - # already exists (i.e., both size & - # level are same) - - for entry in have: - if entry['dest'] == 'buffered' and entry['size'] == size: - - if not level or entry['level'] == level: - present = True - - if not present: - if size and level: - commands.append('logging buffered {0} {1}'.format(size, level)) - else: - commands.append('logging buffered {0}'.format(size)) - - else: - if dest: - dest_cmd = 'logging {0}'.format(dest) - if level: - dest_cmd += ' {0}'.format(level) - - commands.append(dest_cmd) - return commands - - -def parse_facility(line): - facility = None - match = re.search(r'logging facility (\S+)', line, re.M) - if match: - facility = match.group(1) - - return facility - - -def parse_size(line, dest): - size = None - - if dest == 'buffered': - match = re.search(r'logging buffered (\S+)', line, re.M) - if match: - try: - int_size = int(match.group(1)) - except ValueError: - int_size = None - - if int_size: - if isinstance(int_size, int): - size = str(match.group(1)) - else: - size = str(10) - - return size - - -def parse_name(line, dest): - name = None - if dest == 'host': - match = re.search(r'logging host (\S+)', line, re.M) - if match: - name = match.group(1) - - return name - - -def parse_level(line, dest): - level = None - - if dest != 'host': - - # Line for buffer logging entry in running-config is of the form: - # logging buffered <size> <level> - - if dest == 'buffered': - match = re.search(r'logging buffered (?:\d+) (\S+)', line, re.M) - - else: - match = re.search(r'logging {0} (\S+)'.format(dest), line, re.M) - - if match: - if match.group(1) in LEVEL_GROUP: - level = match.group(1) - - return level - - -def map_config_to_obj(module): - obj = [] - - data = get_config(module, flags=['section logging']) - - for line in data.split('\n'): - - match = re.search(r'logging (\S+)', line, re.M) - - if match: - if match.group(1) in DEST_GROUP: - dest = match.group(1) - - else: - dest = None - - obj.append({'dest': dest, - 'name': parse_name(line, dest), - 'size': parse_size(line, dest), - 'facility': parse_facility(line), - 'level': parse_level(line, dest)}) - - return obj - - -def parse_obj(obj, module): - if module.params['size'] is None: - obj.append({ - 'dest': module.params['dest'], - 'name': module.params['name'], - 'size': module.params['size'], - 'facility': module.params['facility'], - 'level': module.params['level'], - 'state': module.params['state'] - }) - - else: - obj.append({ - 'dest': module.params['dest'], - 'name': module.params['name'], - 'size': str(validate_size(module.params['size'], module)), - 'facility': module.params['facility'], - 'level': module.params['level'], - 'state': module.params['state'] - }) - - return obj - - -def map_params_to_obj(module, required_if=None): - obj = [] - aggregate = module.params.get('aggregate') - if aggregate: - for item in aggregate: - for key in item: - if item.get(key) is None: - item[key] = module.params[key] - - module._check_required_if(required_if, item) - d = item.copy() - - if d['dest'] != 'host': - d['name'] = None - - if d['dest'] == 'buffered': - if 'size' in d: - d['size'] = str(validate_size(d['size'], module)) - elif 'size' not in d: - d['size'] = str(10) - else: - pass - - if d['dest'] != 'buffered': - d['size'] = None - - obj.append(d) - - else: - if module.params['dest'] != 'host': - module.params['name'] = None - - if module.params['dest'] == 'buffered': - if not module.params['size']: - module.params['size'] = str(10) - else: - module.params['size'] = None - - parse_obj(obj, module) - - return obj - - -def main(): - """ main entry point for module execution - """ - element_spec = dict( - dest=dict(choices=DEST_GROUP), - name=dict(), - size=dict(type='int'), - facility=dict(), - level=dict(choices=LEVEL_GROUP), - state=dict(default='present', choices=['present', 'absent']), - ) - - aggregate_spec = deepcopy(element_spec) - - # remove default in aggregate spec, to handle common arguments - remove_default_spec(aggregate_spec) - - argument_spec = dict( - aggregate=dict(type='list', elements='dict', options=aggregate_spec), - ) - - argument_spec.update(element_spec) - argument_spec.update(eos_argument_spec) - - required_if = [('dest', 'host', ['name'])] - - module = AnsibleModule(argument_spec=argument_spec, - required_if=required_if, - supports_check_mode=True) - - warnings = list() - - result = {'changed': False} - if warnings: - result['warnings'] = warnings - - have = map_config_to_obj(module) - want = map_params_to_obj(module, required_if=required_if) - - commands = map_obj_to_commands((want, have), module) - result['commands'] = commands - - if commands: - commit = not module.check_mode - response = load_config(module, commands, commit=commit) - if response.get('diff') and module._diff: - result['diff'] = {'prepared': response.get('diff')} - result['session_name'] = response.get('session') - result['changed'] = True - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_static_routes.py b/lib/ansible/modules/network/eos/eos_static_routes.py deleted file mode 100644 index c04491beb8..0000000000 --- a/lib/ansible/modules/network/eos/eos_static_routes.py +++ /dev/null @@ -1,1444 +0,0 @@ -#!/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 eos_static_routes -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network' -} - -DOCUMENTATION = """ ---- -module: eos_static_routes -version_added: "2.10" -short_description: Configures and manages attributes of static routes on Arista EOS platforms. -description: This module configures and manages the attributes of static routes on Arista EOS platforms. -author: Gomathi Selvi Srinivasan (@GomathiselviS) -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 list of configurations for static routes. - type: list - elements: dict - suboptions: - vrf: - description: - - The VRF to which the static route(s) belong. - type: str - address_families: - description: A dictionary specifying the address family to which the static route(s) belong. - type: list - elements: dict - suboptions: - afi: - description: - - Specifies the top level address family indicator. - type: str - choices: ['ipv4', 'ipv6'] - required: True - routes: - description: A dictionary that specifies the static route configurations. - elements: dict - type: list - suboptions: - dest: - description: - - Destination IPv4 subnet (CIDR or address-mask notation). - - The address format is <v4/v6 address>/<mask> or <v4/v6 address> <mask>. - - The mask is number in range 0-32 for IPv4 and in range 0-128 for IPv6. - type: str - required: True - next_hops: - description: - - Details of route to be taken. - type: list - elements: dict - suboptions: - forward_router_address: - description: - - Forwarding router's address on destination interface. - type: str - interface: - description: - - Outgoing interface to take. For anything except 'null0', then next hop IP address should also be configured. - - IP address of the next hop router or - - null0 Null0 interface or - - ethernet e_num Ethernet interface or - - loopback l_num Loopback interface or - - management m_num Management interface or - - port-channel p_num - - vlan v_num - - vxlan vx_num - - Nexthop-Group Specify nexthop group name - - Tunnel Tunnel interface - - vtep Configure VXLAN Tunnel End Points - type: str - nexthop_grp: - description: - - Nexthop group - type: str - admin_distance: - description: - - Preference or administrative distance of route (range 1-255). - type: int - description: - description: - - Name of the static route. - type: str - tag: - description: - - Route tag value (ranges from 0 to 4294967295). - type: int - track: - description: - - Track value (range 1 - 512). Track must already be configured on the device before adding the route. - type: str - mpls_label: - description: - - MPLS label - type: int - vrf: - description: - - VRF of the destination. - type: str - running_config: - description: - - The module, by default, will connect to the remote device and - retrieve the current running-config to use as a base for comparing - against the contents of source. There are times when it is not - desirable to have the task get the current running-config for - every task in a playbook. The I(running_config) argument allows the - implementer to pass in the configuration to use as the base - config for comparison. This value of this option should be the - output received from device by executing command - version_added: "2.10" - type: str - state: - description: - - The state the configuration should be left in. - type: str - choices: - ['deleted', 'merged', 'overridden', 'replaced', 'gathered', 'rendered', 'parsed'] - default: - merged -""" -EXAMPLES = """ -# Using deleted - -# Various scenarios for delete operations: - -# Before state: -# ------------ -# veos(config)#show running-config | grep route -# ip route 10.2.2.0/24 Ethernet1 -# ip route 10.2.2.0/24 64.1.1.1 label 17 33 -# ip route 33.33.33.0/24 Nexthop-Group testgrp -# ip route vrf testvrf 22.65.1.0/24 Null0 90 name testroute -# ipv6 route 5222:5::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Ethernet1 55 -# ipv6 route vrf testvrf 2222:6::/64 Null0 90 name testroute1 -# veos(config)# - -- name: Delete nexthop - eos_static_routes: - config: - - address_families: - - afi: ipv4 - routes: - - dest: 10.2.2.0/24 - next_hops: - - interface: 64.1.1.1 - mpls_label: 17 - admin_distance: 33 - - dest: "33.33.33.0 255.255.255.0" - next_hops: - - interface: 'Nexthop-Group testgrp' - state: "deleted" - -# "after": [ -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "10.2.2.0/24", -# "next_hops": [ -# { -# "interface": "Ethernet1" -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "5222:5::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# } -# ] -# } -# ] -# } -# ] -# }, -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "22.65.1.0/24", -# "next_hops": [ -# { -# "admin_distance": 90, -# "description": "testroute", -# "interface": "Null0" -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "2222:6::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# }, -# { -# "admin_distance": 55, -# "interface": "Ethernet1" -# }, -# { -# "admin_distance": 90, -# "description": "testroute1", -# "interface": "Null0" -# } -# ] -# } -# ] -# } -# ], -# "vrf": "testvrf" -# } -# ], -# "before": [ -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "10.2.2.0/24", -# "next_hops": [ -# { -# "interface": "Ethernet1" -# }, -# { -# "admin_distance": 33, -# "interface": "64.1.1.1", -# "mpls_label": 17 -# } -# ] -# }, -# { -# "dest": "33.33.33.0/24", -# "next_hops": [ -# { -# "nexthop_grp": "testgrp" -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "5222:5::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# } -# ] -# } -# ] -# } -# ] -# }, -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "22.65.1.0/24", -# "next_hops": [ -# { -# "admin_distance": 90, -# "description": "testroute", -# "interface": "Null0" -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "2222:6::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# }, -# { -# "admin_distance": 55, -# "interface": "Ethernet1" -# }, -# { -# "admin_distance": 90, -# "description": "testroute1", -# "interface": "Null0" -# } -# ] -# } -# ] -# } -# ], -# "vrf": "testvrf" -# } -# ], -# "changed": true, -# "commands": [ -# "no ip route 10.2.2.0/24 64.1.1.1 label 17 33", -# "no ip route 33.33.33.0/24 Nexthop-Group testgrp" -# ] - - -# After State -# ----------- - -# veos(config)#show running-config | grep route -# ip route 10.2.2.0/24 Ethernet1 -# ip route vrf testvrf 22.65.1.0/24 Null0 90 name testroute -# ipv6 route 5222:5::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Ethernet1 55 -# ipv6 route vrf testvrf 2222:6::/64 Null0 90 name testroute1 -# veos(config)# - - -# Before State -# ____________ - -# veos(config)#show running-config | grep route -# ip route 10.2.2.0/24 Ethernet1 -# ip route vrf testvrf 22.65.1.0/24 Null0 90 name testroute -# ipv6 route 5222:5::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Ethernet1 55 -# ipv6 route vrf testvrf 2222:6::/64 Null0 90 name testroute1 -# veos(config)# - -- name: Delete route - eos_static_routes: - config: - - address_families: - - afi: ipv4 - routes: - - dest: 10.2.2.0/24 - state: "deleted" - -# "after": [ -# { -# "address_families": [ -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "5222:5::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# } -# ] -# } -# ] -# } -# ] -# }, -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "22.65.1.0/24", -# "next_hops": [ -# { -# "admin_distance": 90, -# "description": "testroute", -# "interface": "Null0" -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "2222:6::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# }, -# { -# "admin_distance": 55, -# "interface": "Ethernet1" -# }, -# { -# "admin_distance": 90, -# "description": "testroute1", -# "interface": "Null0" -# } -# ] -# } -# ] -# } -# ], -# "vrf": "testvrf" -# } -# ], -# "before": [ -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "10.2.2.0/24", -# "next_hops": [ -# { -# "interface": "Ethernet1" -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "5222:5::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# } -# ] -# } -# ] -# } -# ] -# }, -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "22.65.1.0/24", -# "next_hops": [ -# { -# "admin_distance": 90, -# "description": "testroute", -# "interface": "Null0" -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "2222:6::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# }, -# { -# "admin_distance": 55, -# "interface": "Ethernet1" -# }, -# { -# "admin_distance": 90, -# "description": "testroute1", -# "interface": "Null0" -# } -# ] -# } -# ] -# } -# ], -# "vrf": "testvrf" -# } -# ], -# "changed": true, -# "commands": [ -# "no ip route 10.2.2.0/24 Ethernet1" -# ] - -# After State -# ----------- -# veos(config)#show running-config | grep route -# ip route vrf testvrf 22.65.1.0/24 Null0 90 name testroute -# ipv6 route 5222:5::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Ethernet1 55 -# ipv6 route vrf testvrf 2222:6::/64 Null0 90 name testroute1 -# veos(config)# - - -# Before State: -# ------------ - -# veos(config)#show running-config | grep route -# ip route vrf testvrf 22.65.1.0/24 Null0 90 name testroute -# ipv6 route 5222:5::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Ethernet1 55 -# ipv6 route vrf testvrf 2222:6::/64 Null0 90 name testroute1 -# veos(config)# - -- name: Delete afi - eos_static_routes: - config: - - vrf: "testvrf" - address_families: - - afi: "ipv4" - state: "deleted" - -# "after": [ -# { -# "address_families": [ -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "5222:5::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# } -# ] -# } -# ] -# } -# ] -# }, -# { -# "address_families": [ -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "2222:6::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# }, -# { -# "admin_distance": 55, -# "interface": "Ethernet1" -# }, -# { -# "admin_distance": 90, -# "description": "testroute1", -# "interface": "Null0" -# } -# ] -# } -# ] -# } -# ], -# "vrf": "testvrf" -# } -# ], -# "before": [ -# { -# "address_families": [ -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "5222:5::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# } -# ] -# } -# ] -# } -# ] -# }, -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "22.65.1.0/24", -# "next_hops": [ -# { -# "admin_distance": 90, -# "description": "testroute", -# "interface": "Null0" -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "2222:6::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# }, -# { -# "admin_distance": 55, -# "interface": "Ethernet1" -# }, -# { -# "admin_distance": 90, -# "description": "testroute1", -# "interface": "Null0" -# } -# ] -# } -# ] -# } -# ], -# "vrf": "testvrf" -# } -# ], -# "changed": true, -# "commands": [ -# "no ip route vrf testvrf 22.65.1.0/24 Null0 90 name testroute" -# ], - -# After State -# ___________ - -# veos(config)#show running-config | grep route -# ipv6 route 5222:5::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Ethernet1 55 -# ipv6 route vrf testvrf 2222:6::/64 Null0 90 name testroute1 - -# Before State -#------------- - -# veos(config)#show running-config | grep route -# ipv6 route 5222:5::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Ethernet1 55 -# ipv6 route vrf testvrf 2222:6::/64 Null0 90 name testroute1 - -- name: Delete vrf - eos_static_routes: - config: - - vrf: testvrf - state: "deleted" - -# "after": [ -# { -# "address_families": [ -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "5222:5::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# } -# ] -# } -# ] -# } -# ] -# } -# ], -# "before": [ -# { -# "address_families": [ -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "5222:5::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# } -# ] -# } -# ] -# } -# ] -# }, -# { -# "address_families": [ -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "2222:6::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# }, -# { -# "admin_distance": 55, -# "interface": "Ethernet1" -# }, -# { -# "admin_distance": 90, -# "description": "testroute1", -# "interface": "Null0" -# } -# ] -# } -# ] -# } -# ], -# "vrf": "testvrf" -# } -# ], -# "changed": true, -# "commands": [ -# "no ipv6 route vrf testvrf 2222:6::/64 Management1 4312:100::1", -# "no ipv6 route vrf testvrf 2222:6::/64 Ethernet1 55", -# "no ipv6 route vrf testvrf 2222:6::/64 Null0 90 name testroute1" -# ] -# -# After State: -# ----------- - -# veos(config)#show running-config | grep route -# ipv6 route 5222:5::/64 Management1 4312:100::1 -# veos(config)# - - -# -# Using merged - -# Before : [ -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "165.10.1.0/24", -# "next_hops": [ -# { -# "admin_distance": 100, -# "interface": "Ethernet1" -# } -# ] -# }, -# { -# "dest": "172.17.252.0/24", -# "next_hops": [ -# { -# "nexthop_grp": "testgroup" -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "5001::/64", -# "next_hops": [ -# { -# "admin_distance": 50, -# "interface": "Ethernet1" -# } -# ] -# } -# ] -# } -# ] -# }, -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "130.1.122.0/24", -# "next_hops": [ -# { -# "interface": "Ethernet1", -# "tag": 50 -# } -# ] -# } -# ] -# } -# ], -# "vrf": "testvrf" -# } -# ] -# -# Before State -# ------------- -# veos(config)#show running-config | grep "route" -# ip route 165.10.1.0/24 Ethernet1 100 -# ip route 172.17.252.0/24 Nexthop-Group testgroup -# ip route vrf testvrf 130.1.122.0/24 Ethernet1 tag 50 -# ipv6 route 5001::/64 Ethernet1 50 -# veos(config)# - -- name: Merge new static route configuration - eos_static_routes: - config: - - vrf: testvrf - address_families: - - afi: ipv6 - routes: - - dest: 2211::0/64 - next_hop: - - forward_router_address: 100:1::2 - interface: "Ethernet1" - state: merged - -# After State -# ----------- - -#After [ -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "165.10.1.0/24", -# "next_hops": [ -# { -# "admin_distance": 100, -# "interface": "Ethernet1" -# } -# ] -# }, -# { -# "dest": "172.17.252.0/24", -# "next_hops": [ -# { -# "nexthop_grp": "testgroup" -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "5001::/64", -# "next_hops": [ -# { -# "admin_distance": 50, -# "interface": "Ethernet1" -# } -# ] -# } -# ] -# } -# ] -# }, -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "130.1.122.0/24", -# "next_hops": [ -# { -# "interface": "Ethernet1", -# "tag": 50 -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "2211::0/64", -# "next_hops": [ -# { -# "aforward_router_address": 100:1::2 -# "interface": "Ethernet1" -# } -# ] -# } -# ] -# } - -# ], -# "vrf": "testvrf" -# } -# ] -# -# veos(config)#show running-config | grep "route" -# ip route 165.10.1.0/24 Ethernet1 100 -# ip route 172.17.252.0/24 Nexthop-Group testgroup -# ip route vrf testvrf 130.1.122.0/24 Ethernet1 tag 50 -# ipv6 route 2211::/64 Ethernet1 100:1::2 -# ipv6 route 5001::/64 Ethernet1 50 -# veos(config)# - - -# Using overridden - - -# Before State -# ------------- - -# "before": [ -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "165.10.1.0/24", -# "next_hops": [ -# { -# "admin_distance": 100, -# "interface": "Ethernet1" -# } -# ] -# }, -# { -# "dest": "172.17.252.0/24", -# "next_hops": [ -# { -# "nexthop_grp": "testgroup" -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "5001::/64", -# "next_hops": [ -# { -# "admin_distance": 50, -# "interface": "Ethernet1" -# } -# ] -# } -# ] -# } -# ] -# }, -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "130.1.122.0/24", -# "next_hops": [ -# { -# "interface": "Ethernet1", -# "tag": 50 -# } -# ] -# } -# ] -# } -# ], -# "vrf": "testvrf" -# } -# ] -# veos(config)#show running-config | grep "route" -# ip route 165.10.1.0/24 Ethernet1 100 -# ip route 172.17.252.0/24 Nexthop-Group testgroup -# ip route vrf testvrf 130.1.122.0/24 Ethernet1 tag 50 -# ipv6 route 5001::/64 Ethernet1 50 -# veos(config)# - -- name: Overridden static route configuration - eos_static_routes: - config: - - address_families: - - afi: ipv4 - routes: - - dest: 10.2.2.0/24 - next_hop: - - interface: "Ethernet1" - state: replaced - -# After State -# ----------- - -# "after": [ -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "10.2.2.0/24", -# "next_hops": [ -# { -# "interface": "Ethernet1" -# } -# ] -# } -# ] -# } -# ] -# } -# ] -# veos(config)#show running-config | grep "route" -# ip route 10.2.2.0/24 Ethernet1 -# veos(config)# - - -# Using replaced - -# Before State -# ------------- - -# ip route 10.2.2.0/24 Ethernet1 -# ip route 10.2.2.0/24 64.1.1.1 label 17 33 -# ip route 33.33.33.0/24 Nexthop-Group testgrp -# ip route vrf testvrf 22.65.1.0/24 Null0 90 name testroute -# ipv6 route 5222:5::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Ethernet1 55 -# ipv6 route vrf testvrf 2222:6::/64 Null0 90 name testroute1 - -# [ -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "10.2.2.0/24", -# "next_hops": [ -# { -# "interface": "Ethernet1" -# }, -# { -# "admin_distance": 33, -# "interface": "64.1.1.1", -# "mpls_label": 17 -# } -# ] -# }, -# { -# "dest": "33.33.33.0/24", -# "next_hops": [ -# { -# "nexthop_grp": "testgrp" -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "5222:5::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# } -# ] -# } -# ] -# } -# ] -# }, -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "22.65.1.0/24", -# "next_hops": [ -# { -# "admin_distance": 90, -# "description": "testroute", -# "interface": "Null0" -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "2222:6::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# }, -# { -# "admin_distance": 90, -# "description": "testroute1", -# "interface": "Null0" -# } -# ] -# } -# ] -# } -# ], -# "vrf": "testvrf" -# } -# ] - -- name: Replace nexthop - eos_static_routes: - config: - - vrf: testvrf - address_families: - - afi: ipv6 - routes: - - dest: 2222:6::/64 - next_hops: - - admin_distance: 55 - interface: "Ethernet1" - state: "replaced" - -# After State -# ----------- - -# veos(config)#show running-config | grep route -# ip route 10.2.2.0/24 Ethernet1 -# ip route 10.2.2.0/24 64.1.1.1 label 17 33 -# ip route 33.33.33.0/24 Nexthop-Group testgrp -# ip route vrf testvrf 22.65.1.0/24 Null0 90 name testroute -# ipv6 route 5222:5::/64 Management1 4312:100::1 -# ipv6 route vrf testvrf 2222:6::/64 Ethernet1 55 - -# "after": [ -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "10.2.2.0/24", -# "next_hops": [ -# { -# "interface": "Ethernet1" -# }, -# { -# "admin_distance": 33, -# "interface": "64.1.1.1", -# "mpls_label": 17 -# } -# ] -# }, -# { -# "dest": "33.33.33.0/24", -# "next_hops": [ -# { -# "nexthop_grp": "testgrp" -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "5222:5::/64", -# "next_hops": [ -# { -# "forward_router_address": "4312:100::1", -# "interface": "Management1" -# } -# ] -# } -# ] -# } -# ] -# }, -# { -# "address_families": [ -# { -# "afi": "ipv4", -# "routes": [ -# { -# "dest": "22.65.1.0/24", -# "next_hops": [ -# { -# "admin_distance": 90, -# "description": "testroute", -# "interface": "Null0" -# } -# ] -# } -# ] -# }, -# { -# "afi": "ipv6", -# "routes": [ -# { -# "dest": "2222:6::/64", -# "next_hops": [ -# { -# "admin_distance": 55, -# "interface": "Ethernet1" -# } -# ] -# } -# ] -# } -# ], -# "vrf": "testvrf" -# } -# ] - -# Before State -# ------------- -# veos(config)#show running-config | grep "route" -# ip route 165.10.1.0/24 Ethernet1 10.1.1.2 100 -# ipv6 route 5001::/64 Ethernet1 -# veos(config)# - - -- name: Gather the exisitng condiguration - eos_static_routes: - state: gathered - -# returns : -# eos_static_routes: -# config: -# - address_families: -# - afi: ipv4 -# routes: -# - dest: 165.10.1.0/24 -# next_hop: -# - forward_router_address: 10.1.1.2 -# interface: "Ethernet1" -# admin_distance: 100 -# - afi: ipv6 -# routes: -# - dest: 5001::/64 -# next_hop: -# - interface: "Ethernet1" - - -# Using rendered - -# eos_static_routes: -# config: -# - address_families: -# - afi: ipv4 -# routes: -# - dest: 165.10.1.0/24 -# next_hop: -# - forward_router_address: 10.1.1.2 -# interface: "Ethernet1" -# admin_distance: 100 -# - afi: ipv6 -# routes: -# - dest: 5001::/64 -# next_hop: -# - interface: "Ethernet1" - -# returns: - -# ip route 165.10.1.0/24 Ethernet1 10.1.1.2 100 -# ipv6 route 5001::/64 Ethernet1 - - -""" -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: - - ip route vrf vrf1 192.2.2.0/24 125.2.3.1 93 -rendered: - description: The set of CLI commands generated from the value in C(config) option - returned: When C(state) is I(rendered) - type: list - sample: > - "address_families": [ - { - "afi": "ipv4", - "routes": [ - { - "dest": "192.2.2.0/24", - "next_hops": [ - { - "admin_distance": 93, - "description": null, - "forward_router_address": null, - "interface": "125.2.3.1", - "mpls_label": null, - "nexthop_grp": null, - "tag": null, - "track": null, - "vrf": null - } - ] - } - ] - } - ], - "vrf": "vrf1" - } - ], - "running_config": null, - "state": "rendered" - } -gathered: - description: The configuration as structured data transformed for the running configuration - fetched from remote host - returned: When C(state) is I(gathered) - type: list - sample: > - The configuration returned will always be in the same format - of the parameters above. -parsed: - description: The configuration as structured data transformed for the value of - C(running_config) option - returned: When C(state) is I(parsed) - type: list - sample: > - The configuration returned will always be in the same format - of the parameters above. -""" - - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.argspec.static_routes.static_routes import Static_routesArgs -from ansible.module_utils.network.eos.config.static_routes.static_routes import Static_routes - - -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',)), - ('state', 'parsed', ('running_config',))] - mutually_exclusive = [('config', 'running_config')] - - module = AnsibleModule(argument_spec=Static_routesArgs.argument_spec, - required_if=required_if, - supports_check_mode=True, - mutually_exclusive=mutually_exclusive) - - result = Static_routes(module).execute_module() - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_system.py b/lib/ansible/modules/network/eos/eos_system.py deleted file mode 100644 index 9d10393811..0000000000 --- a/lib/ansible/modules/network/eos/eos_system.py +++ /dev/null @@ -1,339 +0,0 @@ -#!/usr/bin/python -# -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network'} - - -DOCUMENTATION = """ ---- -module: eos_system -version_added: "2.3" -author: "Peter Sprygada (@privateip)" -short_description: Manage the system attributes on Arista EOS devices -description: - - This module provides declarative management of node system attributes - on Arista EOS devices. It provides an option to configure host system - parameters or remove those parameters from the device active - configuration. -extends_documentation_fragment: eos -notes: - - Tested against EOS 4.15 -options: - hostname: - description: - - Configure the device hostname parameter. This option takes an ASCII string value. - domain_name: - description: - - Configure the IP domain name - on the remote device to the provided value. Value - should be in the dotted name form and will be - appended to the C(hostname) to create a fully-qualified - domain name. - domain_search: - description: - - Provides the list of domain suffixes to - append to the hostname for the purpose of doing name resolution. - This argument accepts a list of names and will be reconciled - with the current active configuration on the running node. - aliases: ['domain_list'] - lookup_source: - description: - - Provides one or more source - interfaces to use for performing DNS lookups. The interface - provided in C(lookup_source) can only exist in a single VRF. This - argument accepts either a list of interface names or a list of - hashes that configure the interface name and VRF name. See - examples. - name_servers: - description: - - List of DNS name servers by IP address to use to perform name resolution - lookups. This argument accepts either a list of DNS servers or - a list of hashes that configure the name server and VRF name. See - examples. - state: - description: - - State of the configuration - values in the device's current active configuration. When set - to I(present), the values should be configured in the device active - configuration and when set to I(absent) the values should not be - in the device active configuration - default: present - choices: ['present', 'absent'] -""" - -EXAMPLES = """ -- name: configure hostname and domain-name - eos_system: - hostname: eos01 - domain_name: test.example.com - -- name: remove configuration - eos_system: - state: absent - -- name: configure DNS lookup sources - eos_system: - lookup_source: Management1 - -- name: configure DNS lookup sources with VRF support - eos_system: - lookup_source: - - interface: Management1 - vrf: mgmt - - interface: Ethernet1 - vrf: myvrf - -- name: configure name servers - eos_system: - name_servers: - - 8.8.8.8 - - 8.8.4.4 - -- name: configure name servers with VRF support - eos_system: - name_servers: - - { server: 8.8.8.8, vrf: mgmt } - - { server: 8.8.4.4, vrf: mgmt } -""" - -RETURN = """ -commands: - description: The list of configuration mode commands to send to the device - returned: always - type: list - sample: - - hostname eos01 - - ip domain-name test.example.com -session_name: - description: The EOS config session name used to load the configuration - returned: changed - type: str - sample: ansible_1479315771 -""" -import re - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.common.utils import ComplexList -from ansible.module_utils.network.eos.eos import load_config, get_config -from ansible.module_utils.network.eos.eos import eos_argument_spec - -_CONFIGURED_VRFS = None - - -def has_vrf(module, vrf): - global _CONFIGURED_VRFS - if _CONFIGURED_VRFS is not None: - return vrf in _CONFIGURED_VRFS - config = get_config(module) - _CONFIGURED_VRFS = re.findall(r'vrf definition (\S+)', config) - _CONFIGURED_VRFS.append('default') - return vrf in _CONFIGURED_VRFS - - -def map_obj_to_commands(want, have, module): - commands = list() - state = module.params['state'] - - def needs_update(x): - return want.get(x) and (want.get(x) != have.get(x)) - - if state == 'absent': - if have['domain_name']: - commands.append('no ip domain-name') - - if have['hostname'] != 'localhost': - commands.append('no hostname') - - if state == 'present': - if needs_update('hostname'): - commands.append('hostname %s' % want['hostname']) - - if needs_update('domain_name'): - commands.append('ip domain-name %s' % want['domain_name']) - - if want['domain_list']: - # handle domain_list items to be removed - for item in set(have['domain_list']).difference(want['domain_list']): - commands.append('no ip domain-list %s' % item) - - # handle domain_list items to be added - for item in set(want['domain_list']).difference(have['domain_list']): - commands.append('ip domain-list %s' % item) - - if want['lookup_source']: - # handle lookup_source items to be removed - for item in have['lookup_source']: - if item not in want['lookup_source']: - if item['vrf']: - if not has_vrf(module, item['vrf']): - module.fail_json(msg='vrf %s is not configured' % item['vrf']) - values = (item['vrf'], item['interface']) - commands.append('no ip domain lookup vrf %s source-interface %s' % values) - else: - commands.append('no ip domain lookup source-interface %s' % item['interface']) - - # handle lookup_source items to be added - for item in want['lookup_source']: - if item not in have['lookup_source']: - if item['vrf']: - if not has_vrf(module, item['vrf']): - module.fail_json(msg='vrf %s is not configured' % item['vrf']) - values = (item['vrf'], item['interface']) - commands.append('ip domain lookup vrf %s source-interface %s' % values) - else: - commands.append('ip domain lookup source-interface %s' % item['interface']) - - if want['name_servers']: - # handle name_servers items to be removed. Order does matter here - # since name servers can only be in one vrf at a time - for item in have['name_servers']: - if item not in want['name_servers']: - if not has_vrf(module, item['vrf']): - module.fail_json(msg='vrf %s is not configured' % item['vrf']) - if item['vrf'] not in ('default', None): - values = (item['vrf'], item['server']) - commands.append('no ip name-server vrf %s %s' % values) - else: - commands.append('no ip name-server %s' % item['server']) - - # handle name_servers items to be added - for item in want['name_servers']: - if item not in have['name_servers']: - if not has_vrf(module, item['vrf']): - module.fail_json(msg='vrf %s is not configured' % item['vrf']) - if item['vrf'] not in ('default', None): - values = (item['vrf'], item['server']) - commands.append('ip name-server vrf %s %s' % values) - else: - commands.append('ip name-server %s' % item['server']) - - return commands - - -def parse_hostname(config): - match = re.search(r'^hostname (\S+)', config, re.M) - if match: - return match.group(1) - - -def parse_domain_name(config): - match = re.search(r'^ip domain-name (\S+)', config, re.M) - if match: - return match.group(1) - - -def parse_lookup_source(config): - objects = list() - regex = r'ip domain lookup (?:vrf (\S+) )*source-interface (\S+)' - for vrf, intf in re.findall(regex, config, re.M): - if len(vrf) == 0: - vrf = None - objects.append({'interface': intf, 'vrf': vrf}) - return objects - - -def parse_name_servers(config): - objects = list() - for vrf, addr in re.findall(r'ip name-server vrf (\S+) (\S+)', config, re.M): - objects.append({'server': addr, 'vrf': vrf}) - return objects - - -def map_config_to_obj(module): - config = get_config(module) - return { - 'hostname': parse_hostname(config), - 'domain_name': parse_domain_name(config), - 'domain_list': re.findall(r'^ip domain-list (\S+)', config, re.M), - 'lookup_source': parse_lookup_source(config), - 'name_servers': parse_name_servers(config) - } - - -def map_params_to_obj(module): - obj = { - 'hostname': module.params['hostname'], - 'domain_name': module.params['domain_name'], - 'domain_list': module.params['domain_list'] - } - - lookup_source = ComplexList(dict( - interface=dict(key=True), - vrf=dict() - ), module) - - name_servers = ComplexList(dict( - server=dict(key=True), - vrf=dict(default='default') - ), module) - - for arg, cast in [('lookup_source', lookup_source), ('name_servers', name_servers)]: - if module.params[arg] is not None: - obj[arg] = cast(module.params[arg]) - else: - obj[arg] = None - - return obj - - -def main(): - """ main entry point for module execution - """ - argument_spec = dict( - hostname=dict(), - - domain_name=dict(), - domain_list=dict(type='list', aliases=['domain_search']), - - # { interface: <str>, vrf: <str> } - lookup_source=dict(type='list'), - - # { server: <str>; vrf: <str> } - name_servers=dict(type='list'), - - state=dict(default='present', choices=['present', 'absent']) - ) - - argument_spec.update(eos_argument_spec) - - module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True) - - result = {'changed': False} - - want = map_params_to_obj(module) - have = map_config_to_obj(module) - - commands = map_obj_to_commands(want, have, module) - result['commands'] = commands - - if commands: - commit = not module.check_mode - response = load_config(module, commands, commit=commit) - if response.get('diff') and module._diff: - result['diff'] = {'prepared': response.get('diff')} - result['session_name'] = response.get('session') - result['changed'] = True - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_user.py b/lib/ansible/modules/network/eos/eos_user.py deleted file mode 100644 index d48fd0528d..0000000000 --- a/lib/ansible/modules/network/eos/eos_user.py +++ /dev/null @@ -1,400 +0,0 @@ -#!/usr/bin/python -# -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network'} - - -DOCUMENTATION = """ ---- -module: eos_user -version_added: "2.3" -author: "Peter Sprygada (@privateip)" -short_description: Manage the collection of local users on EOS devices -description: - - This module provides declarative management of the local usernames - configured on Arista EOS devices. It allows playbooks to manage - either individual usernames or the collection of usernames in the - current running config. It also supports purging usernames from the - configuration that are not explicitly defined. -extends_documentation_fragment: eos -notes: - - Tested against EOS 4.15 -options: - aggregate: - description: - - The set of username objects to be configured on the remote - Arista EOS device. The list entries can either be the username - or a hash of username and properties. This argument is mutually - exclusive with the C(username) argument. - aliases: ['users', 'collection'] - version_added: "2.4" - name: - description: - - The username to be configured on the remote Arista EOS - device. This argument accepts a stringv value and is mutually - exclusive with the C(aggregate) argument. - Please note that this option is not same as C(provider username). - version_added: "2.4" - configured_password: - description: - - The password to be configured on the remote Arista EOS device. The - password needs to be provided in clear and it will be encrypted - on the device. - Please note that this option is not same as C(provider password). - version_added: "2.4" - update_password: - description: - - Since passwords are encrypted in the device running config, this - argument will instruct the module when to change the password. When - set to C(always), the password will always be updated in the device - and when set to C(on_create) the password will be updated only if - the username is created. - default: always - choices: ['on_create', 'always'] - privilege: - description: - - The C(privilege) argument configures the privilege level of the - user when logged into the system. This argument accepts integer - values in the range of 1 to 15. - role: - description: - - Configures the role for the username in the - device running configuration. The argument accepts a string value - defining the role name. This argument does not check if the role - has been configured on the device. - sshkey: - description: - - Specifies the SSH public key to configure - for the given username. This argument accepts a valid SSH key value. - nopassword: - description: - - Defines the username without assigning - a password. This will allow the user to login to the system - without being authenticated by a password. - type: bool - purge: - description: - - Instructs the module to consider the - resource definition absolute. It will remove any previously - configured usernames on the device with the exception of the - `admin` user which cannot be deleted per EOS constraints. - type: bool - default: false - state: - description: - - Configures the state of the username definition - as it relates to the device operational configuration. When set - to I(present), the username(s) should be configured in the device active - configuration and when set to I(absent) the username(s) should not be - in the device active configuration - default: present - choices: ['present', 'absent'] -""" - -EXAMPLES = """ -- name: create a new user - eos_user: - name: ansible - sshkey: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" - state: present - -- name: remove all users except admin - eos_user: - purge: yes - -- name: set multiple users to privilege level 15 - eos_user: - aggregate: - - name: netop - - name: netend - privilege: 15 - state: present - -- name: Change Password for User netop - eos_user: - username: netop - configured_password: "{{ new_password }}" - update_password: always - state: present -""" - -RETURN = """ -commands: - description: The list of configuration mode commands to send to the device - returned: always - type: list - sample: - - name ansible secret password - - name admin secret admin -session_name: - description: The EOS config session name used to load the configuration - returned: when changed is True - type: str - sample: ansible_1479315771 -""" - -import re - -from copy import deepcopy -from functools import partial - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.common.utils import remove_default_spec -from ansible.module_utils.network.eos.eos import get_config, load_config -from ansible.module_utils.network.eos.eos import eos_argument_spec -from ansible.module_utils.six import iteritems - - -def validate_privilege(value, module): - if not 1 <= value <= 15: - module.fail_json(msg='privilege must be between 1 and 15, got %s' % value) - - -def map_obj_to_commands(updates, module): - commands = list() - update_password = module.params['update_password'] - - for update in updates: - want, have = update - - def needs_update(x): - return want.get(x) and (want.get(x) != have.get(x)) - - def add(x): - return commands.append('username %s %s' % (want['name'], x)) - - if want['state'] == 'absent': - commands.append('no username %s' % want['name']) - continue - - if needs_update('configured_password'): - if update_password == 'always' or not have: - add('secret %s' % want['configured_password']) - - if needs_update('role'): - add('role %s' % want['role']) - - if needs_update('privilege'): - add('privilege %s' % want['privilege']) - - if needs_update('sshkey'): - add('sshkey %s' % want['sshkey']) - - if needs_update('nopassword'): - if want['nopassword']: - add('nopassword') - else: - add('no username %s nopassword' % want['name']) - - if want.get('state') == 'present' and want.get('name'): - value = [want.get('configured_password'), want.get('nopassword'), want.get('sshkey')] - if all(v is None for v in value) is True: - module.fail_json(msg='configured_password, sshkey or nopassword should be provided') - - return commands - - -def parse_role(data): - match = re.search(r'role (\S+)', data, re.M) - if match: - return match.group(1) - - -def parse_sshkey(data): - match = re.search(r'sshkey (.+)$', data, re.M) - if match: - return match.group(1) - - -def parse_privilege(data): - match = re.search(r'privilege (\S+)', data, re.M) - if match: - return int(match.group(1)) - - -def map_config_to_obj(module): - data = get_config(module, flags=['section username']) - - match = re.findall(r'^username (\S+)', data, re.M) - if not match: - return list() - - instances = list() - - for user in set(match): - regex = r'username %s .+$' % user - cfg = re.findall(regex, data, re.M) - cfg = '\n'.join(cfg) - obj = { - 'name': user, - 'state': 'present', - 'nopassword': 'nopassword' in cfg, - 'configured_password': None, - 'sshkey': parse_sshkey(cfg), - 'privilege': parse_privilege(cfg), - 'role': parse_role(cfg) - } - instances.append(obj) - - return instances - - -def get_param_value(key, item, module): - # if key doesn't exist in the item, get it from module.params - if not item.get(key): - value = module.params[key] - - # if key does exist, do a type check on it to validate it - else: - value_type = module.argument_spec[key].get('type', 'str') - type_checker = module._CHECK_ARGUMENT_TYPES_DISPATCHER[value_type] - type_checker(item[key]) - value = item[key] - - # validate the param value (if validator func exists) - validator = globals().get('validate_%s' % key) - if all((value, validator)): - validator(value, module) - - return value - - -def map_params_to_obj(module): - aggregate = module.params['aggregate'] - if not aggregate: - if not module.params['name'] and module.params['purge']: - return list() - elif not module.params['name']: - module.fail_json(msg='name is required') - else: - collection = [{'name': module.params['name']}] - else: - collection = list() - for item in aggregate: - if not isinstance(item, dict): - collection.append({'name': item}) - elif 'name' not in item: - module.fail_json(msg='name is required') - else: - collection.append(item) - - objects = list() - - for item in collection: - get_value = partial(get_param_value, item=item, module=module) - item['configured_password'] = get_value('configured_password') - item['nopassword'] = get_value('nopassword') - item['privilege'] = get_value('privilege') - item['role'] = get_value('role') - item['sshkey'] = get_value('sshkey') - item['state'] = get_value('state') - objects.append(item) - - return objects - - -def update_objects(want, have): - updates = list() - for entry in want: - if 'name' in entry: - item = next((i for i in have if i['name'] == entry['name']), None) - if all((item is None, entry['state'] == 'present')): - updates.append((entry, {})) - elif item: - for key, value in iteritems(entry): - if value and value != item[key]: - updates.append((entry, item)) - return updates - - -def main(): - """ main entry point for module execution - """ - element_spec = dict( - name=dict(), - - configured_password=dict(no_log=True), - nopassword=dict(type='bool'), - update_password=dict(default='always', choices=['on_create', 'always']), - - privilege=dict(type='int'), - role=dict(), - - sshkey=dict(), - - state=dict(default='present', choices=['present', 'absent']) - ) - - aggregate_spec = deepcopy(element_spec) - - # remove default in aggregate spec, to handle common arguments - remove_default_spec(aggregate_spec) - - argument_spec = dict( - aggregate=dict(type='list', elements='dict', options=aggregate_spec, aliases=['collection', 'users']), - purge=dict(type='bool', default=False) - ) - - argument_spec.update(element_spec) - argument_spec.update(eos_argument_spec) - mutually_exclusive = [('name', 'aggregate')] - - module = AnsibleModule(argument_spec=argument_spec, - mutually_exclusive=mutually_exclusive, - supports_check_mode=True) - - warnings = list() - - result = {'changed': False} - if warnings: - result['warnings'] = warnings - - want = map_params_to_obj(module) - have = map_config_to_obj(module) - - commands = map_obj_to_commands(update_objects(want, have), module) - - if module.params['purge']: - want_users = [x['name'] for x in want] - have_users = [x['name'] for x in have] - for item in set(have_users).difference(want_users): - if item != 'admin': - commands.append('no username %s' % item) - - result['commands'] = commands - - # the eos cli prevents this by rule so capture it and display - # a nice failure message - if 'no username admin' in commands: - module.fail_json(msg='cannot delete the `admin` account') - - if commands: - commit = not module.check_mode - response = load_config(module, commands, commit=commit) - if response.get('diff') and module._diff: - result['diff'] = {'prepared': response.get('diff')} - result['session_name'] = response.get('session') - result['changed'] = True - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_vlans.py b/lib/ansible/modules/network/eos/eos_vlans.py deleted file mode 100644 index 2f0bdc72f3..0000000000 --- a/lib/ansible/modules/network/eos/eos_vlans.py +++ /dev/null @@ -1,240 +0,0 @@ -#!/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 eos_vlans -""" - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network' -} - -DOCUMENTATION = """ ---- -module: eos_vlans -version_added: 2.9 -short_description: Manage VLANs on Arista EOS devices. -description: This module provides declarative management of VLANs on Arista EOS network 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 VLANs options - type: list - elements: dict - suboptions: - name: - description: - - Name of the VLAN. - type: str - vlan_id: - description: - - ID of the VLAN. Range 1-4094 - type: int - required: true - state: - description: - - Operational state of the VLAN - type: str - choices: - - active - - suspend - state: - description: - - The state of the configuration after module completion - type: str - choices: - - merged - - replaced - - overridden - - deleted - default: merged -""" -EXAMPLES = """ -# Using deleted - -# Before state: -# ------------- -# -# veos(config-vlan-20)#show running-config | section vlan -# vlan 10 -# name ten -# ! -# vlan 20 -# name twenty - -- name: Delete attributes of the given VLANs. - eos_vlans: - config: - - vlan_id: 20 - state: deleted - -# After state: -# ------------ -# -# veos(config-vlan-20)#show running-config | section vlan -# vlan 10 -# name ten - - -# Using merged - -# Before state: -# ------------- -# -# veos(config-vlan-20)#show running-config | section vlan -# vlan 10 -# name ten -# ! -# vlan 20 -# name twenty - -- name: Merge given VLAN attributes with device configuration - eos_vlans: - config: - - vlan_id: 20 - state: suspend - state: merged - -# After state: -# ------------ -# -# veos(config-vlan-20)#show running-config | section vlan -# vlan 10 -# name ten -# ! -# vlan 20 -# name twenty -# state suspend - - -# Using overridden - -# Before state: -# ------------- -# -# veos(config-vlan-20)#show running-config | section vlan -# vlan 10 -# name ten -# ! -# vlan 20 -# name twenty - -- name: Override device configuration of all VLANs with provided configuration - eos_vlans: - config: - - vlan_id: 20 - state: suspend - state: overridden - -# After state: -# ------------ -# -# veos(config-vlan-20)#show running-config | section vlan -# vlan 20 -# state suspend - - -# Using replaced - -# Before state: -# ------------- -# -# veos(config-vlan-20)#show running-config | section vlan -# vlan 10 -# name ten -# ! -# vlan 20 -# name twenty - -- name: Replace all attributes of specified VLANs with provided configuration - eos_vlans: - config: - - vlan_id: 20 - state: suspend - state: replaced - -# After state: -# ------------ -# -# veos(config-vlan-20)#show running-config | section vlan -# vlan 10 -# name ten -# ! -# vlan 20 -# state suspend - - -""" -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: ['vlan 10', 'no name', 'vlan 11', 'name Eleven'] -""" - - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.eos.argspec.vlans.vlans import VlansArgs -from ansible.module_utils.network.eos.config.vlans.vlans import Vlans - - -def main(): - """ - Main entry point for module execution - - :returns: the result form module invocation - """ - module = AnsibleModule(argument_spec=VlansArgs.argument_spec, - supports_check_mode=True) - - result = Vlans(module).execute_module() - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/network/eos/eos_vrf.py b/lib/ansible/modules/network/eos/eos_vrf.py deleted file mode 100644 index 0684be033a..0000000000 --- a/lib/ansible/modules/network/eos/eos_vrf.py +++ /dev/null @@ -1,348 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# (c) 2017, Ansible by Red Hat, inc -# -# This file is part of Ansible by Red Hat -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'network'} - - -DOCUMENTATION = """ ---- -module: eos_vrf -version_added: "2.4" -author: "Ricardo Carrillo Cruz (@rcarrillocruz)" -short_description: Manage VRFs on Arista EOS network devices -description: - - This module provides declarative management of VRFs - on Arista EOS network devices. -notes: - - Tested against EOS 4.15 -options: - name: - description: - - Name of the VRF. - required: true - rd: - description: - - Route distinguisher of the VRF - interfaces: - description: - - Identifies the set of interfaces that - should be configured in the VRF. Interfaces must be routed - interfaces in order to be placed into a VRF. The name of interface - should be in expanded format and not abbreviated. - associated_interfaces: - description: - - This is a intent option and checks the operational state of the for given vrf C(name) - for associated interfaces. If the value in the C(associated_interfaces) does not match with - the operational state of vrf interfaces on device it will result in failure. - version_added: "2.5" - aggregate: - description: List of VRFs definitions - purge: - description: - - Purge VRFs not defined in the I(aggregate) parameter. - default: no - type: bool - delay: - description: - - Time in seconds to wait before checking for the operational state on remote - device. This wait is applicable for operational state arguments. - default: 10 - state: - description: - - State of the VRF configuration. - default: present - choices: ['present', 'absent'] -extends_documentation_fragment: eos -""" - -EXAMPLES = """ -- name: Create vrf - eos_vrf: - name: test - rd: 1:200 - interfaces: - - Ethernet2 - state: present - -- name: Delete VRFs - eos_vrf: - name: test - state: absent - -- name: Create aggregate of VRFs with purge - eos_vrf: - aggregate: - - { name: test4, rd: "1:204" } - - { name: test5, rd: "1:205" } - state: present - purge: yes - -- name: Delete aggregate of VRFs - eos_vrf: - aggregate: - - name: test2 - - name: test3 - - name: test4 - - name: test5 - state: absent -""" - -RETURN = """ -commands: - description: The list of configuration mode commands to send to the device - returned: always - type: list - sample: - - vrf definition test - - rd 1:100 - - interface Ethernet1 - - vrf forwarding test -""" -import re -import time - -from copy import deepcopy - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.network.common.utils import remove_default_spec -from ansible.module_utils.network.eos.eos import load_config, run_commands -from ansible.module_utils.network.eos.eos import eos_argument_spec - - -def search_obj_in_list(name, lst): - for o in lst: - if o['name'] == name: - return o - - -def map_obj_to_commands(updates, module): - commands = list() - want, have = updates - state = module.params['state'] - purge = module.params['purge'] - - for w in want: - name = w['name'] - rd = w['rd'] - - obj_in_have = search_obj_in_list(name, have) - - if state == 'absent': - if obj_in_have: - commands.append('no vrf definition %s' % name) - elif state == 'present': - if not obj_in_have: - commands.append('vrf definition %s' % name) - - if rd is not None: - commands.append('rd %s' % rd) - - if w['interfaces']: - for i in w['interfaces']: - commands.append('interface %s' % i) - commands.append('vrf forwarding %s' % w['name']) - else: - if w['rd'] is not None and w['rd'] != obj_in_have['rd']: - commands.append('vrf definition %s' % w['name']) - commands.append('rd %s' % w['rd']) - - if w['interfaces']: - if not obj_in_have['interfaces']: - for i in w['interfaces']: - commands.append('interface %s' % i) - commands.append('vrf forwarding %s' % w['name']) - elif set(w['interfaces']) != obj_in_have['interfaces']: - missing_interfaces = list(set(w['interfaces']) - set(obj_in_have['interfaces'])) - - for i in missing_interfaces: - commands.append('interface %s' % i) - commands.append('vrf forwarding %s' % w['name']) - - if purge: - for h in have: - obj_in_want = search_obj_in_list(h['name'], want) - if not obj_in_want: - commands.append('no vrf definition %s' % h['name']) - - return commands - - -def map_config_to_obj(module): - objs = [] - output = run_commands(module, {'command': 'show vrf', 'output': 'text'}) - - lines = output[0].strip().splitlines()[3:] - - out_len = len(lines) - index = 0 - while out_len > index: - line = lines[index] - if not line: - continue - - splitted_line = re.split(r'\s{2,}', line.strip()) - - if len(splitted_line) == 1: - index += 1 - continue - else: - obj = dict() - obj['name'] = splitted_line[0] - obj['rd'] = splitted_line[1] - obj['interfaces'] = [] - - if len(splitted_line) > 4: - obj['interfaces'] = [] - interfaces = splitted_line[4] - if interfaces.endswith(','): - while interfaces.endswith(','): - # gather all comma separated interfaces - if out_len <= index: - break - index += 1 - line = lines[index] - vrf_line = re.split(r'\s{2,}', line.strip()) - interfaces += vrf_line[-1] - - for i in interfaces.split(','): - obj['interfaces'].append(i.strip().lower()) - index += 1 - objs.append(obj) - - return objs - - -def map_params_to_obj(module): - obj = [] - aggregate = module.params.get('aggregate') - if aggregate: - for item in aggregate: - for key in item: - if item.get(key) is None: - item[key] = module.params[key] - - if item.get('interfaces'): - item['interfaces'] = [intf.replace(" ", "").lower() for intf in item.get('interfaces') if intf] - - if item.get('associated_interfaces'): - item['associated_interfaces'] = [intf.replace(" ", "").lower() for intf in item.get('associated_interfaces') if intf] - - obj.append(item.copy()) - else: - obj.append({ - 'name': module.params['name'], - 'state': module.params['state'], - 'rd': module.params['rd'], - 'interfaces': [intf.replace(" ", "").lower() for intf in module.params['interfaces']] if module.params['interfaces'] else [], - 'associated_interfaces': [intf.replace(" ", "").lower() for intf in - module.params['associated_interfaces']] if module.params['associated_interfaces'] else [] - - }) - - return obj - - -def check_declarative_intent_params(want, module, result): - have = None - is_delay = False - - for w in want: - if w.get('associated_interfaces') is None: - continue - - if result['changed'] and not is_delay: - time.sleep(module.params['delay']) - is_delay = True - - if have is None: - have = map_config_to_obj(module) - - for i in w['associated_interfaces']: - obj_in_have = search_obj_in_list(w['name'], have) - - if obj_in_have: - interfaces = obj_in_have.get('interfaces') - if interfaces is not None and i not in interfaces: - module.fail_json(msg="Interface %s not configured on vrf %s" % (i, w['name'])) - - -def main(): - """ main entry point for module execution - """ - element_spec = dict( - name=dict(), - interfaces=dict(type='list'), - associated_interfaces=dict(type='list'), - delay=dict(default=10, type='int'), - rd=dict(), - state=dict(default='present', choices=['present', 'absent']) - ) - - aggregate_spec = deepcopy(element_spec) - - # remove default in aggregate spec, to handle common arguments - remove_default_spec(aggregate_spec) - - argument_spec = dict( - aggregate=dict(type='list', elements='dict', options=aggregate_spec), - purge=dict(default=False, type='bool') - ) - - argument_spec.update(element_spec) - argument_spec.update(eos_argument_spec) - - required_one_of = [['name', 'aggregate']] - mutually_exclusive = [['name', 'aggregate']] - module = AnsibleModule(argument_spec=argument_spec, - required_one_of=required_one_of, - mutually_exclusive=mutually_exclusive, - supports_check_mode=True) - - warnings = list() - - result = {'changed': False} - - if warnings: - result['warnings'] = warnings - - want = map_params_to_obj(module) - have = map_config_to_obj(module) - - commands = map_obj_to_commands((want, have), module) - result['commands'] = commands - - if commands: - commit = not module.check_mode - response = load_config(module, commands, commit=commit) - if response.get('diff') and module._diff: - result['diff'] = {'prepared': response.get('diff')} - result['session_name'] = response.get('session') - result['changed'] = True - - check_declarative_intent_params(want, module, result) - - module.exit_json(**result) - - -if __name__ == '__main__': - main() |