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

View file

@ -32,7 +32,7 @@ options:
- Description of Interface.
enabled:
description:
- Interface link status.
- Configure interface link status.
speed:
description:
- Interface link speed.
@ -46,21 +46,21 @@ options:
choices: ['full', 'half', 'auto']
tx_rate:
description:
- Transmit rate.
- Transmit rate in bits per second (bps).
rx_rate:
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:
description: List of Interfaces definitions.
purge:
description:
- Purge Interfaces not defined in the aggregate parameter.
This applies only for logical interface.
default: no
state:
description:
- State of the Interface configuration, C(up) means present and
operationally up and C(down) means present and operationally C(down)
- State of the Interface configuration, C(up) idicates present and
operationally up and C(down) indicates present and operationally C(down)
default: present
choices: ['present', 'absent', 'up', 'down']
active:
@ -89,12 +89,12 @@ EXAMPLES = """
- name: make interface down
junos_interface:
name: ge-0/0/1
state: down
enabled: False
- name: make interface up
junos_interface:
name: ge-0/0/1
state: up
enabled: True
- name: Deactivate interface config
junos_interface:
@ -127,6 +127,19 @@ EXAMPLES = """
aggregate:
- { name: ge-0/0/1, description: test-interface-1, 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 = """
@ -142,15 +155,19 @@ diff.prepared:
"""
import collections
from time import sleep
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 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
try:
from lxml.etree import tostring
from lxml.etree import Element, SubElement, tostring
except ImportError:
from xml.etree.ElementTree import tostring
from xml.etree.ElementTree import Element, SubElement, tostring
USE_PERSISTENT_CONNECTION = True
@ -176,12 +193,13 @@ def main():
element_spec = dict(
name=dict(),
description=dict(),
enabled=dict(),
enabled=dict(default=True, type='bool'),
speed=dict(),
mtu=dict(type='int'),
duplex=dict(choices=['full', 'half', 'auto']),
tx_rate=dict(),
rx_rate=dict(),
delay=dict(default=10, type='int'),
state=dict(default='present',
choices=['present', 'absent', 'up', 'down']),
active=dict(default=True, type='bool')
@ -192,7 +210,6 @@ def main():
argument_spec = dict(
aggregate=dict(type='list', elements='dict', options=aggregate_spec),
purge=dict(default=False, type='bool')
)
argument_spec.update(element_spec)
@ -238,12 +255,10 @@ def main():
for param in params:
item = param.copy()
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'):
item['state'] = 'present'
else:
item['disable'] = True
validate_param_values(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
with locked_config(module):
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
commit = not module.check_mode
@ -266,6 +281,43 @@ def main():
if module._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)
if __name__ == "__main__":

View file

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