junos_interface intent arguments (#27947)

* junos_interface intent arguments

*  Add check for intent argument in junos_interface
*  Integration test for intent arguments

* Minor type fixes

* Add delay only if config diff is present

* add enabled configuration argument

* net_interface test case changes

* Minor doc change
This commit is contained in:
Ganesh Nalawade 2017-08-13 13:18:15 +05:30 committed by GitHub
parent 6e7cf7377b
commit 21bd7bcbb0
6 changed files with 267 additions and 37 deletions

View file

@ -32,7 +32,7 @@ options:
- Description of Interface. - Description of Interface.
enabled: enabled:
description: description:
- Interface link status. - Configure interface link status.
speed: speed:
description: description:
- Interface link speed. - Interface link speed.
@ -59,8 +59,8 @@ options:
default: no default: no
state: state:
description: description:
- State of the Interface configuration, C(up) means present and - State of the Interface configuration, C(up) indicates present and
operationally up and C(down) means present and operationally C(down) operationally up and C(down) indicates present and operationally C(down)
default: present default: present
choices: ['present', 'absent', 'up', 'down'] choices: ['present', 'absent', 'up', 'down']
""" """
@ -80,13 +80,13 @@ EXAMPLES = """
net_interface: net_interface:
name: ge-0/0/1 name: ge-0/0/1
description: test-interface description: test-interface
state: up enabled: True
- name: make interface down - name: make interface down
net_interface: net_interface:
name: ge-0/0/1 name: ge-0/0/1
description: test-interface description: test-interface
state: down enabled: False
""" """
RETURN = """ RETURN = """

View file

@ -32,7 +32,7 @@ options:
- Description of Interface. - Description of Interface.
enabled: enabled:
description: description:
- Interface link status. - Configure interface link status.
speed: speed:
description: description:
- Interface link speed. - Interface link speed.
@ -46,21 +46,21 @@ options:
choices: ['full', 'half', 'auto'] choices: ['full', 'half', 'auto']
tx_rate: tx_rate:
description: description:
- Transmit rate. - Transmit rate in bits per second (bps).
rx_rate: rx_rate:
description: description:
- Receiver rate. - Receiver rate in bits per second (bps).
delay:
description:
- Time in seconds to wait before checking for the operational state on remote
device. This wait is applicable for operational state argument which are
I(state) with values C(up)/C(down), I(tx_rate) and I(rx_rate).
aggregate: aggregate:
description: List of Interfaces definitions. description: List of Interfaces definitions.
purge:
description:
- Purge Interfaces not defined in the aggregate parameter.
This applies only for logical interface.
default: no
state: state:
description: description:
- State of the Interface configuration, C(up) means present and - State of the Interface configuration, C(up) idicates present and
operationally up and C(down) means present and operationally C(down) operationally up and C(down) indicates present and operationally C(down)
default: present default: present
choices: ['present', 'absent', 'up', 'down'] choices: ['present', 'absent', 'up', 'down']
active: active:
@ -89,12 +89,12 @@ EXAMPLES = """
- name: make interface down - name: make interface down
junos_interface: junos_interface:
name: ge-0/0/1 name: ge-0/0/1
state: down enabled: False
- name: make interface up - name: make interface up
junos_interface: junos_interface:
name: ge-0/0/1 name: ge-0/0/1
state: up enabled: True
- name: Deactivate interface config - name: Deactivate interface config
junos_interface: junos_interface:
@ -127,6 +127,19 @@ EXAMPLES = """
aggregate: aggregate:
- { name: ge-0/0/1, description: test-interface-1, state: absent} - { name: ge-0/0/1, description: test-interface-1, state: absent}
- { name: ge-0/0/2, description: test-interface-2, state: absent} - { name: ge-0/0/2, description: test-interface-2, state: absent}
- name: Check intent arguments
junos_interface:
name: "{{ name }}"
state: up
tx_rate: ge(0)
rx_rate: le(0)
- name: Config + intent
junos_interface:
name: "{{ name }}"
enabled: False
state: down
""" """
RETURN = """ RETURN = """
@ -142,15 +155,19 @@ diff.prepared:
""" """
import collections import collections
from time import sleep
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.netconf import send_request
from ansible.module_utils.network_common import conditional
from ansible.module_utils.junos import junos_argument_spec, check_args 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
from ansible.module_utils.junos import commit_configuration, discard_changes, locked_config, to_param_list from ansible.module_utils.junos import commit_configuration, discard_changes, locked_config, to_param_list
try: try:
from lxml.etree import tostring from lxml.etree import Element, SubElement, tostring
except ImportError: except ImportError:
from xml.etree.ElementTree import tostring from xml.etree.ElementTree import Element, SubElement, tostring
USE_PERSISTENT_CONNECTION = True USE_PERSISTENT_CONNECTION = True
@ -176,12 +193,13 @@ def main():
element_spec = dict( element_spec = dict(
name=dict(), name=dict(),
description=dict(), description=dict(),
enabled=dict(), enabled=dict(default=True, type='bool'),
speed=dict(), speed=dict(),
mtu=dict(type='int'), mtu=dict(type='int'),
duplex=dict(choices=['full', 'half', 'auto']), duplex=dict(choices=['full', 'half', 'auto']),
tx_rate=dict(), tx_rate=dict(),
rx_rate=dict(), rx_rate=dict(),
delay=dict(default=10, type='int'),
state=dict(default='present', state=dict(default='present',
choices=['present', 'absent', 'up', 'down']), choices=['present', 'absent', 'up', 'down']),
active=dict(default=True, type='bool') active=dict(default=True, type='bool')
@ -192,7 +210,6 @@ def main():
argument_spec = dict( argument_spec = dict(
aggregate=dict(type='list', elements='dict', options=aggregate_spec), aggregate=dict(type='list', elements='dict', options=aggregate_spec),
purge=dict(default=False, type='bool')
) )
argument_spec.update(element_spec) argument_spec.update(element_spec)
@ -238,12 +255,10 @@ def main():
for param in params: for param in params:
item = param.copy() item = param.copy()
state = item.get('state') state = item.get('state')
item['disable'] = True if state == 'down' else False item['disable'] = True if not item.get('enabled') else False
if state in ('present', 'up', 'down'): if state in ('present', 'up', 'down'):
item['state'] = 'present' item['state'] = 'present'
else:
item['disable'] = True
validate_param_values(module, param_to_xpath_map, param=item) validate_param_values(module, param_to_xpath_map, param=item)
want = map_params_to_obj(module, param_to_xpath_map, param=item) want = map_params_to_obj(module, param_to_xpath_map, param=item)
@ -252,7 +267,7 @@ def main():
diff = None diff = None
with locked_config(module): with locked_config(module):
for req in requests: for req in requests:
diff = load_config(module, tostring(req), warnings, action='replace') diff = load_config(module, tostring(req), warnings, action='merge')
# issue commit after last configuration change is done # issue commit after last configuration change is done
commit = not module.check_mode commit = not module.check_mode
@ -266,6 +281,43 @@ def main():
if module._diff: if module._diff:
result['diff'] = {'prepared': diff} result['diff'] = {'prepared': diff}
failed_conditions = []
for item in params:
state = item.get('state')
tx_rate = item.get('tx_rate')
rx_rate = item.get('rx_rate')
if state not in ('up', 'down') and tx_rate is None and rx_rate is None:
continue
element = Element('get-interface-information')
intf_name = SubElement(element, 'interface-name')
intf_name.text = item.get('name')
if result['changed']:
sleep(item.get('delay'))
reply = send_request(module, element, ignore_warning=False)
if state in ('up', 'down'):
admin_status = reply.xpath('interface-information/physical-interface/admin-status')
if not admin_status or not conditional(state, admin_status[0].text.strip()):
failed_conditions.append('state ' + 'eq(%s)' % state)
if tx_rate:
output_bps = reply.xpath('interface-information/physical-interface/traffic-statistics/output-bps')
if not output_bps or not conditional(tx_rate, output_bps[0].text.strip(), cast=int):
failed_conditions.append('tx_rate ' + tx_rate)
if rx_rate:
input_bps = reply.xpath('interface-information/physical-interface/traffic-statistics/input-bps')
if not input_bps or not conditional(rx_rate, input_bps[0].text.strip(), cast=int):
failed_conditions.append('rx_rate ' + rx_rate)
if failed_conditions:
msg = 'One or more conditional statements have not be satisfied'
module.fail_json(msg=msg, failed_conditions=failed_conditions)
module.exit_json(**result) module.exit_json(**result)
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -111,7 +111,7 @@
junos_interface: junos_interface:
name: ge-0/0/1 name: ge-0/0/1
description: test-interface description: test-interface
state: down enabled: False
provider: "{{ netconf }}" provider: "{{ netconf }}"
register: result register: result
@ -124,7 +124,7 @@
junos_interface: junos_interface:
name: ge-0/0/1 name: ge-0/0/1
description: test-interface description: test-interface
state: up enabled: True
provider: "{{ netconf }}" provider: "{{ netconf }}"
register: result register: result
@ -202,8 +202,8 @@
- name: Disable interface on aggregate - name: Disable interface on aggregate
junos_interface: junos_interface:
aggregate: aggregate:
- { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: full, mtu: 512, state: down} - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: full, mtu: 512, enabled: False}
- { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, state: down} - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, enabled: False}
provider: "{{ netconf }}" provider: "{{ netconf }}"
register: result register: result
@ -215,8 +215,8 @@
- name: Enable interface on aggregate - name: Enable interface on aggregate
junos_interface: junos_interface:
aggregate: aggregate:
- { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: full, mtu: 512, state: up} - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: full, mtu: 512, enabled: True}
- { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, state: up} - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, enabled: True}
provider: "{{ netconf }}" provider: "{{ netconf }}"
register: result register: result

View file

@ -0,0 +1,89 @@
---
- debug: msg="START junos_interface netconf/intent.yaml"
- name: get facts
junos_facts:
provider: "{{ netconf }}"
register: result
- name: Define interface name for vSRX
set_fact:
name: pp0
when: result['ansible_facts']['ansible_net_model'] | search("vSRX*")
- name: Define interface name for vQFX
set_fact:
name: gr-0/0/0
when: result['ansible_facts']['ansible_net_model'] | search("vqfx*")
- name: Check intent arguments
junos_interface:
name: "{{ name }}"
state: up
tx_rate: ge(0)
rx_rate: le(0)
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.failed == false"
- name: Check intent arguments (failed condition)
junos_interface:
name: "{{ name }}"
state: down
tx_rate: gt(0)
rx_rate: lt(0)
provider: "{{ netconf }}"
ignore_errors: yes
register: result
- assert:
that:
- "result.failed == true"
- "'state eq(down)' in result.failed_conditions"
- "'tx_rate gt(0)' in result.failed_conditions"
- "'rx_rate lt(0)' in result.failed_conditions"
- name: Config + intent
junos_interface:
name: "{{ name }}"
enabled: False
state: down
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.failed == false"
- result.diff.prepared | search("\+ *disable")
- name: Config + intent (fail)
junos_interface:
name: "{{ name }}"
enabled: False
state: up
provider: "{{ netconf }}"
ignore_errors: yes
register: result
- assert:
that:
- "result.failed == true"
- "'state eq(up)' in result.failed_conditions"
- name: Aggregate config + intent (pass)
junos_interface:
aggregate:
- name: "{{ name }}"
enabled: True
state: up
provider: "{{ netconf }}"
ignore_errors: yes
register: result
- assert:
that:
- "result.failed == false"

View file

@ -70,7 +70,7 @@
net_interface: net_interface:
name: ge-0/0/1 name: ge-0/0/1
description: test-interface description: test-interface
state: down enabled: False
provider: "{{ netconf }}" provider: "{{ netconf }}"
register: result register: result
@ -90,7 +90,7 @@
net_interface: net_interface:
name: ge-0/0/1 name: ge-0/0/1
description: test-interface description: test-interface
state: up enabled: True
provider: "{{ netconf }}" provider: "{{ netconf }}"
register: result register: result
@ -175,8 +175,8 @@
- name: Disable interface on aggregate - name: Disable interface on aggregate
net_interface: net_interface:
aggregate: aggregate:
- { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: full, mtu: 512, state: down} - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: full, mtu: 512, enabled: False}
- { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, state: down} - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, enabled: False}
provider: "{{ netconf }}" provider: "{{ netconf }}"
register: result register: result
@ -188,8 +188,8 @@
- name: Enable interface on aggregate - name: Enable interface on aggregate
net_interface: net_interface:
aggregate: aggregate:
- { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: full, mtu: 512, state: up} - { name: ge-0/0/1, description: test-interface-1, speed: 1g, duplex: full, mtu: 512, enabled: True}
- { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, state: up} - { name: ge-0/0/2, description: test-interface-2, speed: 10m, duplex: full, mtu: 256, enabled: True}
provider: "{{ netconf }}" provider: "{{ netconf }}"
register: result register: result

View file

@ -0,0 +1,89 @@
---
- debug: msg="START net_interface junos/intent.yaml"
- name: get facts
junos_facts:
provider: "{{ netconf }}"
register: result
- name: Define interface name for vSRX
set_fact:
name: pp0
when: result['ansible_facts']['ansible_net_model'] | search("vSRX*")
- name: Define interface name for vQFX
set_fact:
name: gr-0/0/0
when: result['ansible_facts']['ansible_net_model'] | search("vqfx*")
- name: Check intent arguments
net_interface:
name: "{{ name }}"
state: up
tx_rate: ge(0)
rx_rate: le(0)
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.failed == false"
- name: Check intent arguments (failed condition)
net_interface:
name: "{{ name }}"
state: down
tx_rate: gt(0)
rx_rate: lt(0)
provider: "{{ netconf }}"
ignore_errors: yes
register: result
- assert:
that:
- "result.failed == true"
- "'state eq(down)' in result.failed_conditions"
- "'tx_rate gt(0)' in result.failed_conditions"
- "'rx_rate lt(0)' in result.failed_conditions"
- name: Config + intent
net_interface:
name: "{{ name }}"
enabled: False
state: down
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.failed == false"
- result.diff.prepared | search("\+ *disable")
- name: Config + intent (fail)
net_interface:
name: "{{ name }}"
enabled: False
state: up
provider: "{{ netconf }}"
ignore_errors: yes
register: result
- assert:
that:
- "result.failed == true"
- "'state eq(up)' in result.failed_conditions"
- name: Aggregate config + intent (pass)
net_interface:
aggregate:
- name: "{{ name }}"
enabled: True
state: up
provider: "{{ netconf }}"
ignore_errors: yes
register: result
- assert:
that:
- "result.failed == false"