Handle common argument in aggregate parameter for vyos module (#28182)

* Handle common agrument in aggregate parameter for vyos module

*  Add supoort to set parameter in aggregate to it's respctive
   top level argument if value not provided in aggregate.
*  Aggregate argument spec validation
*  Documentation for aggregate

* Fix unit test failure
This commit is contained in:
Ganesh Nalawade 2017-08-15 19:09:44 +05:30 committed by GitHub
parent 3f9d6aa0f1
commit 38c0b581c3
18 changed files with 353 additions and 165 deletions

View file

@ -87,6 +87,24 @@ EXAMPLES = """
name: ge-0/0/1 name: ge-0/0/1
description: test-interface description: test-interface
enabled: False enabled: False
- name: Create interface using aggregate
net_interface:
aggregate:
- name: ge-0/0/1
description: test-interface-1
- name: ge-0/0/2
description: test-interface-2
speed: 1g
duplex: full
mtu: 512
- name: Delete interface using aggregate
junos_interface:
aggregate:
- name: ge-0/0/1
- name: ge-0/0/2
state: absent
""" """
RETURN = """ RETURN = """

View file

@ -70,6 +70,18 @@ EXAMPLES = """
name: bond0 name: bond0
state: absent state: absent
- name: Create aggregate of linkagg definitions
net_linkagg:
aggregate:
- { name: bond0, members: [eth1] }
- { name: bond1, members: [eth2] }
- name: Remove aggregate of linkagg definitions
net_linkagg:
aggregate:
- name: bond0
- name: bond1
state: absent
""" """
RETURN = """ RETURN = """

View file

@ -58,6 +58,20 @@ EXAMPLES = """
net_lldp_interface: net_lldp_interface:
name: eth1 name: eth1
state: absent state: absent
- name: Create aggregate of LLDP interface configurations
net_lldp_interface:
aggregate:
- name: eth1
- name: eth2
state: present
- name: Delete aggregate of LLDP interface configurations
net_lldp_interface:
aggregate:
- name: eth1
- name: eth2
state: absent
""" """
RETURN = """ RETURN = """

View file

@ -55,6 +55,19 @@ EXAMPLES = """
net_l3_interface: net_l3_interface:
name: eth0 name: eth0
state: absent state: absent
- name: Set IP addresses on aggregate
net_l3_interface:
aggregate:
- { name: eth1, ipv4: 192.168.2.10/24 }
- { name: eth2, ipv4: 192.168.3.10/24, ipv6: "fd5d:12c9:2201:1::1/64" }
- name: Remove IP addresses on aggregate
net_l3_interface:
aggregate:
- { name: eth1, ipv4: 192.168.2.10/24 }
- { name: eth2, ipv4: 192.168.3.10/24, ipv6: "fd5d:12c9:2201:1::1/64" }
state: absent
""" """
RETURN = """ RETURN = """

View file

@ -70,6 +70,13 @@ EXAMPLES = """
aggregate: aggregate:
- { prefix: 192.168.2.0, mask 255.255.255.0, next_hop: 10.0.0.1 } - { prefix: 192.168.2.0, mask 255.255.255.0, next_hop: 10.0.0.1 }
- { prefix: 192.168.3.0, mask 255.255.255.0, next_hop: 10.0.2.1 } - { prefix: 192.168.3.0, mask 255.255.255.0, next_hop: 10.0.2.1 }
- name: Remove static route collections
net_static_route:
aggregate:
- { prefix: 172.24.1.0/24, next_hop: 192.168.42.64 }
- { prefix: 172.24.3.0/24, next_hop: 192.168.42.64 }
state: absent
""" """
RETURN = """ RETURN = """

View file

@ -98,9 +98,11 @@ EXAMPLES = """
name: ansible name: ansible
sshkey: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" sshkey: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
state: present state: present
- name: remove all users except admin - name: remove all users except admin
net_user: net_user:
purge: yes purge: yes
- name: set multiple users to privilege level 15 - name: set multiple users to privilege level 15
net_user: net_user:
aggregate: aggregate:
@ -108,6 +110,7 @@ EXAMPLES = """
- name: netend - name: netend
privilege: 15 privilege: 15
state: present state: present
- name: Change Password for User netop - name: Change Password for User netop
net_user: net_user:
name: netop name: netop

View file

@ -93,6 +93,26 @@ EXAMPLES = """
speed: 100 speed: 100
mtu: 256 mtu: 256
duplex: full duplex: full
- name: Set interface using aggregate
vyos_interface:
aggregate:
- { name: eth1, description: test-interface-1, speed: 100, duplex: half, mtu: 512}
- { name: eth2, description: test-interface-2, speed: 1000, duplex: full, mtu: 256}
- name: Disable interface on aggregate
net_interface:
aggregate:
- name: eth1
- name: eth2
enabled: False
- name: Delete interface using aggregate
net_interface:
aggregate:
- name: eth1
- name: eth2
state: absent
""" """
RETURN = """ RETURN = """
@ -108,12 +128,13 @@ commands:
""" """
import re import re
from copy import deepcopy
from time import sleep from time import sleep
from ansible.module_utils._text import to_text from ansible.module_utils._text import to_text
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import exec_command from ansible.module_utils.connection import exec_command
from ansible.module_utils.network_common import conditional from ansible.module_utils.network_common import conditional, remove_default_spec
from ansible.module_utils.vyos import load_config, get_config from ansible.module_utils.vyos import load_config, get_config
from ansible.module_utils.vyos import vyos_argument_spec, check_args from ansible.module_utils.vyos import vyos_argument_spec, check_args
@ -213,40 +234,19 @@ def map_config_to_obj(module):
def map_params_to_obj(module): def map_params_to_obj(module):
obj = [] obj = []
params = ['speed', 'description', 'duplex', 'mtu']
aggregate = module.params.get('aggregate') aggregate = module.params.get('aggregate')
if aggregate: if aggregate:
for c in aggregate: for item in aggregate:
d = c.copy() for key in item:
if 'name' not in d: if item.get(key) is None:
module.fail_json(msg="missing required arguments: %s" % 'name') item[key] = module.params[key]
for item in params:
if item not in d:
d[item] = None
if d.get('description') is None:
d['description'] = DEFAULT_DESCRIPTION
if not d.get('state'):
d['state'] = module.params['state']
if d.get('enabled') is None:
d['enabled'] = module.params['enabled']
d = item.copy()
if d['enabled']: if d['enabled']:
d['disable'] = False d['disable'] = False
else: else:
d['disable'] = True d['disable'] = True
if d.get('delay') is None:
d['delay'] = module.params['delay']
if d.get('speed'):
d['speed'] = str(d['speed'])
obj.append(d) obj.append(d)
else: else:
params = { params = {
@ -300,7 +300,7 @@ def check_declarative_intent_params(module, want, result):
def main(): def main():
""" main entry point for module execution """ main entry point for module execution
""" """
argument_spec = dict( element_spec = dict(
name=dict(), name=dict(),
description=dict(default=DEFAULT_DESCRIPTION), description=dict(default=DEFAULT_DESCRIPTION),
speed=dict(), speed=dict(),
@ -308,11 +308,21 @@ def main():
duplex=dict(choices=['full', 'half', 'auto']), duplex=dict(choices=['full', 'half', 'auto']),
enabled=dict(default=True, type='bool'), enabled=dict(default=True, type='bool'),
delay=dict(default=10, type='int'), delay=dict(default=10, type='int'),
aggregate=dict(type='list'),
state=dict(default='present', state=dict(default='present',
choices=['present', 'absent', 'up', 'down']) 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(vyos_argument_spec) argument_spec.update(vyos_argument_spec)
required_one_of = [['name', 'aggregate']] required_one_of = [['name', 'aggregate']]

View file

@ -45,10 +45,6 @@ options:
- IPv6 of the L3 interface. - IPv6 of the L3 interface.
aggregate: aggregate:
description: List of L3 interfaces definitions description: List of L3 interfaces definitions
purge:
description:
- Purge L3 interfaces not defined in the aggregate parameter.
default: no
state: state:
description: description:
- State of the L3 interface configuration. - State of the L3 interface configuration.
@ -66,6 +62,19 @@ EXAMPLES = """
vyos_l3_interface: vyos_l3_interface:
name: eth0 name: eth0
state: absent state: absent
- name: Set IP addresses on aggregate
vyos_l3_interface:
aggregate:
- { name: eth1, ipv4: 192.168.2.10/24 }
- { name: eth2, ipv4: 192.168.3.10/24, ipv6: "fd5d:12c9:2201:1::1/64" }
- name: Remove IP addresses on aggregate
vyos_l3_interface:
aggregate:
- { name: eth1, ipv4: 192.168.2.10/24 }
- { name: eth2, ipv4: 192.168.3.10/24, ipv6: "fd5d:12c9:2201:1::1/64" }
state: absent
""" """
RETURN = """ RETURN = """
@ -76,7 +85,10 @@ commands:
sample: sample:
- set interfaces ethernet eth0 address '192.168.0.1/24' - set interfaces ethernet eth0 address '192.168.0.1/24'
""" """
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network_common import remove_default_spec
from ansible.module_utils.vyos import load_config, run_commands from ansible.module_utils.vyos import load_config, run_commands
from ansible.module_utils.vyos import vyos_argument_spec, check_args from ansible.module_utils.vyos import vyos_argument_spec, check_args
@ -153,18 +165,14 @@ def map_config_to_obj(module):
def map_params_to_obj(module): def map_params_to_obj(module):
obj = [] obj = []
if 'aggregate' in module.params and module.params['aggregate']: aggregate = module.params.get('aggregate')
for c in module.params['aggregate']: if aggregate:
d = c.copy() for item in aggregate:
for key in item:
if item.get(key) is None:
item[key] = module.params[key]
if 'ipv4' not in d: obj.append(item.copy())
d['ipv4'] = None
if 'ipv6' not in d:
d['ipv6'] = None
if 'state' not in d:
d['state'] = module.params['state']
obj.append(d)
else: else:
obj.append({ obj.append({
'name': module.params['name'], 'name': module.params['name'],
@ -179,16 +187,25 @@ def map_params_to_obj(module):
def main(): def main():
""" main entry point for module execution """ main entry point for module execution
""" """
argument_spec = dict( element_spec = dict(
name=dict(), name=dict(),
ipv4=dict(), ipv4=dict(),
ipv6=dict(), ipv6=dict(),
aggregate=dict(type='list'),
purge=dict(default=False, type='bool'),
state=dict(default='present', state=dict(default='present',
choices=['present', 'absent']) 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(vyos_argument_spec) argument_spec.update(vyos_argument_spec)
required_one_of = [['name', 'aggregate']] required_one_of = [['name', 'aggregate']]

View file

@ -49,10 +49,6 @@ options:
- List of members of the link aggregation group. - List of members of the link aggregation group.
aggregate: aggregate:
description: List of link aggregation definitions. description: List of link aggregation definitions.
purge:
description:
- Purge link aggregation groups not defined in the aggregates parameter.
default: no
state: state:
description: description:
- State of the link aggregation group. - State of the link aggregation group.
@ -73,6 +69,18 @@ EXAMPLES = """
name: bond0 name: bond0
state: absent state: absent
- name: Create aggregate of linkagg definitions
vyos_linkagg:
aggregate:
- { name: bond0, members: [eth1] }
- { name: bond1, members: [eth2] }
- name: Remove aggregate of linkagg definitions
vyos_linkagg:
aggregate:
- name: bond0
- name: bond1
state: absent
""" """
RETURN = """ RETURN = """
@ -85,7 +93,10 @@ commands:
- set interfaces ethernet eth0 bond-group 'bond0' - set interfaces ethernet eth0 bond-group 'bond0'
- set interfaces ethernet eth1 bond-group 'bond0' - set interfaces ethernet eth1 bond-group 'bond0'
""" """
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network_common import remove_default_spec
from ansible.module_utils.vyos import load_config, run_commands from ansible.module_utils.vyos import load_config, run_commands
from ansible.module_utils.vyos import vyos_argument_spec, check_args from ansible.module_utils.vyos import vyos_argument_spec, check_args
@ -173,17 +184,14 @@ def map_config_to_obj(module):
def map_params_to_obj(module): def map_params_to_obj(module):
obj = [] 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 'aggregate' in module.params and module.params['aggregate']: obj.append(item.copy())
for c in module.params['aggregate']:
d = c.copy()
if 'state' not in d:
d['state'] = module.params['state']
if 'mode' not in d:
d['mode'] = module.params['mode']
obj.append(d)
else: else:
obj.append({ obj.append({
'name': module.params['name'], 'name': module.params['name'],
@ -198,25 +206,35 @@ def map_params_to_obj(module):
def main(): def main():
""" main entry point for module execution """ main entry point for module execution
""" """
argument_spec = dict( element_spec = dict(
name=dict(), name=dict(),
mode=dict(choices=['802.3ad', 'active-backup', 'broadcast', mode=dict(choices=['802.3ad', 'active-backup', 'broadcast',
'round-robin', 'transmit-load-balance', 'round-robin', 'transmit-load-balance',
'adaptive-load-balance', 'xor-hash', 'on'], 'adaptive-load-balance', 'xor-hash', 'on'],
default='802.3ad'), default='802.3ad'),
members=dict(type='list'), members=dict(type='list'),
aggregate=dict(type='list'),
purge=dict(default=False, type='bool'),
state=dict(default='present', state=dict(default='present',
choices=['present', 'absent', 'up', 'down']) 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(vyos_argument_spec) argument_spec.update(vyos_argument_spec)
required_one_of = [['name', 'aggregate']] required_one_of = [['name', 'aggregate']]
mutually_exclusive = [['name', 'aggregate']] mutually_exclusive = [['name', 'aggregate']]
module = AnsibleModule(argument_spec=argument_spec, module = AnsibleModule(argument_spec=argument_spec,
required_one_of=required_one_of, required_one_of=required_one_of,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True) supports_check_mode=True)
warnings = list() warnings = list()

View file

@ -78,7 +78,6 @@ def main():
""" """
argument_spec = dict( argument_spec = dict(
interfaces=dict(type='list'), interfaces=dict(type='list'),
purge=dict(default=False, type='bool'),
state=dict(default='present', state=dict(default='present',
choices=['present', 'absent', choices=['present', 'absent',
'enabled', 'disabled']) 'enabled', 'disabled'])

View file

@ -39,10 +39,6 @@ options:
- Name of the interface LLDP should be configured on. - Name of the interface LLDP should be configured on.
aggregate: aggregate:
description: List of interfaces LLDP should be configured on. description: List of interfaces LLDP should be configured on.
purge:
description:
- Purge interfaces not defined in the aggregate parameter.
default: no
state: state:
description: description:
- State of the LLDP configuration. - State of the LLDP configuration.
@ -64,7 +60,21 @@ EXAMPLES = """
- name: Disable LLDP globally - name: Disable LLDP globally
net_lldp_interface: net_lldp_interface:
state: lldp state: disabled
- name: Create aggregate of LLDP interface configurations
vyos_lldp_interface:
aggregate:
- name: eth1
- name: eth2
state: present
- name: Delete aggregate of LLDP interface configurations
vyos_lldp_interface:
aggregate:
- name: eth1
- name: eth2
state: absent
""" """
RETURN = """ RETURN = """
@ -76,7 +86,10 @@ commands:
- set service lldp eth1 - set service lldp eth1
- set service lldp eth2 disable - set service lldp eth2 disable
""" """
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network_common import remove_default_spec
from ansible.module_utils.vyos import get_config, load_config from ansible.module_utils.vyos import get_config, load_config
from ansible.module_utils.vyos import vyos_argument_spec, check_args from ansible.module_utils.vyos import vyos_argument_spec, check_args
@ -142,14 +155,14 @@ def map_config_to_obj(module):
def map_params_to_obj(module): def map_params_to_obj(module):
obj = [] obj = []
if module.params['aggregate']: aggregate = module.params.get('aggregate')
for i in module.params['aggregate']: if aggregate:
d = i.copy() for item in aggregate:
for key in item:
if item.get(key) is None:
item[key] = module.params[key]
if 'state' not in d: obj.append(item.copy())
d['state'] = module.params['state']
obj.append(d)
else: else:
obj.append({'name': module.params['name'], 'state': module.params['state']}) obj.append({'name': module.params['name'], 'state': module.params['state']})
@ -159,16 +172,26 @@ def map_params_to_obj(module):
def main(): def main():
""" main entry point for module execution """ main entry point for module execution
""" """
argument_spec = dict( element_spec = dict(
name=dict(), name=dict(),
aggregate=dict(type='list'),
purge=dict(default=False, type='bool'),
state=dict(default='present', state=dict(default='present',
choices=['present', 'absent', choices=['present', 'absent',
'enabled', 'disabled']) 'enabled', 'disabled'])
) )
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(vyos_argument_spec) argument_spec.update(vyos_argument_spec)
required_one_of = [['name', 'aggregate']] required_one_of = [['name', 'aggregate']]
mutually_exclusive = [['name', 'aggregate']] mutually_exclusive = [['name', 'aggregate']]

View file

@ -50,10 +50,6 @@ options:
- Set logging severity levels. - Set logging severity levels.
aggregate: aggregate:
description: List of logging definitions. description: List of logging definitions.
purge:
description:
- Purge logging not defined in the aggregate parameter.
default: no
state: state:
description: description:
- State of the logging configuration. - State of the logging configuration.
@ -67,16 +63,33 @@ EXAMPLES = """
dest: console dest: console
facility: all facility: all
level: crit level: crit
- name: remove console logging configuration - name: remove console logging configuration
vyos_logging: vyos_logging:
dest: console dest: console
state: absent state: absent
- name: configure file logging - name: configure file logging
vyos_logging: vyos_logging:
dest: file dest: file
name: test name: test
facility: local3 facility: local3
level: err level: err
- name: Add logging aggregate
vyos_logging:
aggregate:
- { dest: file, name: test1, facility: all, level: info }
- { dest: file, name: test2, facility: news, level: debug }
state: present
- name: Remove logging aggregate
vyos_logging:
aggregate:
- { dest: console, facility: all, level: info }
- { dest: console, facility: daemon, level: warning }
- { dest: file, name: test2, facility: news, level: debug }
state: absent
""" """
RETURN = """ RETURN = """
@ -90,7 +103,10 @@ commands:
import re import re
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network_common import remove_default_spec
from ansible.module_utils.vyos import get_config, load_config from ansible.module_utils.vyos import get_config, load_config
from ansible.module_utils.vyos import vyos_argument_spec, check_args from ansible.module_utils.vyos import vyos_argument_spec, check_args
@ -160,21 +176,18 @@ def config_to_dict(module):
return obj return obj
def map_params_to_obj(module): def map_params_to_obj(module, required_if=None):
obj = [] obj = []
if 'aggregate' in module.params and module.params['aggregate']: aggregate = module.params.get('aggregate')
for c in module.params['aggregate']: if aggregate:
d = c.copy() for item in aggregate:
if d['dest'] not in ('host', 'file', 'user'): for key in item:
d['name'] = None if item.get(key) is None:
else: item[key] = module.params[key]
pass
if 'state' not in d: module._check_required_if(required_if, item)
d['state'] = module.params['state'] obj.append(item.copy())
obj.append(d)
else: else:
if module.params['dest'] not in ('host', 'file', 'user'): if module.params['dest'] not in ('host', 'file', 'user'):
@ -194,16 +207,25 @@ def map_params_to_obj(module):
def main(): def main():
""" main entry point for module execution """ main entry point for module execution
""" """
argument_spec = dict( element_spec = dict(
dest=dict(type='str', choices=['console', 'file', 'global', 'host', 'user']), dest=dict(type='str', choices=['console', 'file', 'global', 'host', 'user']),
name=dict(type='str'), name=dict(type='str'),
facility=dict(type='str'), facility=dict(type='str'),
level=dict(type='str'), level=dict(type='str'),
state=dict(default='present', choices=['present', 'absent']), state=dict(default='present', choices=['present', 'absent']),
aggregate=dict(type='list'),
purge=dict(default=False, type='bool')
) )
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(vyos_argument_spec) argument_spec.update(vyos_argument_spec)
required_if = [('dest', 'host', ['name', 'facility', 'level']), required_if = [('dest', 'host', ['name', 'facility', 'level']),
('dest', 'file', ['name', 'facility', 'level']), ('dest', 'file', ['name', 'facility', 'level']),
@ -221,7 +243,7 @@ def main():
result = {'changed': False} result = {'changed': False}
if warnings: if warnings:
result['warnings'] = warnings result['warnings'] = warnings
want = map_params_to_obj(module) want = map_params_to_obj(module, required_if=required_if)
have = config_to_dict(module) have = config_to_dict(module)
commands = spec_to_commands((want, have), module) commands = spec_to_commands((want, have), module)

View file

@ -50,10 +50,6 @@ options:
- Admin distance of the static route. - Admin distance of the static route.
aggregate: aggregate:
description: List of static route definitions description: List of static route definitions
purge:
description:
- Purge static routes not defined in the aggregates parameter.
default: no
state: state:
description: description:
- State of the static route configuration. - State of the static route configuration.
@ -67,22 +63,32 @@ EXAMPLES = """
prefix: 192.168.2.0 prefix: 192.168.2.0
mask: 24 mask: 24
next_hop: 10.0.0.1 next_hop: 10.0.0.1
- name: configure static route prefix/mask - name: configure static route prefix/mask
vyos_static_route: vyos_static_route:
prefix: 192.168.2.0/16 prefix: 192.168.2.0/16
next_hop: 10.0.0.1 next_hop: 10.0.0.1
- name: remove configuration - name: remove configuration
vyos_static_route: vyos_static_route:
prefix: 192.168.2.0 prefix: 192.168.2.0
mask: 16 mask: 16
next_hop: 10.0.0.1 next_hop: 10.0.0.1
state: absent state: absent
- name: configure aggregates of static routes - name: configure aggregates of static routes
vyos_static_route: vyos_static_route:
aggregate: aggregate:
- { prefix: 192.168.2.0, mask: 24, next_hop: 10.0.0.1 } - { prefix: 192.168.2.0, mask: 24, next_hop: 10.0.0.1 }
- { prefix: 192.168.3.0, mask: 16, next_hop: 10.0.2.1 } - { prefix: 192.168.3.0, mask: 16, next_hop: 10.0.2.1 }
- { prefix: 192.168.3.0/16, next_hop: 10.0.2.1 } - { prefix: 192.168.3.0/16, next_hop: 10.0.2.1 }
- name: Remove static route collections
vyos_static_route:
aggregate:
- { prefix: 172.24.1.0/24, next_hop: 192.168.42.64 }
- { prefix: 172.24.3.0/24, next_hop: 192.168.42.64 }
state: absent
""" """
RETURN = """ RETURN = """
@ -93,10 +99,12 @@ commands:
sample: sample:
- set protocols static route 192.168.2.0/16 next-hop 10.0.0.1 - set protocols static route 192.168.2.0/16 next-hop 10.0.0.1
""" """
import re import re
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network_common import remove_default_spec
from ansible.module_utils.vyos import get_config, load_config from ansible.module_utils.vyos import get_config, load_config
from ansible.module_utils.vyos import vyos_argument_spec, check_args from ansible.module_utils.vyos import vyos_argument_spec, check_args
@ -156,20 +164,23 @@ def config_to_dict(module):
return obj return obj
def map_params_to_obj(module): def map_params_to_obj(module, required_together=None):
obj = [] 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 'aggregate' in module.params and module.params['aggregate']: module._check_required_together(required_together, item)
for c in module.params['aggregate']: d = item.copy()
d = c.copy()
if '/' in d['prefix']: if '/' in d['prefix']:
d['mask'] = d['prefix'].split('/')[1] d['mask'] = d['prefix'].split('/')[1]
d['prefix'] = d['prefix'].split('/')[0] d['prefix'] = d['prefix'].split('/')[0]
if 'state' not in d: if 'admin_distance' in d:
d['state'] = module.params['state'] d['admin_distance'] = str(d['admin_distance'])
if 'admin_distance' not in d:
d['admin_distance'] = str(module.params['admin_distance'])
obj.append(d) obj.append(d)
else: else:
@ -197,16 +208,27 @@ def map_params_to_obj(module):
def main(): def main():
""" main entry point for module execution """ main entry point for module execution
""" """
argument_spec = dict( element_spec = dict(
prefix=dict(type='str'), prefix=dict(type='str'),
mask=dict(type='str'), mask=dict(type='str'),
next_hop=dict(type='str'), next_hop=dict(type='str'),
admin_distance=dict(type='int'), admin_distance=dict(type='int'),
aggregate=dict(type='list'),
purge=dict(type='bool'),
state=dict(default='present', choices=['present', 'absent']) state=dict(default='present', choices=['present', 'absent'])
) )
aggregate_spec = deepcopy(element_spec)
aggregate_spec['prefix'] = 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(vyos_argument_spec)
argument_spec.update(vyos_argument_spec) argument_spec.update(vyos_argument_spec)
required_one_of = [['aggregate', 'prefix']] required_one_of = [['aggregate', 'prefix']]
required_together = [['prefix', 'next_hop']] required_together = [['prefix', 'next_hop']]
@ -215,6 +237,7 @@ def main():
module = AnsibleModule(argument_spec=argument_spec, module = AnsibleModule(argument_spec=argument_spec,
required_one_of=required_one_of, required_one_of=required_one_of,
required_together=required_together, required_together=required_together,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True) supports_check_mode=True)
warnings = list() warnings = list()
@ -223,7 +246,7 @@ def main():
result = {'changed': False} result = {'changed': False}
if warnings: if warnings:
result['warnings'] = warnings result['warnings'] = warnings
want = map_params_to_obj(module) want = map_params_to_obj(module, required_together=required_together)
have = config_to_dict(module) have = config_to_dict(module)
commands = spec_to_commands((want, have), module) commands = spec_to_commands((want, have), module)

View file

@ -127,9 +127,11 @@ commands:
import re import re
from copy import deepcopy
from functools import partial from functools import partial
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network_common import remove_default_spec
from ansible.module_utils.vyos import get_config, load_config from ansible.module_utils.vyos import get_config, load_config
from ansible.module_utils.six import iteritems from ansible.module_utils.six import iteritems
from ansible.module_utils.vyos import vyos_argument_spec, check_args from ansible.module_utils.vyos import vyos_argument_spec, check_args
@ -215,13 +217,6 @@ def get_param_value(key, item, module):
if not item.get(key): if not item.get(key):
value = module.params[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) # validate the param value (if validator func exists)
validator = globals().get('validate_%s' % key) validator = globals().get('validate_%s' % key)
if all((value, validator)): if all((value, validator)):
@ -231,21 +226,17 @@ def get_param_value(key, item, module):
def map_params_to_obj(module): def map_params_to_obj(module):
users = module.params['users'] aggregate = module.params['aggregate']
if not users: if not aggregate:
if not module.params['name'] and module.params['purge']: if not module.params['name'] and module.params['purge']:
return list() return list()
elif not module.params['name']:
module.fail_json(msg='username is required')
else: else:
aggregate = [{'name': module.params['name']}] aggregate = [{'name': module.params['name']}]
else: else:
aggregate = list() aggregate = list()
for item in users: for item in aggregate:
if not isinstance(item, dict): if not isinstance(item, dict):
aggregate.append({'name': item}) aggregate.append({'name': item})
elif 'name' not in item:
module.fail_json(msg='name is required')
else: else:
aggregate.append(item) aggregate.append(item)
@ -278,8 +269,7 @@ def update_objects(want, have):
def main(): def main():
""" main entry point for module execution """ main entry point for module execution
""" """
argument_spec = dict( element_spec = dict(
users=dict(type='list', aliases=['aggregate']),
name=dict(), name=dict(),
full_name=dict(), full_name=dict(),
@ -292,9 +282,20 @@ def main():
state=dict(default='present', choices=['present', 'absent']) state=dict(default='present', choices=['present', 'absent'])
) )
argument_spec.update(vyos_argument_spec) aggregate_spec = deepcopy(element_spec)
mutually_exclusive = [('name', 'users')] 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, aliases=['users']),
)
argument_spec.update(element_spec)
argument_spec.update(vyos_argument_spec)
mutually_exclusive = [('name', 'aggregate')]
module = AnsibleModule(argument_spec=argument_spec, module = AnsibleModule(argument_spec=argument_spec,
mutually_exclusive=mutually_exclusive, mutually_exclusive=mutually_exclusive,
supports_check_mode=True) supports_check_mode=True)

View file

@ -138,8 +138,9 @@
- name: Disable interface on aggregate - name: Disable interface on aggregate
net_interface: net_interface:
aggregate: aggregate:
- { name: eth1, description: test-interface-1, speed: 100, duplex: half, mtu: 512, enabled: False} - name: eth1
- { name: eth2, description: test-interface-2, speed: 1000, duplex: full, mtu: 256, enabled: False} - name: eth2
enabled: False
register: result register: result
- assert: - assert:
@ -151,8 +152,9 @@
- name: Enable interface on aggregate - name: Enable interface on aggregate
net_interface: net_interface:
aggregate: aggregate:
- { name: eth1, description: test-interface-1, speed: 100, duplex: half, mtu: 512, enabled: True} - name: eth1
- { name: eth2, description: test-interface-2, speed: 1000, duplex: full, mtu: 256, enabled: True} - name: eth2
enabled: True
register: result register: result
- assert: - assert:
@ -164,8 +166,9 @@
- name: Delete interface aggregate - name: Delete interface aggregate
net_interface: net_interface:
aggregate: aggregate:
- { name: eth1, state: absent} - name: eth1
- { name: eth2, state: absent} - name: eth2
state: absent
register: result register: result
- assert: - assert:
@ -177,8 +180,9 @@
- name: Delete interface aggregate (idempotent) - name: Delete interface aggregate (idempotent)
net_interface: net_interface:
aggregate: aggregate:
- { name: eth1, state: absent} - name: eth1
- { name: eth2, state: absent} - name: eth2
state: absent
register: result register: result
- assert: - assert:

View file

@ -167,8 +167,9 @@
- name: Disable interface on aggregate - name: Disable interface on aggregate
vyos_interface: vyos_interface:
aggregate: aggregate:
- { name: eth1, description: test-interface-1, enabled: False} - name: eth1
- { name: eth2, description: test-interface-2, enabled: False} - name: eth2
enabled: False
register: result register: result
- assert: - assert:
@ -180,8 +181,9 @@
- name: Enable interface on aggregate - name: Enable interface on aggregate
vyos_interface: vyos_interface:
aggregate: aggregate:
- { name: eth1, description: test-interface-1, enabled: True} - name: eth1
- { name: eth2, description: test-interface-2, enabled: True} - name: eth2
enabled: True
register: result register: result
- assert: - assert:
@ -193,8 +195,9 @@
- name: Delete interface aggregate - name: Delete interface aggregate
vyos_interface: vyos_interface:
aggregate: aggregate:
- { name: eth1, state: absent} - name: eth1
- { name: eth2, state: absent} - name: eth2
state: absent
register: result register: result
- assert: - assert:
@ -206,8 +209,9 @@
- name: Delete interface aggregate (idempotent) - name: Delete interface aggregate (idempotent)
vyos_interface: vyos_interface:
aggregate: aggregate:
- { name: eth1, state: absent} - name: eth1
- { name: eth2, state: absent} - name: eth2
state: absent
register: result register: result
- assert: - assert:

View file

@ -156,8 +156,8 @@
- name: Remove collection of linkagg definitions - name: Remove collection of linkagg definitions
vyos_linkagg: vyos_linkagg:
aggregate: aggregate:
- { name: bond0 } - name: bond0
- { name: bond1 } - name: bond1
state: absent state: absent
register: result register: result
@ -172,8 +172,8 @@
- name: Remove collection of linkagg definitions again (idempotent) - name: Remove collection of linkagg definitions again (idempotent)
vyos_linkagg: vyos_linkagg:
aggregate: aggregate:
- { name: bond0 } - name: bond0
- { name: bond1 } - name: bond1
state: absent state: absent
register: result register: result

View file

@ -90,8 +90,8 @@
- name: Create aggregate of LLDP interface configurations - name: Create aggregate of LLDP interface configurations
vyos_lldp_interface: vyos_lldp_interface:
aggregate: aggregate:
- { name: eth1 } - name: eth1
- { name: eth2 } - name: eth2
state: present state: present
register: result register: result
@ -104,8 +104,8 @@
- name: Create aggregate of LLDP interface configurations again (idempotent) - name: Create aggregate of LLDP interface configurations again (idempotent)
vyos_lldp_interface: vyos_lldp_interface:
aggregate: aggregate:
- { name: eth1 } - name: eth1
- { name: eth2 } - name: eth2
state: present state: present
register: result register: result
@ -116,7 +116,7 @@
- name: Override LLDP interface configuration on aggregate - name: Override LLDP interface configuration on aggregate
vyos_lldp_interface: vyos_lldp_interface:
aggregate: aggregate:
- { name: eth1 } - name: eth1
- { name: eth2, state: disabled } - { name: eth2, state: disabled }
state: present state: present
register: result register: result
@ -129,7 +129,7 @@
- name: Override LLDP interface configuration on aggregate again (idempotent) - name: Override LLDP interface configuration on aggregate again (idempotent)
vyos_lldp_interface: vyos_lldp_interface:
aggregate: aggregate:
- { name: eth1 } - name: eth1
- { name: eth2, state: disabled } - { name: eth2, state: disabled }
state: present state: present
register: result register: result
@ -141,8 +141,8 @@
- name: Delete aggregate of LLDP interface configurations - name: Delete aggregate of LLDP interface configurations
vyos_lldp_interface: vyos_lldp_interface:
aggregate: aggregate:
- { name: eth1 } - name: eth1
- { name: eth2 } - name: eth2
state: absent state: absent
register: result register: result
@ -155,8 +155,8 @@
- name: Delete aggregate of LLDP interface configurations (idempotent) - name: Delete aggregate of LLDP interface configurations (idempotent)
vyos_lldp_interface: vyos_lldp_interface:
aggregate: aggregate:
- { name: eth1 } - name: eth1
- { name: eth2 } - name: eth2
state: absent state: absent
register: result register: result