diff --git a/lib/ansible/module_utils/junos.py b/lib/ansible/module_utils/junos.py index 8a6ed1e2c8e..8ec0a8a0dfc 100644 --- a/lib/ansible/module_utils/junos.py +++ b/lib/ansible/module_utils/junos.py @@ -184,6 +184,10 @@ def locked_config(module): def get_diff(module): reply = get_configuration(module, compare=True, format='text') + # if warning is received from device diff is empty. + if isinstance(reply, list): + return None + output = reply.find('.//configuration-output') if output is not None: return to_text(output.text, encoding='latin1').strip() @@ -210,7 +214,7 @@ def get_param(module, key): return module.params[key] or module.params['provider'].get(key) -def map_params_to_obj(module, param_to_xpath_map): +def map_params_to_obj(module, param_to_xpath_map, param=None): """ Creates a new dictionary with key as xpath corresponding to param and value is a list of dict with metadata and values for @@ -231,12 +235,15 @@ def map_params_to_obj(module, param_to_xpath_map): :param param_to_xpath_map: Modules params to xpath map :return: obj """ + if not param: + param = module.params + obj = collections.OrderedDict() for key, attribute in param_to_xpath_map.items(): - if key in module.params: + if key in param: is_attribute_dict = False - value = module.params[key] + value = param[key] if not isinstance(value, (list, tuple)): value = [value] @@ -261,10 +268,13 @@ def map_params_to_obj(module, param_to_xpath_map): return obj -def map_obj_to_ele(module, want, top, value_map=None): +def map_obj_to_ele(module, want, top, value_map=None, param=None): if not HAS_LXML: module.fail_json(msg='lxml is not installed.') + if not param: + param = module.params + root = Element('root') top_ele = top.split('/') ele = SubElement(root, top_ele[0]) @@ -273,8 +283,8 @@ def map_obj_to_ele(module, want, top, value_map=None): for item in top_ele[1:-1]: ele = SubElement(ele, item) container = ele - state = module.params.get('state') - active = module.params.get('active') + state = param.get('state') + active = param.get('active') if active: oper = 'active' else: @@ -374,3 +384,14 @@ def map_obj_to_ele(module, want, top, value_map=None): par.set('delete', 'delete') return root.getchildren()[0] + + +def to_param_list(module): + aggregate = module.params.get('aggregate') + if aggregate: + if isinstance(aggregate, dict): + return [aggregate] + else: + return aggregate + else: + return [module.params] diff --git a/lib/ansible/modules/network/junos/junos_banner.py b/lib/ansible/modules/network/junos/junos_banner.py index f05f917fc8f..3e4500984e2 100644 --- a/lib/ansible/modules/network/junos/junos_banner.py +++ b/lib/ansible/modules/network/junos/junos_banner.py @@ -2,26 +2,15 @@ # -*- 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 . -# +# 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.0', 'status': ['preview'], - 'supported_by': 'community'} + 'supported_by': 'core'} DOCUMENTATION = """ --- diff --git a/lib/ansible/modules/network/junos/junos_command.py b/lib/ansible/modules/network/junos/junos_command.py index 774ce8ec650..86c820fd7e8 100644 --- a/lib/ansible/modules/network/junos/junos_command.py +++ b/lib/ansible/modules/network/junos/junos_command.py @@ -1,20 +1,12 @@ #!/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 . -# +# -*- 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.0', 'status': ['preview'], diff --git a/lib/ansible/modules/network/junos/junos_config.py b/lib/ansible/modules/network/junos/junos_config.py index 7ccea607b5d..5042eae53d0 100644 --- a/lib/ansible/modules/network/junos/junos_config.py +++ b/lib/ansible/modules/network/junos/junos_config.py @@ -1,20 +1,12 @@ #!/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 . -# +# -*- 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.0', 'status': ['preview'], diff --git a/lib/ansible/modules/network/junos/junos_facts.py b/lib/ansible/modules/network/junos/junos_facts.py index 13f3964fb10..062fd6f566c 100644 --- a/lib/ansible/modules/network/junos/junos_facts.py +++ b/lib/ansible/modules/network/junos/junos_facts.py @@ -1,20 +1,12 @@ #!/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 . -# +# -*- 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.0', 'status': ['preview'], diff --git a/lib/ansible/modules/network/junos/junos_interface.py b/lib/ansible/modules/network/junos/junos_interface.py index e2a2210e412..5919086b847 100644 --- a/lib/ansible/modules/network/junos/junos_interface.py +++ b/lib/ansible/modules/network/junos/junos_interface.py @@ -2,22 +2,11 @@ # -*- 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 . -# +# 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.0', 'status': ['preview'], @@ -65,7 +54,7 @@ options: description: List of Interfaces definitions. purge: description: - - Purge Interfaces not defined in the aggregates parameter. + - Purge Interfaces not defined in the aggregate parameter. This applies only for logical interface. default: no state: @@ -126,6 +115,18 @@ EXAMPLES = """ speed: 1g mtu: 256 duplex: full + +- name: Create interface using aggregate + junos_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: half, mtu: 512} + - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256} + +- name: Delete interface using aggregate + junos_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, state: absent} + - { name: ge-0/0/2, description: test-interface-2, state: absent} """ RETURN = """ @@ -141,10 +142,12 @@ diff.prepared: """ import collections +from copy import copy + from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.junos import junos_argument_spec, check_args from ansible.module_utils.junos import load_config, map_params_to_obj, map_obj_to_ele -from ansible.module_utils.junos import commit_configuration, discard_changes, locked_config +from ansible.module_utils.junos import commit_configuration, discard_changes, locked_config, to_param_list try: from lxml.etree import tostring @@ -159,19 +162,21 @@ def validate_mtu(value, module): module.fail_json(msg='mtu must be between 256 and 9192') -def validate_param_values(module, obj): +def validate_param_values(module, obj, param=None): + if not param: + 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(module.params.get(key), module) + validator(param.get(key), module) def main(): """ main entry point for module execution """ - argument_spec = dict( - name=dict(required=True), + element_spec = dict( + name=dict(), description=dict(), enabled=dict(), speed=dict(), @@ -179,16 +184,30 @@ def main(): duplex=dict(choices=['full', 'half', 'auto']), tx_rate=dict(), rx_rate=dict(), - aggregate=dict(), - purge=dict(default=False, type='bool'), state=dict(default='present', choices=['present', 'absent', 'up', 'down']), active=dict(default=True, type='bool') ) + aggregate_spec = copy(element_spec) + aggregate_spec['name'] = dict(required=True) + + 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(junos_argument_spec) + required_one_of = [['name', 'aggregate']] + mutually_exclusive = [['name', 'aggregate'], + ['state', 'aggregate'], + ['active', 'aggregate']] + module = AnsibleModule(argument_spec=argument_spec, + required_one_of=required_one_of, + mutually_exclusive=mutually_exclusive, supports_check_mode=True) warnings = list() @@ -211,26 +230,33 @@ def main(): ('disable', {'xpath': 'disable', 'tag_only': True}) ]) - state = module.params.get('state') - module.params['disable'] = True if state == 'down' else False - - if state in ('present', 'up', 'down'): - module.params['state'] = 'present' - else: - module.params['disable'] = True - choice_to_value_map = { 'link-mode': {'full': 'full-duplex', 'half': 'half-duplex', 'auto': 'automatic'} } - validate_param_values(module, param_to_xpath_map) + params = to_param_list(module) + + requests = list() + for param in params: + item = copy(param) + state = item.get('state') + item['disable'] = True if state == 'down' else False + + if state in ('present', 'up', 'down'): + item['state'] = 'present' + else: + item['disable'] = True - want = map_params_to_obj(module, param_to_xpath_map) - ele = map_obj_to_ele(module, want, top, choice_to_value_map) + validate_param_values(module, param_to_xpath_map, param=item) + want = map_params_to_obj(module, param_to_xpath_map, param=item) + requests.append(map_obj_to_ele(module, want, top, value_map=choice_to_value_map, param=item)) + diff = None with locked_config(module): - diff = load_config(module, tostring(ele), warnings, action='replace') + for req in requests: + diff = load_config(module, tostring(req), warnings, action='replace') + # issue commit after last configuration change is done commit = not module.check_mode if diff: if commit: diff --git a/lib/ansible/modules/network/junos/junos_l3_interface.py b/lib/ansible/modules/network/junos/junos_l3_interface.py index b5912015cb6..f1a86407cf4 100644 --- a/lib/ansible/modules/network/junos/junos_l3_interface.py +++ b/lib/ansible/modules/network/junos/junos_l3_interface.py @@ -2,22 +2,11 @@ # -*- 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 . -# +# 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.0', 'status': ['preview'], @@ -80,6 +69,25 @@ EXAMPLES = """ junos_l3_interface: name: ge-0/0/1 state: absent + +- name: Set ipv4 address using aggregate + junos_l3_interface: + aggregate: + - name: ge-0/0/1 + ipv4: 1.1.1.1 + - name: ge-0/0/2 + ipv4: 2.2.2.2 + ipv6: fd5d:12c9:2201:2::2 + +- name: Delete ipv4 address using aggregate + junos_l3_interface: + aggregate: + - name: ge-0/0/1 + ipv4: 1.1.1.1 + state: absent + - name: ge-0/0/2 + ipv4: 2.2.2.2 + state: absent """ RETURN = """ @@ -95,10 +103,12 @@ diff: """ import collections +from copy import copy + from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.junos import junos_argument_spec, check_args from ansible.module_utils.junos import load_config, map_params_to_obj, map_obj_to_ele -from ansible.module_utils.junos import commit_configuration, discard_changes, locked_config +from ansible.module_utils.junos import commit_configuration, discard_changes, locked_config, to_param_list try: from lxml.etree import tostring @@ -111,23 +121,35 @@ USE_PERSISTENT_CONNECTION = True def main(): """ main entry point for module execution """ - argument_spec = dict( - name=dict(required=True), + element_spec = dict( + name=dict(), ipv4=dict(), ipv6=dict(), unit=dict(default=0, type='int'), - aggregate=dict(), - purge=dict(default=False, type='bool'), state=dict(default='present', choices=['present', 'absent']), active=dict(default=True, type='bool') ) + aggregate_spec = copy(element_spec) + aggregate_spec['name'] = dict(required=True) + + 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(junos_argument_spec) - required_one_of = [['ipv4', 'ipv6']] + required_one_of = [['name', 'aggregate']] + + mutually_exclusive = [['name', 'aggregate'], + ['state', 'aggregate'], + ['active', 'aggregate']] module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, + mutually_exclusive=mutually_exclusive, required_one_of=required_one_of) warnings = list() @@ -148,11 +170,21 @@ def main(): ('ipv6', {'xpath': 'inet6/address/name', 'top': 'unit/family', 'is_key': True}) ]) - want = map_params_to_obj(module, param_to_xpath_map) - ele = map_obj_to_ele(module, want, top) + params = to_param_list(module) + + requests = list() + for param in params: + item = copy(param) + if not item['ipv4'] and not item['ipv6']: + module.fail_json(msg="one of the following is required: ipv4,ipv6") + + want = map_params_to_obj(module, param_to_xpath_map, param=item) + requests.append(map_obj_to_ele(module, want, top, param=item)) + diff = None with locked_config(module): - diff = load_config(module, tostring(ele), warnings, action='replace') + for req in requests: + diff = load_config(module, tostring(req), warnings, action='replace') commit = not module.check_mode if diff: diff --git a/lib/ansible/modules/network/junos/junos_linkagg.py b/lib/ansible/modules/network/junos/junos_linkagg.py index 824208b30f1..0c320b2dac0 100644 --- a/lib/ansible/modules/network/junos/junos_linkagg.py +++ b/lib/ansible/modules/network/junos/junos_linkagg.py @@ -2,22 +2,11 @@ # -*- 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 . -# +# 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.0', 'status': ['preview'], @@ -62,12 +51,6 @@ options: description: description: - Description of Interface. - collection: - description: List of link aggregation definitions. - purge: - description: - - Purge link aggregation groups not defined in the collections parameter. - default: no state: description: - State of the link aggregation group. @@ -281,8 +264,6 @@ def main(): min_links=dict(type='int'), device_count=dict(type='int'), description=dict(default=DEFAULT_COMMENT), - collection=dict(type='list'), - purge=dict(type='bool'), state=dict(default='present', choices=['present', 'absent', 'up', 'down']), active=dict(default=True, type='bool') ) diff --git a/lib/ansible/modules/network/junos/junos_lldp.py b/lib/ansible/modules/network/junos/junos_lldp.py index 3f96ea6ad31..4706ac51592 100644 --- a/lib/ansible/modules/network/junos/junos_lldp.py +++ b/lib/ansible/modules/network/junos/junos_lldp.py @@ -2,22 +2,11 @@ # -*- 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 . -# +# 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.0', 'status': ['preview'], diff --git a/lib/ansible/modules/network/junos/junos_lldp_interface.py b/lib/ansible/modules/network/junos/junos_lldp_interface.py index 999bad73957..1f522c9cb6e 100644 --- a/lib/ansible/modules/network/junos/junos_lldp_interface.py +++ b/lib/ansible/modules/network/junos/junos_lldp_interface.py @@ -2,22 +2,11 @@ # -*- 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 . -# +# 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.0', 'status': ['preview'], diff --git a/lib/ansible/modules/network/junos/junos_logging.py b/lib/ansible/modules/network/junos/junos_logging.py index 1be8e3436c4..8bc0dc3b88b 100644 --- a/lib/ansible/modules/network/junos/junos_logging.py +++ b/lib/ansible/modules/network/junos/junos_logging.py @@ -2,22 +2,11 @@ # -*- 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 . -# +# 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.0', 'status': ['preview'], @@ -53,7 +42,7 @@ options: description: List of logging definitions. purge: description: - - Purge logging not defined in the aggregates parameter. + - Purge logging not defined in the aggregate parameter. default: no state: description: @@ -108,6 +97,18 @@ EXAMPLES = """ files: 30 size: 65536 rotate_frequency: 10 + +- name: Configure file logging using aggregate + junos_logging: + aggregate: + - {dest: file, name: test-1, facility: pfe, level: critical, active: True} + - {dest: file, name: test-2, facility: kernel, level: emergency, active: True} + +- name: Delete file logging using aggregate + junos_logging: + aggregate: + - {dest: file, name: test-1, facility: pfe, level: critical, active: True, state: absent} + - {dest: file, name: test-2, facility: kernel, level: emergency, active: True, state: absent} """ RETURN = """ @@ -125,9 +126,11 @@ diff.prepared: """ import collections +from copy import copy + from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.junos import junos_argument_spec, check_args -from ansible.module_utils.junos import load_config, map_params_to_obj, map_obj_to_ele +from ansible.module_utils.junos import load_config, map_params_to_obj, map_obj_to_ele, to_param_list from ansible.module_utils.junos import commit_configuration, discard_changes, locked_config try: @@ -153,18 +156,20 @@ def validate_rotate_frequency(value, module): module.fail_json(msg='rotate_frequency must be between 1 and 59') -def validate_param_values(module, obj): +def validate_param_values(module, obj, param=None): + if not param: + 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(module.params.get(key), module) + validator(param.get(key), module) def main(): """ main entry point for module execution """ - argument_spec = dict( + element_spec = dict( dest=dict(choices=['console', 'host', 'file', 'user']), name=dict(), facility=dict(), @@ -173,14 +178,28 @@ def main(): size=dict(type='int'), files=dict(type='int'), src_addr=dict(), - aggregate=dict(), - purge=dict(default=False, type='bool'), state=dict(default='present', choices=['present', 'absent']), active=dict(default=True, type='bool') ) + argument_spec = dict( + aggregate=dict(type='list', elements='dict', options=element_spec), + purge=dict(default=False, type='bool') + ) + + argument_spec.update(element_spec) argument_spec.update(junos_argument_spec) + mutually_exclusive = [['dest', 'aggregate'], + ['name', 'aggregate'], + ['facility', 'aggregate'], + ['rotate_frequency', 'aggregate'], + ['size', 'aggregate'], + ['files', 'aggregate'], + ['src_addr', 'aggregate'], + ['state', 'aggregate'], + ['active', 'aggregate']] + required_if = [('dest', 'host', ['name', 'facility', 'level']), ('dest', 'file', ['name', 'facility', 'level']), ('dest', 'user', ['name', 'facility', 'level']), @@ -188,6 +207,7 @@ def main(): module = AnsibleModule(argument_spec=argument_spec, required_if=required_if, + mutually_exclusive=mutually_exclusive, supports_check_mode=True) warnings = list() @@ -198,40 +218,47 @@ def main(): if warnings: result['warnings'] = warnings - dest = module.params.get('dest') - if dest == 'console' and module.params.get('name'): - module.fail_json(msg="%s and %s are mutually exclusive" % ('console', 'name')) - - top = 'system/syslog' - is_facility_key = False - field_top = None - if dest: - if dest == 'console': - field_top = dest - is_facility_key = True - else: - field_top = dest + '/contents' - is_facility_key = False - - param_to_xpath_map = collections.OrderedDict() - param_to_xpath_map.update([ - ('name', {'xpath': 'name', 'is_key': True, 'top': dest}), - ('facility', {'xpath': 'name', 'is_key': is_facility_key, 'top': field_top}), - ('size', {'xpath': 'size', 'leaf_only': True, 'is_key': True, 'top': 'archive'}), - ('files', {'xpath': 'files', 'leaf_only': True, 'is_key': True, 'top': 'archive'}), - ('rotate_frequency', {'xpath': 'log-rotate-frequency', 'leaf_only': True}), - ]) - - if module.params.get('level'): - param_to_xpath_map['level'] = {'xpath': module.params.get('level'), 'tag_only': True, 'top': field_top} - - validate_param_values(module, param_to_xpath_map) - - want = map_params_to_obj(module, param_to_xpath_map) - ele = map_obj_to_ele(module, want, top) + params = to_param_list(module) + + requests = list() + for param in params: + item = copy(param) + dest = item.get('dest') + if dest == 'console' and item.get('name'): + module.fail_json(msg="%s and %s are mutually exclusive" % ('console', 'name')) + + top = 'system/syslog' + is_facility_key = False + field_top = None + if dest: + if dest == 'console': + field_top = dest + is_facility_key = True + else: + field_top = dest + '/contents' + is_facility_key = False + + param_to_xpath_map = collections.OrderedDict() + param_to_xpath_map.update([ + ('name', {'xpath': 'name', 'is_key': True, 'top': dest}), + ('facility', {'xpath': 'name', 'is_key': is_facility_key, 'top': field_top}), + ('size', {'xpath': 'size', 'leaf_only': True, 'is_key': True, 'top': 'archive'}), + ('files', {'xpath': 'files', 'leaf_only': True, 'is_key': True, 'top': 'archive'}), + ('rotate_frequency', {'xpath': 'log-rotate-frequency', 'leaf_only': True}), + ]) + + if item.get('level'): + param_to_xpath_map['level'] = {'xpath': item.get('level'), 'tag_only': True, 'top': field_top} + + validate_param_values(module, param_to_xpath_map, param=item) + + want = map_params_to_obj(module, param_to_xpath_map, param=item) + requests.append(map_obj_to_ele(module, want, top, param=item)) + diff = None with locked_config(module): - diff = load_config(module, tostring(ele), warnings, action='replace') + for req in requests: + diff = load_config(module, tostring(req), warnings, action='replace') commit = not module.check_mode if diff: diff --git a/lib/ansible/modules/network/junos/junos_netconf.py b/lib/ansible/modules/network/junos/junos_netconf.py index c0235071978..fba91b60376 100644 --- a/lib/ansible/modules/network/junos/junos_netconf.py +++ b/lib/ansible/modules/network/junos/junos_netconf.py @@ -1,20 +1,12 @@ #!/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 . -# +# -*- 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.0', 'status': ['preview'], diff --git a/lib/ansible/modules/network/junos/junos_package.py b/lib/ansible/modules/network/junos/junos_package.py index fc05875d617..5f8072450d5 100644 --- a/lib/ansible/modules/network/junos/junos_package.py +++ b/lib/ansible/modules/network/junos/junos_package.py @@ -1,24 +1,16 @@ #!/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 . -# +# -*- 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.0', 'status': ['preview'], - 'supported_by': 'community'} + 'supported_by': 'core'} DOCUMENTATION = """ diff --git a/lib/ansible/modules/network/junos/junos_rpc.py b/lib/ansible/modules/network/junos/junos_rpc.py index 57ec7bc6d3b..a7e12468d62 100644 --- a/lib/ansible/modules/network/junos/junos_rpc.py +++ b/lib/ansible/modules/network/junos/junos_rpc.py @@ -1,20 +1,12 @@ #!/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 . -# +# -*- 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.0', 'status': ['preview'], diff --git a/lib/ansible/modules/network/junos/junos_static_route.py b/lib/ansible/modules/network/junos/junos_static_route.py index d829722bff5..5204e929e29 100644 --- a/lib/ansible/modules/network/junos/junos_static_route.py +++ b/lib/ansible/modules/network/junos/junos_static_route.py @@ -2,22 +2,11 @@ # -*- 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 . -# +# 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.0', 'status': ['preview'], @@ -58,7 +47,7 @@ options: description: List of static route definitions purge: description: - - Purge static routes not defined in the aggregates parameter. + - Purge static routes not defined in the aggregate parameter. default: no state: description: @@ -111,6 +100,18 @@ EXAMPLES = """ qualified_preference: 3 state: present active: True + +- name: Configure static route using aggregate + junos_static_route: + aggregate: + - {address: 4.4.4.0/24, next_hop: 3.3.3.3, preference: 10, qualified_next_hop: 5.5.5.5, qualified_preference: 30} + - {address: 5.5.5.0/24, next_hop: 6.6.6.6, preference: 11, qualified_next_hop: 7.7.7.7, qualified_preference: 12} + +- name: Delete static route using aggregate + junos_static_route: + aggregate: + - {address: 4.4.4.0/24, state: absent} + - {address: 5.5.5.0/24, state: absent} """ RETURN = """ @@ -131,9 +132,11 @@ diff.prepared: """ import collections +from copy import copy + from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.junos import junos_argument_spec, check_args -from ansible.module_utils.junos import load_config, map_params_to_obj, map_obj_to_ele +from ansible.module_utils.junos import load_config, map_params_to_obj, map_obj_to_ele, to_param_list from ansible.module_utils.junos import commit_configuration, discard_changes, locked_config try: @@ -144,32 +147,38 @@ except ImportError: USE_PERSISTENT_CONNECTION = True -def validate_param_values(module, obj): - for key in obj: - # validate the param value (if validator func exists) - validator = globals().get('validate_%s' % key) - if callable(validator): - validator(module.params.get(key), module) - - def main(): """ main entry point for module execution """ - argument_spec = dict( - address=dict(required=True, type='str', aliases=['prefix']), + element_spec = dict( + address=dict(type='str', aliases=['prefix']), next_hop=dict(type='str'), preference=dict(type='int', aliases=['admin_distance']), qualified_next_hop=dict(type='str'), qualified_preference=dict(type='int'), - aggregate=dict(type='list'), - purge=dict(type='bool'), state=dict(default='present', choices=['present', 'absent']), active=dict(default=True, type='bool') ) + aggregate_spec = copy(element_spec) + aggregate_spec['address'] = dict(required=True) + + 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(junos_argument_spec) + required_one_of = [['aggregate', 'address']] - mutually_exclusive = [['aggregate', 'address']] + mutually_exclusive = [['aggregate', 'address'], + ['aggregate', 'next_hop'], + ['aggregate', 'preference'], + ['aggregate', 'qualified_next_hop'], + ['aggregate', 'qualified_preference'], + ['aggregate', 'state'], + ['aggregate', 'active']] module = AnsibleModule(argument_spec=argument_spec, required_one_of=required_one_of, @@ -179,10 +188,6 @@ def main(): warnings = list() check_args(module, warnings) - if module.params['state'] == 'present': - if not module.params['address'] and module.params['next_hop']: - module.fail_json(msg="parameters are required together: ['address', 'next_hop']") - result = {'changed': False} if warnings: @@ -199,13 +204,21 @@ def main(): ('qualified_preference', {'xpath': 'preference', 'top': 'qualified-next-hop'}) ]) - validate_param_values(module, param_to_xpath_map) + params = to_param_list(module) + requests = list() + + for param in params: + item = copy(param) + if item['state'] == 'present': + if not item['address'] and item['next_hop']: + module.fail_json(msg="parameters are required together: ['address', 'next_hop']") - want = map_params_to_obj(module, param_to_xpath_map) - ele = map_obj_to_ele(module, want, top) + want = map_params_to_obj(module, param_to_xpath_map, param=item) + requests.append(map_obj_to_ele(module, want, top, param=item)) with locked_config(module): - diff = load_config(module, tostring(ele), warnings, action='replace') + for req in requests: + diff = load_config(module, tostring(req), warnings, action='replace') commit = not module.check_mode if diff: diff --git a/lib/ansible/modules/network/junos/junos_system.py b/lib/ansible/modules/network/junos/junos_system.py index c7a42bc4b60..9a0fa789fa0 100644 --- a/lib/ansible/modules/network/junos/junos_system.py +++ b/lib/ansible/modules/network/junos/junos_system.py @@ -2,22 +2,11 @@ # -*- 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 . -# +# 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.0', 'status': ['preview'], diff --git a/lib/ansible/modules/network/junos/junos_user.py b/lib/ansible/modules/network/junos/junos_user.py index ab0ff9212e3..a4a825c3562 100644 --- a/lib/ansible/modules/network/junos/junos_user.py +++ b/lib/ansible/modules/network/junos/junos_user.py @@ -1,20 +1,12 @@ #!/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 . -# +# -*- 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.0', 'status': ['preview'], @@ -122,6 +114,18 @@ EXAMPLES = """ junos_user: name: ansible purge: yes + +- name: Create list of users + junos_user: + aggregate: + - {name: test_user1, full_name: test_user2, role: operator, state: present} + - {name: test_user2, full_name: test_user2, role: read-only, state: present} + +- name: Delete list of users + junos_user: + aggregate: + - {name: test_user1, full_name: test_user2, role: operator, state: absent} + - {name: test_user2, full_name: test_user2, role: read-only, state: absent} """ RETURN = """ @@ -251,26 +255,35 @@ def map_params_to_obj(module): def main(): """ main entry point for module execution """ - argument_spec = dict( - aggregate=dict(type='list', aliases=['collection', 'users']), + element_spec = dict( name=dict(), - full_name=dict(), role=dict(choices=ROLES, default='unauthorized'), sshkey=dict(), - - purge=dict(type='bool'), - state=dict(choices=['present', 'absent'], default='present'), active=dict(default=True, type='bool') ) - mutually_exclusive = [('aggregate', 'name')] + argument_spec = dict( + aggregate=dict(type='list', elements='dict', options=element_spec, aliases=['collection', 'users']), + purge=dict(default=False, type='bool') + ) + + argument_spec.update(element_spec) + argument_spec.update(junos_argument_spec) + + required_one_of = [['aggregate', 'name']] + mutually_exclusive = [['aggregate', 'name'], + ['aggregate', 'full_name'], + ['aggregate', 'sshkey'], + ['aggregate', 'state'], + ['aggregate', 'active']] argument_spec.update(junos_argument_spec) module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=mutually_exclusive, + required_one_of=required_one_of, supports_check_mode=True) warnings = list() diff --git a/lib/ansible/modules/network/junos/junos_vlan.py b/lib/ansible/modules/network/junos/junos_vlan.py index e49729e7487..45068df8d1d 100644 --- a/lib/ansible/modules/network/junos/junos_vlan.py +++ b/lib/ansible/modules/network/junos/junos_vlan.py @@ -2,28 +2,16 @@ # -*- 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 . -# +# 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.0', 'status': ['preview'], 'supported_by': 'core'} - DOCUMENTATION = """ --- module: junos_vlan @@ -53,7 +41,7 @@ options: description: List of VLANs definitions. purge: description: - - Purge VLANs not defined in the aggregates parameter. + - Purge VLANs not defined in the aggregate parameter. default: no state: description: @@ -95,6 +83,18 @@ EXAMPLES = """ vlan_name: test state: present active: True + +- name: Create vlan configuration using aggregate + junos_vlan: + aggregate: + - { vlan_id: 159, name: test_vlan_1, description: test vlan-1, state: present } + - { vlan_id: 160, name: test_vlan_2, description: test vlan-2, state: present } + +- name: Delete vlan configuration using aggregate + junos_vlan: + aggregate: + - { vlan_id: 159, name: test_vlan_1, state: absent } + - { vlan_id: 160, name: test_vlan_2, state: absent } """ RETURN = """ @@ -110,9 +110,11 @@ diff.prepared: """ import collections +from copy import copy + from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.junos import junos_argument_spec, check_args -from ansible.module_utils.junos import load_config, map_params_to_obj, map_obj_to_ele +from ansible.module_utils.junos import load_config, map_params_to_obj, map_obj_to_ele, to_param_list from ansible.module_utils.junos import commit_configuration, discard_changes, locked_config try: @@ -128,31 +130,52 @@ def validate_vlan_id(value, module): module.fail_json(msg='vlan_id must be between 1 and 4094') -def validate_param_values(module, obj): +def validate_param_values(module, obj, param=None): + if not param: + 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(module.params.get(key), module) + validator(param.get(key), module) def main(): """ main entry point for module execution """ - argument_spec = dict( - name=dict(required=True), - vlan_id=dict(required=True, type='int'), + element_spec = dict( + name=dict(), + vlan_id=dict(type='int'), description=dict(), interfaces=dict(), - aggregate=dict(), - purge=dict(default=False, type='bool'), state=dict(default='present', choices=['present', 'absent']), active=dict(default=True, type='bool') ) + aggregate_spec = copy(element_spec) + aggregate_spec['name'] = dict(required=True) + aggregate_spec['vlan_id'] = dict(required=True, type='int') + 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(junos_argument_spec) + required_one_of = [['aggregate', 'name']] + required_together = [['name', 'vlan_id']] + mutually_exclusive = [['aggregate', 'name'], + ['aggregate', 'vlan_id'], + ['aggregate', 'description'], + ['aggregate', 'interfaces'], + ['aggregate', 'state'], + ['aggregate', 'active']] + 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() @@ -172,13 +195,19 @@ def main(): ('description', 'description') ]) - validate_param_values(module, param_to_xpath_map) + params = to_param_list(module) + requests = list() + + for param in params: + item = copy(param) + validate_param_values(module, param_to_xpath_map, param=item) - want = map_params_to_obj(module, param_to_xpath_map) - ele = map_obj_to_ele(module, want, top) + want = map_params_to_obj(module, param_to_xpath_map, param=item) + requests.append(map_obj_to_ele(module, want, top, param=item)) with locked_config(module): - diff = load_config(module, tostring(ele), warnings, action='replace') + for req in requests: + diff = load_config(module, tostring(req), warnings, action='replace') commit = not module.check_mode if diff: diff --git a/lib/ansible/modules/network/junos/junos_vrf.py b/lib/ansible/modules/network/junos/junos_vrf.py index d3e0b663e6a..07749fe1cca 100644 --- a/lib/ansible/modules/network/junos/junos_vrf.py +++ b/lib/ansible/modules/network/junos/junos_vrf.py @@ -2,22 +2,11 @@ # -*- 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 . -# +# 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.0', 'status': ['preview'], @@ -68,9 +57,8 @@ options: exclusive with the C(name) argument. purge: description: - - Instructs the module to consider the - VRF definition absolute. It will remove any previously configured - VRFs on the device. + - Instructs the module to consider the VRF definition absolute. + It will remove any previously configured VRFs on the device. default: false state: description: @@ -136,6 +124,26 @@ EXAMPLES = """ rd: 1.1.1.1:10 target: target:65514:113 active: True + +- name: Create vrf using aggregate + junos_vrf: + aggregate: + - name: test-1 + description: test-vrf-1 + interfaces: + - ge-0/0/3 + - ge-0/0/2 + rd: 1.1.1.1:10 + target: target:65514:113 + state: present + - name: test-2 + description: test-vrf-2 + interfaces: + - ge-0/0/4 + - ge-0/0/5 + rd: 2.2.2.2:10 + target: target:65515:114 + state: present """ RETURN = """ @@ -156,9 +164,11 @@ diff.prepared: """ import collections +from copy import copy + from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.junos import junos_argument_spec, check_args -from ansible.module_utils.junos import load_config, map_params_to_obj, map_obj_to_ele +from ansible.module_utils.junos import load_config, map_params_to_obj, map_obj_to_ele, to_param_list from ansible.module_utils.junos import commit_configuration, discard_changes, locked_config try: @@ -172,22 +182,40 @@ USE_PERSISTENT_CONNECTION = True def main(): """ main entry point for module execution """ - argument_spec = dict( - name=dict(required=True), + element_spec = dict( + name=dict(), description=dict(), rd=dict(type='list'), interfaces=dict(type='list'), target=dict(type='list'), - aggregate=dict(type='list'), - purge=dict(default=False, type='bool'), state=dict(default='present', choices=['present', 'absent']), active=dict(default=True, type='bool') ) + aggregate_spec = copy(element_spec) + aggregate_spec['name'] = dict(required=True) + + 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(junos_argument_spec) + required_one_of = [['aggregate', 'name']] + mutually_exclusive = [['aggregate', 'name'], + ['aggregate', 'description'], + ['aggregate', 'rd'], + ['aggregate', 'interfaces'], + ['aggregate', 'target'], + ['aggregate', 'state'], + ['aggregate', 'active']] + module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True) + supports_check_mode=True, + required_one_of=required_one_of, + mutually_exclusive=mutually_exclusive) warnings = list() check_args(module, warnings) @@ -209,13 +237,20 @@ def main(): ('target', 'vrf-target/community'), ]) - module.params['type'] = 'vrf' + params = to_param_list(module) + requests = list() + + for param in params: + item = copy(param) + + item['type'] = 'vrf' - want = map_params_to_obj(module, param_to_xpath_map) - ele = map_obj_to_ele(module, want, top) + want = map_params_to_obj(module, param_to_xpath_map, param=item) + requests.append(map_obj_to_ele(module, want, top, param=item)) with locked_config(module): - diff = load_config(module, tostring(ele), warnings, action='replace') + for req in requests: + diff = load_config(module, tostring(req), warnings, action='replace') commit = not module.check_mode if diff: diff --git a/test/integration/targets/junos_interface/tests/netconf/basic.yaml b/test/integration/targets/junos_interface/tests/netconf/basic.yaml index d29dda301f0..75d09cada7f 100644 --- a/test/integration/targets/junos_interface/tests/netconf/basic.yaml +++ b/test/integration/targets/junos_interface/tests/netconf/basic.yaml @@ -147,13 +147,141 @@ provider: "{{ netconf }}" register: config -- name: Get running configuration - junos_rpc: - rpc: get-configuration - provider: "{{ netconf }}" - register: config - - assert: that: - "result.changed == true" - "'ge-0/0/1' not in config.xml" + +- name: Aggregate setup- delete interface ge-0/0/1 + junos_interface: + name: ge-0/0/1 + state: absent + provider: "{{ netconf }}" + register: result + +- name: Aggregate setup- delete interface ge-0/0/2 + junos_interface: + name: ge-0/0/2 + state: absent + provider: "{{ netconf }}" + register: result + +- name: Set interface on aggregate + junos_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: half, mtu: 512} + - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\+ *ge-0/0/1") + - result.diff.prepared | search("\+ *description test-interface-1") + - result.diff.prepared | search("\+ *speed 1g") + - result.diff.prepared | search("\+ *mtu 512") + - result.diff.prepared | search("\+ *link-mode half-duplex") + - result.diff.prepared | search("\+ *description test-interface-2") + - result.diff.prepared | search("\+ *speed 10m") + - result.diff.prepared | search("\+ * mtu 256") + - result.diff.prepared | search("\+ *link-mode full-duplex") + +- name: Set interface on aggregate (idempotent) + junos_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: half, mtu: 512} + - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == false' + +- name: Disable interface on aggregate + junos_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: half, mtu: 512, state: down} + - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, state: down} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\+ *disable") + +- name: Enable interface on aggregate + junos_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: half, mtu: 512, state: up} + - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, state: up} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\- *disable") + +- name: Deactivate interface configuration on aggregate + junos_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: half, mtu: 512, active: False} + - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, active: False} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("! *inactive[:] ge-0/0/1") + - result.diff.prepared | search("! *inactive[:] ge-0/0/2") + +- name: Activate interface configuration on aggregate + junos_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: half, mtu: 512, active: True} + - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, active: True} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("! *active[:] ge-0/0/1") + - result.diff.prepared | search("! *active[:] ge-0/0/2") + +- name: Delete interface on aggregate + junos_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: half, mtu: 512, state: absent} + - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, state: absent} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\- *ge-0/0/1") + - result.diff.prepared | search("\- *description test-interface-1") + - result.diff.prepared | search("\- *speed 1g") + - result.diff.prepared | search("\- *mtu 512") + - result.diff.prepared | search("\- *link-mode half-duplex") + - result.diff.prepared | search("\- *description test-interface-2") + - result.diff.prepared | search("\- *speed 10m") + - result.diff.prepared | search("\- * mtu 256") + - result.diff.prepared | search("\- *link-mode full-duplex") + +- name: Delete interface aggregate (idempotent) + junos_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: half, mtu: 512, state: absent} + - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, state: absent} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == false' diff --git a/test/integration/targets/junos_l3_interface/tests/netconf/basic.yaml b/test/integration/targets/junos_l3_interface/tests/netconf/basic.yaml index a0617ea0845..917625449c7 100644 --- a/test/integration/targets/junos_l3_interface/tests/netconf/basic.yaml +++ b/test/integration/targets/junos_l3_interface/tests/netconf/basic.yaml @@ -110,3 +110,151 @@ - assert: that: - "result.changed == false" + +- name: Aggregate setup- delete interface ge-0/0/1 + junos_l3_interface: + name: ge-0/0/1 + ipv4: 1.1.1.1 + ipv6: fd5d:12c9:2201:1::1 + state: absent + provider: "{{ netconf }}" + register: result + +- name: Aggregate setup- delete interface ge-0/0/2 + junos_l3_interface: + name: ge-0/0/2 + ipv4: 2.2.2.2 + ipv6: fd5d:12c9:2201:2::2 + state: absent + provider: "{{ netconf }}" + register: result + +- name: Configure l3 interface in aggregate + junos_l3_interface: + aggregate: + - name: ge-0/0/1 + ipv4: 1.1.1.1 + ipv6: fd5d:12c9:2201:1::1 + - name: ge-0/0/2 + ipv4: 2.2.2.2 + ipv6: fd5d:12c9:2201:2::2 + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - "'edit interfaces ge-0/0/1 unit 0 family inet' in result.diff.prepared" + - result.diff.prepared | search("\+ *address 1.1.1.1/32") + - "'edit interfaces ge-0/0/1 unit 0 family inet6' in result.diff.prepared" + - result.diff.prepared | search("\+ *address fd5d:12c9:2201:1::1/128") + - "'edit interfaces ge-0/0/2 unit 0 family inet' in result.diff.prepared" + - result.diff.prepared | search("\+ *address 2.2.2.2/32") + - "'edit interfaces ge-0/0/2 unit 0 family inet6' in result.diff.prepared" + - result.diff.prepared | search("\+ *address fd5d:12c9:2201:2::2/128") + +- name: Configure l3 interface in aggregate (idempotent) + junos_l3_interface: + aggregate: + - name: ge-0/0/1 + ipv4: 1.1.1.1 + ipv6: fd5d:12c9:2201:1::1 + active: True + - name: ge-0/0/2 + ipv4: 2.2.2.2 + ipv6: fd5d:12c9:2201:2::2 + active: True + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == false' + +- name: Deactivate l3 interface configuration + junos_l3_interface: + aggregate: + - name: ge-0/0/1 + ipv4: 1.1.1.1 + ipv6: fd5d:12c9:2201:1::1 + active: False + - name: ge-0/0/2 + ipv4: 2.2.2.2 + ipv6: fd5d:12c9:2201:2::2 + active: False + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("! *inactive[:] address 1.1.1.1/32") + - result.diff.prepared | search("! *inactive[:] address fd5d:12c9:2201:1::1/128") + - result.diff.prepared | search("! *inactive[:] address 2.2.2.2/32") + - result.diff.prepared | search("! *inactive[:] address fd5d:12c9:2201:2::2/128") + +- name: Activate l3 interface configuration + junos_l3_interface: + aggregate: + - name: ge-0/0/1 + ipv4: 1.1.1.1 + ipv6: fd5d:12c9:2201:1::1 + active: True + - name: ge-0/0/2 + ipv4: 2.2.2.2 + ipv6: fd5d:12c9:2201:2::2 + active: True + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("! *active[:] address 1.1.1.1/32") + - result.diff.prepared | search("! *active[:] address fd5d:12c9:2201:1::1/128") + - result.diff.prepared | search("! *active[:] address 2.2.2.2/32") + - result.diff.prepared | search("! *active[:] address fd5d:12c9:2201:2::2/128") + +- name: Delete l3 interface configuration + junos_l3_interface: + aggregate: + - name: ge-0/0/1 + ipv4: 1.1.1.1 + ipv6: fd5d:12c9:2201:1::1 + state: absent + - name: ge-0/0/2 + ipv4: 2.2.2.2 + ipv6: fd5d:12c9:2201:2::2 + state: absent + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - "'edit interfaces ge-0/0/1 unit 0 family inet' in result.diff.prepared" + - result.diff.prepared | search("\- *address 1.1.1.1/32") + - "'edit interfaces ge-0/0/1 unit 0 family inet6' in result.diff.prepared" + - result.diff.prepared | search("\- *address fd5d:12c9:2201:1::1/128") + - "'edit interfaces ge-0/0/2 unit 0 family inet' in result.diff.prepared" + - result.diff.prepared | search("\- *address 2.2.2.2/32") + - "'edit interfaces ge-0/0/2 unit 0 family inet6' in result.diff.prepared" + - result.diff.prepared | search("\- *address fd5d:12c9:2201:2::2/128") + +- name: Delete l3 interface configuration (idempotent) + junos_l3_interface: + aggregate: + - name: ge-0/0/1 + ipv4: 1.1.1.1 + ipv6: fd5d:12c9:2201:1::1 + state: absent + - name: ge-0/0/2 + ipv4: 2.2.2.2 + ipv6: fd5d:12c9:2201:2::2 + state: absent + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == false' diff --git a/test/integration/targets/junos_logging/tests/netconf/basic.yaml b/test/integration/targets/junos_logging/tests/netconf/basic.yaml index 1b015d56da7..8777250dfe3 100644 --- a/test/integration/targets/junos_logging/tests/netconf/basic.yaml +++ b/test/integration/targets/junos_logging/tests/netconf/basic.yaml @@ -296,3 +296,87 @@ - "'64k' not in config.xml" - "'40' not in config.xml" - "'20' not in config.xml" + +- name: Seup file logging using aggregate + junos_logging: + aggregate: + - {dest: file, name: test-1, facility: pfe, level: critical, state: absent} + - {dest: file, name: test-2, facility: kernel, level: emergency, state: absent} + provider: "{{ netconf }}" + register: result + +- name: Configure file logging using aggregate + junos_logging: + aggregate: + - {dest: file, name: test-1, facility: pfe, level: critical, active: True} + - {dest: file, name: test-2, facility: kernel, level: emergency, active: True} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\+ *file test-1") + - result.diff.prepared | search("\+ *pfe critical") + - result.diff.prepared | search("\+ *file test-2") + - result.diff.prepared | search("\+ *kernel emergency") + +- name: Deactivate file logging configuration using aggregate + junos_logging: + aggregate: + - {dest: file, name: test-1, facility: pfe, level: critical, active: False} + - {dest: file, name: test-2, facility: kernel, level: emergency, active: False} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("! *inactive[:] file test-1") + - result.diff.prepared | search("! *inactive[:] pfe") + - result.diff.prepared | search("! *inactive[:] file test-2") + - result.diff.prepared | search("! *inactive[:] kernel") + +- name: activate file logging configuration using aggregate + junos_logging: + aggregate: + - {dest: file, name: test-1, facility: pfe, level: critical, active: True} + - {dest: file, name: test-2, facility: kernel, level: emergency, active: True} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("! *active[:] file test-1") + - result.diff.prepared | search("! *active[:] pfe") + - result.diff.prepared | search("! *active[:] file test-2") + - result.diff.prepared | search("! *active[:] kernel") + +- name: Delete file logging using aggregate + junos_logging: + aggregate: + - {dest: file, name: test-1, facility: pfe, level: critical, state: absent} + - {dest: file, name: test-2, facility: kernel, level: emergency, state: absent} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\- *file test-1") + - result.diff.prepared | search("\- *pfe critical") + - result.diff.prepared | search("\- *file test-2") + - result.diff.prepared | search("\- *kernel emergency") + +- name: Delete file logging using aggregate (idempotent) + junos_logging: + aggregate: + - {dest: file, name: test-1, facility: pfe, level: critical, state: absent} + - {dest: file, name: test-2, facility: kernel, level: emergency, state: absent} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - "result.changed == false" diff --git a/test/integration/targets/junos_static_route/tests/netconf/basic.yaml b/test/integration/targets/junos_static_route/tests/netconf/basic.yaml index c849364ed48..c3df57c840e 100644 --- a/test/integration/targets/junos_static_route/tests/netconf/basic.yaml +++ b/test/integration/targets/junos_static_route/tests/netconf/basic.yaml @@ -140,3 +140,102 @@ - assert: that: - "result.changed == false" + +- name: Setup static route for aggegrate + junos_static_route: + aggregate: + - {address: 4.4.4.0/24, state: absent} + - {address: 5.5.5.0/24, state: absent} + provider: "{{ netconf }}" + +- name: Confgiure static route using aggegrate + junos_static_route: + aggregate: + - {address: 4.4.4.0/24, next_hop: 3.3.3.3, preference: 10, qualified_next_hop: 5.5.5.5, qualified_preference: 30} + - {address: 5.5.5.0/24, next_hop: 6.6.6.6, preference: 11, qualified_next_hop: 7.7.7.7, qualified_preference: 12} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\+ *route 4.4.4.0/24") + - result.diff.prepared | search("\+ *next-hop 3.3.3.3") + - result.diff.prepared | search("\+ *qualified-next-hop 5.5.5.5") + - result.diff.prepared | search("\+ *preference 30") + - result.diff.prepared | search("\+ *preference 10") + - result.diff.prepared | search("\+ *route 5.5.5.0/24") + - result.diff.prepared | search("\+ *next-hop 6.6.6.6") + - result.diff.prepared | search("\+ *qualified-next-hop 7.7.7.7") + - result.diff.prepared | search("\+ *preference 12") + - result.diff.prepared | search("\+ *preference 11") + +- name: Deactivate static route configuration using aggegrate + junos_static_route: + aggregate: + - {address: 4.4.4.0/24, next_hop: 3.3.3.3, preference: 10, qualified_next_hop: 5.5.5.5, qualified_preference: 30, active: False} + - {address: 5.5.5.0/24, next_hop: 6.6.6.6, preference: 11, qualified_next_hop: 7.7.7.7, qualified_preference: 12, active: False} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("! *inactive[:] route 4.4.4.0/24") + - result.diff.prepared | search("! *inactive[:] qualified-next-hop 5.5.5.5") + - result.diff.prepared | search("! *inactive[:] preference") + - result.diff.prepared | search("! *inactive[:] route 5.5.5.0/24") + - result.diff.prepared | search("! *inactive[:] qualified-next-hop 7.7.7.7") + - result.diff.prepared | search("! *inactive[:] preference") + +- name: Activate static route configuration using aggegrate + junos_static_route: + aggregate: + - {address: 4.4.4.0/24, next_hop: 3.3.3.3, preference: 10, qualified_next_hop: 5.5.5.5, qualified_preference: 30, active: True} + - {address: 5.5.5.0/24, next_hop: 6.6.6.6, preference: 11, qualified_next_hop: 7.7.7.7, qualified_preference: 12, active: True} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("! *active[:] route 4.4.4.0/24") + - result.diff.prepared | search("! *active[:] qualified-next-hop 5.5.5.5") + - result.diff.prepared | search("! *active[:] preference") + - result.diff.prepared | search("! *active[:] route 5.5.5.0/24") + - result.diff.prepared | search("! *active[:] qualified-next-hop 7.7.7.7") + - result.diff.prepared | search("! *active[:] preference") + +- name: Delete static route configuration using aggegrate + junos_static_route: + aggregate: + - {address: 4.4.4.0/24, state: absent} + - {address: 5.5.5.0/24, state: absent} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\- *route 4.4.4.0/24") + - result.diff.prepared | search("\- *next-hop 3.3.3.3") + - result.diff.prepared | search("\- *qualified-next-hop 5.5.5.5") + - result.diff.prepared | search("\- *preference 30") + - result.diff.prepared | search("\- *preference 10") + - result.diff.prepared | search("\- *route 5.5.5.0/24") + - result.diff.prepared | search("\- *next-hop 6.6.6.6") + - result.diff.prepared | search("\- *qualified-next-hop 7.7.7.7") + - result.diff.prepared | search("\- *preference 12") + - result.diff.prepared | search("\- *preference 11") + +- name: Delete static route configuration using aggegrate (idempotent) + junos_static_route: + aggregate: + - {address: 4.4.4.0/24, state: absent} + - {address: 5.5.5.0/24, state: absent} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - "result.changed == false" diff --git a/test/integration/targets/junos_vlan/tests/netconf/basic.yaml b/test/integration/targets/junos_vlan/tests/netconf/basic.yaml index e154e93e851..4812536deec 100644 --- a/test/integration/targets/junos_vlan/tests/netconf/basic.yaml +++ b/test/integration/targets/junos_vlan/tests/netconf/basic.yaml @@ -102,3 +102,83 @@ that: - "result.changed == true" - "'test-vlan' not in config.xml" + +- name: Setup vlan configuration for aggregate + junos_vlan: + aggregate: + - { vlan_id: 159, name: test_vlan_1, state: absent } + - { vlan_id: 160, name: test_vlan_2, state: absent } + provider: "{{ netconf }}" + +- name: Create vlan configuration using aggregate + junos_vlan: + aggregate: + - { vlan_id: 159, name: test_vlan_1, description: test vlan-1, state: present } + - { vlan_id: 160, name: test_vlan_2, description: test vlan-2, state: present } + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\+ *vlans") + - result.diff.prepared | search("\+ *test_vlan_1") + - result.diff.prepared | search("\+ *vlan-id 159") + - result.diff.prepared | search("\+ *test_vlan_2") + - result.diff.prepared | search("\+ *vlan-id 160") + +- name: Deactivate vlan configuration using aggregate + junos_vlan: + aggregate: + - { vlan_id: 159, name: test_vlan_1, description: test vlan-1, active: False } + - { vlan_id: 160, name: test_vlan_2, description: test vlan-2, active: False } + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("! *inactive[:] test_vlan_1") + - result.diff.prepared | search("! *inactive[:] test_vlan_2") + +- name: activate vlan configuration using aggregate + junos_vlan: + aggregate: + - { vlan_id: 159, name: test_vlan_1, description: test vlan-1, active: True } + - { vlan_id: 160, name: test_vlan_2, description: test vlan-2, active: True } + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("! *active[:] test_vlan_1") + - result.diff.prepared | search("! *active[:] test_vlan_2") + +- name: Delete vlan configuration using aggregate + junos_vlan: + aggregate: + - { vlan_id: 159, name: test_vlan_1, state: absent } + - { vlan_id: 160, name: test_vlan_2, state: absent } + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\- *test_vlan_1") + - result.diff.prepared | search("\- *vlan-id 159") + - result.diff.prepared | search("\- *test_vlan_2") + - result.diff.prepared | search("\- *vlan-id 160") + +- name: Delete vlan configuration using aggregate (idempotent) + junos_vlan: + aggregate: + - { vlan_id: 159, name: test_vlan_1, state: absent } + - { vlan_id: 160, name: test_vlan_2, state: absent } + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == false' diff --git a/test/integration/targets/junos_vrf/tests/netconf/basic.yaml b/test/integration/targets/junos_vrf/tests/netconf/basic.yaml index ee57090dbde..c1ced7bcb21 100644 --- a/test/integration/targets/junos_vrf/tests/netconf/basic.yaml +++ b/test/integration/targets/junos_vrf/tests/netconf/basic.yaml @@ -167,3 +167,171 @@ - assert: that: - "result.changed == false" + +- name: Setup vrf using aggregate + junos_vrf: + aggregate: + - name: test-1 + state: absent + - name: test-2 + state: absent + provider: "{{ netconf }}" + register: result + +- name: Create vrf using aggregate + junos_vrf: + aggregate: + - name: test-1 + description: test-vrf-1 + interfaces: + - ge-0/0/3 + - ge-0/0/2 + rd: 1.1.1.1:10 + target: target:65514:113 + state: present + - name: test-2 + description: test-vrf-2 + interfaces: + - ge-0/0/4 + - ge-0/0/5 + rd: 2.2.2.2:10 + target: target:65515:114 + state: present + provider: "{{ netconf }}" + register: result + +- assert: + that: + - "result.changed == true" + - result.diff.prepared | search("\+ *test-1") + - result.diff.prepared | search("\+ *description test-vrf-1") + - result.diff.prepared | search("\+ *instance-type vrf") + - result.diff.prepared | search("\+ *interface ge-0/0/2.0") + - result.diff.prepared | search("\+ *interface ge-0/0/3.0") + - result.diff.prepared | search("\+ *route-distinguisher 1.1.1.1:10") + - result.diff.prepared | search("\+ *vrf-target target:65514:113") + - result.diff.prepared | search("\+ *test-2") + - result.diff.prepared | search("\+ *description test-vrf-2") + - result.diff.prepared | search("\+ *instance-type vrf") + - result.diff.prepared | search("\+ *interface ge-0/0/4.0") + - result.diff.prepared | search("\+ *interface ge-0/0/5.0") + - result.diff.prepared | search("\+ *route-distinguisher 2.2.2.2:10") + - result.diff.prepared | search("\+ *vrf-target target:65515:114") + +- name: Deactivate vrf configuration using aggregate + junos_vrf: + aggregate: + - name: test-1 + description: test-vrf-1 + interfaces: + - ge-0/0/3 + - ge-0/0/2 + rd: 1.1.1.1:10 + target: target:65514:113 + state: present + active: False + - name: test-2 + description: test-vrf-2 + interfaces: + - ge-0/0/4 + - ge-0/0/5 + rd: 2.2.2.2:10 + target: target:65515:114 + state: present + active: False + provider: "{{ netconf }}" + register: result + +- assert: + that: + - "result.changed == true" + - "'edit routing-instances test-1' in result.diff.prepared" + - result.diff.prepared | search("! *inactive[:] interface ge-0/0/2.0") + - result.diff.prepared | search("! *inactive[:] interface ge-0/0/3.0") + - result.diff.prepared | search("! *inactive[:] route-distinguisher") + - result.diff.prepared | search("! *inactive[:] vrf-target") + - "'edit routing-instances test-2' in result.diff.prepared" + - result.diff.prepared | search("! *inactive[:] interface ge-0/0/4.0") + - result.diff.prepared | search("! *inactive[:] interface ge-0/0/5.0") + - result.diff.prepared | search("! *inactive[:] route-distinguisher") + - result.diff.prepared | search("! *inactive[:] vrf-target") + +- name: Deactivate vrf configuration using aggregate + junos_vrf: + aggregate: + - name: test-1 + description: test-vrf-1 + interfaces: + - ge-0/0/3 + - ge-0/0/2 + rd: 1.1.1.1:10 + target: target:65514:113 + state: present + active: True + - name: test-2 + description: test-vrf-2 + interfaces: + - ge-0/0/4 + - ge-0/0/5 + rd: 2.2.2.2:10 + target: target:65515:114 + state: present + active: True + provider: "{{ netconf }}" + register: result + +- assert: + that: + - "result.changed == true" + - "'edit routing-instances test-1' in result.diff.prepared" + - result.diff.prepared | search("! *active[:] interface ge-0/0/2.0") + - result.diff.prepared | search("! *active[:] interface ge-0/0/3.0") + - result.diff.prepared | search("! *active[:] route-distinguisher") + - result.diff.prepared | search("! *active[:] vrf-target") + - "'edit routing-instances test-2' in result.diff.prepared" + - result.diff.prepared | search("! *active[:] interface ge-0/0/4.0") + - result.diff.prepared | search("! *active[:] interface ge-0/0/5.0") + - result.diff.prepared | search("! *active[:] route-distinguisher") + - result.diff.prepared | search("! *active[:] vrf-target") + +- name: Delete vrf configuration using aggregate + junos_vrf: + aggregate: + - name: test-1 + state: absent + - name: test-2 + state: absent + provider: "{{ netconf }}" + register: result + +- assert: + that: + - "result.changed == true" + - result.diff.prepared | search("\- *test-1") + - result.diff.prepared | search("\- *description test-vrf-1") + - result.diff.prepared | search("\- *instance-type vrf") + - result.diff.prepared | search("\- *interface ge-0/0/2.0") + - result.diff.prepared | search("\- *interface ge-0/0/3.0") + - result.diff.prepared | search("\- *route-distinguisher 1.1.1.1:10") + - result.diff.prepared | search("\- *vrf-target target:65514:113") + - result.diff.prepared | search("\- *test-2") + - result.diff.prepared | search("\- *description test-vrf-2") + - result.diff.prepared | search("\- *instance-type vrf") + - result.diff.prepared | search("\- *interface ge-0/0/4.0") + - result.diff.prepared | search("\- *interface ge-0/0/5.0") + - result.diff.prepared | search("\- *route-distinguisher 2.2.2.2:10") + - result.diff.prepared | search("\- *vrf-target target:65515:114") + +- name: Delete vrf configuration using aggregate (idempotent) + junos_vrf: + aggregate: + - name: test-1 + state: absent + - name: test-2 + state: absent + provider: "{{ netconf }}" + register: result + +- assert: + that: + - "result.changed == false" diff --git a/test/integration/targets/net_interface/tests/junos/basic.yaml b/test/integration/targets/net_interface/tests/junos/basic.yaml index b2dfa4fbc1a..4f3913368a0 100644 --- a/test/integration/targets/net_interface/tests/junos/basic.yaml +++ b/test/integration/targets/net_interface/tests/junos/basic.yaml @@ -83,7 +83,7 @@ - assert: that: - "result.changed == true" - - "'' in config.xml" + - result.diff.prepared | search("\+ *disable") - "'ge-0/0/1' in config.xml" - name: Enable interface @@ -103,7 +103,7 @@ - assert: that: - "result.changed == true" - - "'' not in config.xml" + - result.diff.prepared | search("\- *disable") - "'ge-0/0/1' in config.xml" - name: Delete interface @@ -124,3 +124,109 @@ that: - "result.changed == true" - "'ge-0/0/1' not in config.xml" + +- name: Aggregate setup- delete interface ge-0/0/1 + net_interface: + name: ge-0/0/1 + state: absent + provider: "{{ netconf }}" + register: result + +- name: Aggregate setup- delete interface ge-0/0/2 + net_interface: + name: ge-0/0/2 + state: absent + provider: "{{ netconf }}" + register: result + +- name: Set interface on aggregate + net_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: half, mtu: 512} + - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\+ *ge-0/0/1") + - result.diff.prepared | search("\+ *description test-interface-1") + - result.diff.prepared | search("\+ *speed 1g") + - result.diff.prepared | search("\+ *mtu 512") + - result.diff.prepared | search("\+ *link-mode half-duplex") + - result.diff.prepared | search("\+ *description test-interface-2") + - result.diff.prepared | search("\+ *speed 10m") + - result.diff.prepared | search("\+ * mtu 256") + - result.diff.prepared | search("\+ *link-mode full-duplex") + +- name: Set interface on aggregate (idempotent) + net_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: half, mtu: 512} + - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == false' + +- name: Disable interface on aggregate + net_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: half, mtu: 512, state: down} + - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, state: down} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\+ *disable") + +- name: Enable interface on aggregate + net_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: half, mtu: 512, state: up} + - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, state: up} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\- *disable") + +- name: Delete interface on aggregate + net_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: half, mtu: 512, state: absent} + - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, state: absent} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\- *ge-0/0/1") + - result.diff.prepared | search("\- *description test-interface-1") + - result.diff.prepared | search("\- *speed 1g") + - result.diff.prepared | search("\- *mtu 512") + - result.diff.prepared | search("\- *link-mode half-duplex") + - result.diff.prepared | search("\- *description test-interface-2") + - result.diff.prepared | search("\- *speed 10m") + - result.diff.prepared | search("\- * mtu 256") + - result.diff.prepared | search("\- *link-mode full-duplex") + +- name: Delete interface aggregate (idempotent) + net_interface: + aggregate: + - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: half, mtu: 512, state: absent} + - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, state: absent} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == false' diff --git a/test/integration/targets/net_l3_interface/tests/junos/basic.yaml b/test/integration/targets/net_l3_interface/tests/junos/basic.yaml index 0017721cc09..4e4dcb65903 100644 --- a/test/integration/targets/net_l3_interface/tests/junos/basic.yaml +++ b/test/integration/targets/net_l3_interface/tests/junos/basic.yaml @@ -80,3 +80,107 @@ - assert: that: - "result.changed == false" + +- name: Aggregate setup- delete interface ge-0/0/1 + net_l3_interface: + name: ge-0/0/1 + ipv4: 1.1.1.1 + ipv6: fd5d:12c9:2201:1::1 + state: absent + provider: "{{ netconf }}" + register: result + +- name: Aggregate setup- delete interface ge-0/0/2 + net_l3_interface: + name: ge-0/0/2 + ipv4: 2.2.2.2 + ipv6: fd5d:12c9:2201:2::2 + state: absent + provider: "{{ netconf }}" + register: result + +- name: Configure l3 interface in aggregate + net_l3_interface: + aggregate: + - name: ge-0/0/1 + ipv4: 1.1.1.1 + ipv6: fd5d:12c9:2201:1::1 + - name: ge-0/0/2 + ipv4: 2.2.2.2 + ipv6: fd5d:12c9:2201:2::2 + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - "'edit interfaces ge-0/0/1 unit 0 family inet' in result.diff.prepared" + - result.diff.prepared | search("\+ *address 1.1.1.1/32") + - "'edit interfaces ge-0/0/1 unit 0 family inet6' in result.diff.prepared" + - result.diff.prepared | search("\+ *address fd5d:12c9:2201:1::1/128") + - "'edit interfaces ge-0/0/2 unit 0 family inet' in result.diff.prepared" + - result.diff.prepared | search("\+ *address 2.2.2.2/32") + - "'edit interfaces ge-0/0/2 unit 0 family inet6' in result.diff.prepared" + - result.diff.prepared | search("\+ *address fd5d:12c9:2201:2::2/128") + +- name: Configure l3 interface in aggregate (idempotent) + net_l3_interface: + aggregate: + - name: ge-0/0/1 + ipv4: 1.1.1.1 + ipv6: fd5d:12c9:2201:1::1 + active: True + - name: ge-0/0/2 + ipv4: 2.2.2.2 + ipv6: fd5d:12c9:2201:2::2 + active: True + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == false' + +- name: Delete l3 interface configuration + net_l3_interface: + aggregate: + - name: ge-0/0/1 + ipv4: 1.1.1.1 + ipv6: fd5d:12c9:2201:1::1 + state: absent + - name: ge-0/0/2 + ipv4: 2.2.2.2 + ipv6: fd5d:12c9:2201:2::2 + state: absent + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - "'edit interfaces ge-0/0/1 unit 0 family inet' in result.diff.prepared" + - result.diff.prepared | search("\- *address 1.1.1.1/32") + - "'edit interfaces ge-0/0/1 unit 0 family inet6' in result.diff.prepared" + - result.diff.prepared | search("\- *address fd5d:12c9:2201:1::1/128") + - "'edit interfaces ge-0/0/2 unit 0 family inet' in result.diff.prepared" + - result.diff.prepared | search("\- *address 2.2.2.2/32") + - "'edit interfaces ge-0/0/2 unit 0 family inet6' in result.diff.prepared" + - result.diff.prepared | search("\- *address fd5d:12c9:2201:2::2/128") + +- name: Delete l3 interface configuration (idempotent) + net_l3_interface: + aggregate: + - name: ge-0/0/1 + ipv4: 1.1.1.1 + ipv6: fd5d:12c9:2201:1::1 + state: absent + - name: ge-0/0/2 + ipv4: 2.2.2.2 + ipv6: fd5d:12c9:2201:2::2 + state: absent + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == false' diff --git a/test/integration/targets/net_logging/tests/junos/basic.yaml b/test/integration/targets/net_logging/tests/junos/basic.yaml index 53f583253bc..41b14d88191 100644 --- a/test/integration/targets/net_logging/tests/junos/basic.yaml +++ b/test/integration/targets/net_logging/tests/junos/basic.yaml @@ -122,3 +122,35 @@ that: - "result.changed == true" - "'' not in config.xml" + +- name: Configure file logging using aggregate + net_logging: + aggregate: + - {dest: file, name: test-1, facility: pfe, level: critical, active: True} + - {dest: file, name: test-2, facility: kernel, level: emergency, active: True} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\+ *file test-1") + - result.diff.prepared | search("\+ *pfe critical") + - result.diff.prepared | search("\+ *file test-2") + - result.diff.prepared | search("\+ *kernel emergency") + +- name: Delete file logging using aggregate + net_logging: + aggregate: + - {dest: file, name: test-1, facility: pfe, level: critical, state: absent} + - {dest: file, name: test-2, facility: kernel, level: emergency, state: absent} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\- *file test-1") + - result.diff.prepared | search("\- *pfe critical") + - result.diff.prepared | search("\- *file test-2") + - result.diff.prepared | search("\- *kernel emergency") diff --git a/test/integration/targets/net_static_route/tests/junos/basic.yaml b/test/integration/targets/net_static_route/tests/junos/basic.yaml index bbf6d27212c..9e7b0177595 100644 --- a/test/integration/targets/net_static_route/tests/junos/basic.yaml +++ b/test/integration/targets/net_static_route/tests/junos/basic.yaml @@ -69,3 +69,66 @@ - assert: that: - "result.changed == false" + +- name: Setup static route for aggegrate + net_static_route: + aggregate: + - {address: 4.4.4.0/24, state: absent} + - {address: 5.5.5.0/24, state: absent} + provider: "{{ netconf }}" + +- name: Confgiure static route using aggegrate + net_static_route: + aggregate: + - {address: 4.4.4.0/24, next_hop: 3.3.3.3, preference: 10, qualified_next_hop: 5.5.5.5, qualified_preference: 30} + - {address: 5.5.5.0/24, next_hop: 6.6.6.6, preference: 11, qualified_next_hop: 7.7.7.7, qualified_preference: 12} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\+ *route 4.4.4.0/24") + - result.diff.prepared | search("\+ *next-hop 3.3.3.3") + - result.diff.prepared | search("\+ *qualified-next-hop 5.5.5.5") + - result.diff.prepared | search("\+ *preference 30") + - result.diff.prepared | search("\+ *preference 10") + - result.diff.prepared | search("\+ *route 5.5.5.0/24") + - result.diff.prepared | search("\+ *next-hop 6.6.6.6") + - result.diff.prepared | search("\+ *qualified-next-hop 7.7.7.7") + - result.diff.prepared | search("\+ *preference 12") + - result.diff.prepared | search("\+ *preference 11") + +- name: Delete static route configuration using aggegrate + net_static_route: + aggregate: + - {address: 4.4.4.0/24, state: absent} + - {address: 5.5.5.0/24, state: absent} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\- *route 4.4.4.0/24") + - result.diff.prepared | search("\- *next-hop 3.3.3.3") + - result.diff.prepared | search("\- *qualified-next-hop 5.5.5.5") + - result.diff.prepared | search("\- *preference 30") + - result.diff.prepared | search("\- *preference 10") + - result.diff.prepared | search("\- *route 5.5.5.0/24") + - result.diff.prepared | search("\- *next-hop 6.6.6.6") + - result.diff.prepared | search("\- *qualified-next-hop 7.7.7.7") + - result.diff.prepared | search("\- *preference 12") + - result.diff.prepared | search("\- *preference 11") + +- name: Delete static route configuration using aggegrate (idempotent) + net_static_route: + aggregate: + - {address: 4.4.4.0/24, state: absent} + - {address: 5.5.5.0/24, state: absent} + provider: "{{ netconf }}" + register: result + +- assert: + that: + - "result.changed == false" diff --git a/test/integration/targets/net_user/tests/junos/basic.yaml b/test/integration/targets/net_user/tests/junos/basic.yaml index b05377cb11f..d77dfafe93e 100644 --- a/test/integration/targets/net_user/tests/junos/basic.yaml +++ b/test/integration/targets/net_user/tests/junos/basic.yaml @@ -25,7 +25,7 @@ that: - "result.changed == true" - "'test_user' in config.xml" - - "'read-only' in config.xml" + - "'operator' in config.xml" - name: Create user again (idempotent) net_user: diff --git a/test/integration/targets/net_vlan/tests/junos/basic.yaml b/test/integration/targets/net_vlan/tests/junos/basic.yaml index 9bd980de8df..b1b4d4fd3be 100644 --- a/test/integration/targets/net_vlan/tests/junos/basic.yaml +++ b/test/integration/targets/net_vlan/tests/junos/basic.yaml @@ -58,3 +58,55 @@ that: - "result.changed == true" - "'test-vlan' not in config.xml" + +- name: Setup vlan configuration for aggregate + net_vlan: + aggregate: + - { vlan_id: 159, name: test_vlan_1, state: absent } + - { vlan_id: 160, name: test_vlan_2, state: absent } + provider: "{{ netconf }}" + +- name: Create vlan configuration using aggregate + net_vlan: + aggregate: + - { vlan_id: 159, name: test_vlan_1, description: test vlan-1, state: present } + - { vlan_id: 160, name: test_vlan_2, description: test vlan-2, state: present } + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\+ *vlans") + - result.diff.prepared | search("\+ *test_vlan_1") + - result.diff.prepared | search("\+ *vlan-id 159") + - result.diff.prepared | search("\+ *test_vlan_2") + - result.diff.prepared | search("\+ *vlan-id 160") + +- name: Delete vlan configuration using aggregate + junos_vlan: + aggregate: + - { vlan_id: 159, name: test_vlan_1, state: absent } + - { vlan_id: 160, name: test_vlan_2, state: absent } + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == true' + - result.diff.prepared | search("\- *test_vlan_1") + - result.diff.prepared | search("\- *vlan-id 159") + - result.diff.prepared | search("\- *test_vlan_2") + - result.diff.prepared | search("\- *vlan-id 160") + +- name: Delete vlan configuration using aggregate (idempotent) + junos_vlan: + aggregate: + - { vlan_id: 159, name: test_vlan_1, state: absent } + - { vlan_id: 160, name: test_vlan_2, state: absent } + provider: "{{ netconf }}" + register: result + +- assert: + that: + - 'result.changed == false' diff --git a/test/integration/targets/net_vrf/tests/junos/basic.yaml b/test/integration/targets/net_vrf/tests/junos/basic.yaml index 587a5702356..05967f8d980 100644 --- a/test/integration/targets/net_vrf/tests/junos/basic.yaml +++ b/test/integration/targets/net_vrf/tests/junos/basic.yaml @@ -23,13 +23,13 @@ - assert: that: - "result.changed == true" - - "'+ test-1' in result.diff.prepared" - - "'+ description test-vrf-1;' in result.diff.prepared" - - "'+ instance-type vrf;' in result.diff.prepared" - - "'+ interface ge-0/0/5.0;' in result.diff.prepared" - - "'+ interface ge-0/0/6.0;' in result.diff.prepared" - - "'+ route-distinguisher 3.3.3.3:10;' in result.diff.prepared" - - "'+ vrf-target target:65513:111;' in result.diff.prepared" + - result.diff.prepared | search("\+ *test-1") + - result.diff.prepared | search("\+ *description test-vrf-1") + - result.diff.prepared | search("\+ *instance-type vrf") + - result.diff.prepared | search("\+ *interface ge-0/0/5.0") + - result.diff.prepared | search("\+ *interface ge-0/0/6.0") + - result.diff.prepared | search("\+ *route-distinguisher 3.3.3.3:10") + - result.diff.prepared | search("\+ *vrf-target target:65513:111") - name: Configure vrf and its parameter (idempotent) net_vrf: @@ -65,18 +65,18 @@ that: - "result.changed == true" - "'[edit routing-instances test-1]' in result.diff.prepared" - - "'+ interface ge-0/0/2.0;' in result.diff.prepared" - - "'+ interface ge-0/0/3.0;' in result.diff.prepared" - - "'- interface ge-0/0/5.0;' in result.diff.prepared" - - "'- interface ge-0/0/6.0;' in result.diff.prepared" + - result.diff.prepared | search("\+ *interface ge-0/0/2.0") + - result.diff.prepared | search("\+ *interface ge-0/0/3.0") + - result.diff.prepared | search("\- *interface ge-0/0/5.0") + - result.diff.prepared | search("\- *interface ge-0/0/6.0") - "'[edit routing-instances test-1]' in result.diff.prepared" - - "'- route-distinguisher 3.3.3.3:10;' in result.diff.prepared" - - "'+ route-distinguisher 1.1.1.1:10;' in result.diff.prepared" - - "'- vrf-target target:65513:111;' in result.diff.prepared" - - "'+ vrf-target target:65514:113;' in result.diff.prepared" + - result.diff.prepared | search("\- *route-distinguisher 3.3.3.3:10") + - result.diff.prepared | search("\+ *route-distinguisher 1.1.1.1:10") + - result.diff.prepared | search("\- *vrf-target target:65513:111") + - result.diff.prepared | search("\+ *vrf-target target:65514:113") -- name: Deactivate vrf +- name: Delete vrf net_vrf: name: test-1 description: test-vrf-1 @@ -85,24 +85,22 @@ - ge-0/0/2 rd: 1.1.1.1:10 target: target:65514:113 - state: present - active: False + state: absent provider: "{{ netconf }}" register: result - assert: that: - "result.changed == true" - - "'[edit routing-instances]' in result.diff.prepared" - - "'! inactive: test-1' in result.diff.prepared" - - "'[edit routing-instances test-1]' in result.diff.prepared" - - "'! inactive: interface ge-0/0/2.0' in result.diff.prepared" - - "'! inactive: interface ge-0/0/3.0' in result.diff.prepared" - - "'[edit routing-instances test-1]' in result.diff.prepared" - - "'! inactive: route-distinguisher' in result.diff.prepared" - - "'! inactive: vrf-target' in result.diff.prepared" + - result.diff.prepared | search("\- *test-1") + - result.diff.prepared | search("\- *description test-vrf-1") + - result.diff.prepared | search("\- *instance-type vrf") + - result.diff.prepared | search("\- *interface ge-0/0/2.0") + - result.diff.prepared | search("\- *interface ge-0/0/3.0") + - result.diff.prepared | search("\- *route-distinguisher 1.1.1.1:10") + - result.diff.prepared | search("\- *vrf-target target:65514:113") -- name: Activate vrf +- name: Delete vrf (idempotent) net_vrf: name: test-1 description: test-vrf-1 @@ -111,58 +109,99 @@ - ge-0/0/2 rd: 1.1.1.1:10 target: target:65514:113 - state: present - active: True + state: absent provider: "{{ netconf }}" register: result - assert: that: - - "result.changed == true" - - "'[edit routing-instances]' in result.diff.prepared" - - "'! active: test-1' in result.diff.prepared" - - "'[edit routing-instances test-1]' in result.diff.prepared" - - "'! active: interface ge-0/0/2.0' in result.diff.prepared" - - "'! active: interface ge-0/0/3.0' in result.diff.prepared" - - "'[edit routing-instances test-1]' in result.diff.prepared" - - "'! active: route-distinguisher' in result.diff.prepared" - - "'! active: vrf-target' in result.diff.prepared" + - "result.changed == false" -- name: Delete vrf +- name: Setup vrf using aggregate net_vrf: - name: test-1 - description: test-vrf-1 - interfaces: - - ge-0/0/3 - - ge-0/0/2 - rd: 1.1.1.1:10 - target: target:65514:113 - state: absent + aggregate: + - name: test-1 + state: absent + - name: test-2 + state: absent + provider: "{{ netconf }}" + register: result + +- name: Create vrf using aggregate + net_vrf: + aggregate: + - name: test-1 + description: test-vrf-1 + interfaces: + - ge-0/0/3 + - ge-0/0/2 + rd: 1.1.1.1:10 + target: target:65514:113 + state: present + - name: test-2 + description: test-vrf-2 + interfaces: + - ge-0/0/4 + - ge-0/0/5 + rd: 2.2.2.2:10 + target: target:65515:114 + state: present provider: "{{ netconf }}" register: result - assert: that: - "result.changed == true" - - "'[edit routing-instances]' in result.diff.prepared" - - "'- test-1' in result.diff.prepared" - - "'- description test-vrf-1;' in result.diff.prepared" - - "'- instance-type vrf;' in result.diff.prepared" - - "'- interface ge-0/0/2.0;' in result.diff.prepared" - - "'- interface ge-0/0/3.0;' in result.diff.prepared" - - "'- route-distinguisher 1.1.1.1:10;' in result.diff.prepared" - - "'- vrf-target target:65514:113;' in result.diff.prepared" + - result.diff.prepared | search("\+ *test-1") + - result.diff.prepared | search("\+ *description test-vrf-1") + - result.diff.prepared | search("\+ *instance-type vrf") + - result.diff.prepared | search("\+ *interface ge-0/0/2.0") + - result.diff.prepared | search("\+ *interface ge-0/0/3.0") + - result.diff.prepared | search("\+ *route-distinguisher 1.1.1.1:10") + - result.diff.prepared | search("\+ *vrf-target target:65514:113") + - result.diff.prepared | search("\+ *test-2") + - result.diff.prepared | search("\+ *description test-vrf-2") + - result.diff.prepared | search("\+ *instance-type vrf") + - result.diff.prepared | search("\+ *interface ge-0/0/4.0") + - result.diff.prepared | search("\+ *interface ge-0/0/5.0") + - result.diff.prepared | search("\+ *route-distinguisher 2.2.2.2:10") + - result.diff.prepared | search("\+ *vrf-target target:65515:114") + +- name: Delete vrf configuration using aggregate + net_vrf: + aggregate: + - name: test-1 + state: absent + - name: test-2 + state: absent + provider: "{{ netconf }}" + register: result -- name: Delete vrf (idempotent) +- assert: + that: + - "result.changed == true" + - result.diff.prepared | search("\- *test-1") + - result.diff.prepared | search("\- *description test-vrf-1") + - result.diff.prepared | search("\- *instance-type vrf") + - result.diff.prepared | search("\- *interface ge-0/0/2.0") + - result.diff.prepared | search("\- *interface ge-0/0/3.0") + - result.diff.prepared | search("\- *route-distinguisher 1.1.1.1:10") + - result.diff.prepared | search("\- *vrf-target target:65514:113") + - result.diff.prepared | search("\- *test-2") + - result.diff.prepared | search("\- *description test-vrf-2") + - result.diff.prepared | search("\- *instance-type vrf") + - result.diff.prepared | search("\- *interface ge-0/0/4.0") + - result.diff.prepared | search("\- *interface ge-0/0/5.0") + - result.diff.prepared | search("\- *route-distinguisher 2.2.2.2:10") + - result.diff.prepared | search("\- *vrf-target target:65515:114") + +- name: Delete vrf configuration using aggregate (idempotent) net_vrf: - name: test-1 - description: test-vrf-1 - interfaces: - - ge-0/0/3 - - ge-0/0/2 - rd: 1.1.1.1:10 - target: target:65514:113 - state: absent + aggregate: + - name: test-1 + state: absent + - name: test-2 + state: absent provider: "{{ netconf }}" register: result