Migrated to junipernetworks.junos

pull/68298/head
Ansible Core Team 5 years ago committed by Matt Martz
parent 0c8d6f0805
commit 35063de590

@ -1,22 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The arg spec for the junos facts module.
"""
class FactsArgs(object):
""" The arg spec for the junos facts module
"""
def __init__(self, **kwargs):
pass
argument_spec = {
'gather_subset': dict(default=['!config'], type='list'),
'config_format': dict(default='text', choices=['xml', 'text', 'set', 'json']),
'gather_network_resources': dict(type='list'),
}

@ -1,56 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The arg spec for the junos_interfaces module
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class InterfacesArgs(object):
"""The arg spec for the junos_interfaces module
"""
def __init__(self, **kwargs):
pass
argument_spec = {'config': {'elements': 'dict',
'options': {'description': {'type': 'str'},
'duplex': {'choices': ['automatic',
'full-duplex',
'half-duplex'],
'type': 'str'},
'enabled': {'default': True, 'type': 'bool'},
'hold_time': {'options': {'down': {'type': 'int'},
'up': {'type': 'int'}},
'required_together': [['down', 'up']],
'type': 'dict'},
'mtu': {'type': 'int'},
'name': {'required': True, 'type': 'str'},
'speed': {'type': 'str'}},
'type': 'list'},
'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
'default': 'merged',
'type': 'str'}}

@ -1,49 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The arg spec for the junos_l2_interfaces module
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class L2_interfacesArgs(object):
"""The arg spec for the junos_l2_interfaces module
"""
def __init__(self, **kwargs):
pass
argument_spec = {'config': {'elements': 'dict',
'options': {'access': {'type': 'dict', 'options': {'vlan': {'type': 'str'}}},
'name': {'required': True, 'type': 'str'},
'trunk': {'type': 'dict', 'options': {'allowed_vlans': {'type': 'list'},
'native_vlan': {'type': 'str'}}},
'unit': {'type': 'int'},
'enhanced_layer': {'type': 'bool'}},
'type': 'list'},
'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
'default': 'merged',
'type': 'str'}}

@ -1,37 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The arg spec for the junos_l3_interfaces module
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class L3_interfacesArgs(object): # pylint: disable=R0903
"""The arg spec for the junos_l3_interfaces module
"""
def __init__(self, **kwargs):
pass
argument_spec = {'config': {'elements': 'dict', 'options':
{
'ipv4': {'elements': 'dict',
'options':
{'address': {'type': 'str'}},
'type': 'list'},
'ipv6': {'elements': 'dict',
'options':
{'address': {'type': 'str'}},
'type': 'list'},
'name': {'required': True, 'type': 'str'},
'unit': {'type': 'int', 'default': 0}
},
'type': 'list'},
'state': {'choices':
['merged', 'replaced', 'overridden', 'deleted'],
'default': 'merged',
'type': 'str'}} # pylint: disable=C0301

@ -1,47 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The arg spec for the junos_lacp module
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class LacpArgs(object):
"""The arg spec for the junos_lacp module
"""
def __init__(self, **kwargs):
pass
argument_spec = {'config': {'type': 'dict',
'options': {'link_protection': {'choices': ['revertive',
'non-revertive'],
'type': 'str'},
'system_priority': {'type': 'int'}},
},
'state': {'choices': ['merged', 'replaced', 'deleted'],
'default': 'merged',
'type': 'str'}}

@ -1,53 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The arg spec for the junos_lacp_interfaces module
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class Lacp_interfacesArgs(object):
"""The arg spec for the junos_lacp_interfaces module
"""
def __init__(self, **kwargs):
pass
argument_spec = {'config': {'elements': 'dict',
'options': {'force_up': {'type': 'bool'},
'name': {'type': 'str'},
'period': {'choices': ['fast', 'slow']},
'port_priority': {'type': 'int'},
'sync_reset': {'choices': ['disable', 'enable'],
'type': 'str'},
'system': {'options': {'mac': {'type': 'dict',
'options': {'address': {'type': 'str'}}},
'priority': {'type': 'int'}},
'type': 'dict'}},
'type': 'list'},
'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
'default': 'merged',
'type': 'str'}}

@ -1,51 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The arg spec for the junos_lag_interfaces module
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class Lag_interfacesArgs(object):
"""The arg spec for the junos_lag_interfaces module
"""
def __init__(self, **kwargs):
pass
argument_spec = {'config': {'elements': 'dict',
'options': {'members': {'elements': 'dict',
'options': {'link_type': {'choices': ['primary',
'backup']},
'member': {'type': 'str'}},
'type': 'list'},
'mode': {'choices': ['active', 'passive']},
'name': {'required': True, 'type': 'str'},
'link_protection': {'type': 'bool'}},
'type': 'list'},
'state': {'choices': ['merged', 'replaced', 'overridden', 'deleted'],
'default': 'merged',
'type': 'str'}}

@ -1,47 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The arg spec for the junos_lldp module
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class Lldp_globalArgs(object):
"""The arg spec for the junos_lldp module
"""
def __init__(self, **kwargs):
pass
argument_spec = {'config': {'options': {'address': {'type': 'str'},
'enabled': {'type': 'bool'},
'hold_multiplier': {'type': 'int'},
'interval': {'type': 'int'},
'transmit_delay': {'type': 'int'}},
'type': 'dict'},
'state': {'choices': ['merged', 'replaced', 'deleted'],
'default': 'merged',
'type': 'str'}}

@ -1,45 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The arg spec for the junos_lldp_interfaces module
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class Lldp_interfacesArgs(object):
"""The arg spec for the junos_lldp_interfaces module
"""
def __init__(self, **kwargs):
pass
argument_spec = {'config': {'elements': 'dict',
'options': {'enabled': {'type': 'bool'},
'name': {'required': True, 'type': 'str'}},
'type': 'list'},
'state': {'choices': ['merged', 'replaced', 'deleted', 'overridden'],
'default': 'merged',
'type': 'str'}}

@ -1,73 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The arg spec for the junos_static_routes module
"""
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
class Static_routesArgs(object): # pylint: disable=R0903
"""The arg spec for the junos_static_routes module
"""
def __init__(self, **kwargs):
pass
argument_spec = {
'config': {
'elements': 'dict',
'options': {
'address_families': {
'elements': 'dict',
'options': {
'afi': {
'choices': ['ipv4', 'ipv6'],
'required': True,
'type': 'str'},
'routes': {'elements': 'dict',
'options': {
'dest': {
'type': 'str'},
'metric': {
'type': 'int'},
'next_hop': {
'elements': 'dict',
'options': {
'forward_router_address': {
'type': 'str'}},
'type': 'list'}},
'type': 'list'}},
'type': 'list'},
'vrf': {
'type': 'str'}},
'type': 'list'},
'state': {
'choices': ['merged',
'replaced',
'overridden',
'deleted'],
'default': 'merged',
'type': 'str'}} # pylint: disable=C0301

@ -1,49 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The arg spec for the junos_vlans module
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class VlansArgs(object): # pylint: disable=R0903
"""The arg spec for the junos_vlans module
"""
def __init__(self, **kwargs):
pass
argument_spec = {'config': {'elements': 'dict',
'options': {
'description': {},
'name': {'required': True, 'type': 'str'},
'vlan_id': {'type': 'int'}},
'type': 'list'},
'state': {
'choices': ['merged', 'replaced', 'overridden',
'deleted'],
'default': 'merged',
'type': 'str'}} # pylint: disable=C0301

@ -1,238 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos_interfaces class
It is in this file where the current configuration (as dict)
is compared to the provided configuration (as dict) and the command set
necessary to bring the current configuration to it's desired end-state is
created
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.junos.junos import locked_config, load_config, commit_configuration, discard_changes, tostring
from ansible.module_utils.network.junos.facts.facts import Facts
from ansible.module_utils.network.common.netconf import build_root_xml_node, build_child_xml_node
class Interfaces(ConfigBase):
"""
The junos_interfaces class
"""
gather_subset = [
'!all',
'!min',
]
gather_network_resources = [
'interfaces',
]
def __init__(self, module):
super(Interfaces, self).__init__(module)
def get_interfaces_facts(self):
""" Get the 'facts' (the current configuration)
:rtype: A dictionary
:returns: The current configuration as a dictionary
"""
facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
interfaces_facts = facts['ansible_network_resources'].get('interfaces')
if not interfaces_facts:
return []
return interfaces_facts
def execute_module(self):
""" Execute the module
:rtype: A dictionary
:returns: The result from module execution
"""
result = {'changed': False}
existing_interfaces_facts = self.get_interfaces_facts()
config_xmls = self.set_config(existing_interfaces_facts)
with locked_config(self._module):
for config_xml in to_list(config_xmls):
diff = load_config(self._module, config_xml, [])
commit = not self._module.check_mode
if diff:
if commit:
commit_configuration(self._module)
else:
discard_changes(self._module)
result['changed'] = True
if self._module._diff:
result['diff'] = {'prepared': diff}
result['commands'] = config_xmls
changed_interfaces_facts = self.get_interfaces_facts()
result['before'] = existing_interfaces_facts
if result['changed']:
result['after'] = changed_interfaces_facts
return result
def set_config(self, existing_interfaces_facts):
""" Collect the configuration from the args passed to the module,
collect the current configuration (as a dict from facts)
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
want = self._module.params['config']
have = existing_interfaces_facts
resp = self.set_state(want, have)
return to_list(resp)
def set_state(self, want, have):
""" Select the appropriate function based on the state provided
:param want: the desired configuration as a dictionary
:param have: the current configuration as a dictionary
:rtype: A list
:returns: the list xml configuration necessary to migrate the current configuration
to the desired configuration
"""
root = build_root_xml_node('interfaces')
state = self._module.params['state']
if state == 'overridden':
config_xmls = self._state_overridden(want, have)
elif state == 'deleted':
config_xmls = self._state_deleted(want, have)
elif state == 'merged':
config_xmls = self._state_merged(want, have)
elif state == 'replaced':
config_xmls = self._state_replaced(want, have)
for xml in config_xmls:
root.append(xml)
return tostring(root)
def _state_replaced(self, want, have):
""" The xml configuration generator when state is replaced
:rtype: A list
:returns: the xml configuration necessary to migrate the current configuration
to the desired configuration
"""
intf_xml = []
intf_xml.extend(self._state_deleted(want, have))
intf_xml.extend(self._state_merged(want, have))
return intf_xml
def _state_overridden(self, want, have):
""" The xml configuration generator when state is overridden
:rtype: A list
:returns: the xml configuration necessary to migrate the current configuration
to the desired configuration
"""
interface_xmls_obj = []
# replace interface config with data in want
interface_xmls_obj.extend(self._state_replaced(want, have))
# delete interface config if interface in have not present in want
delete_obj = []
for have_obj in have:
for want_obj in want:
if have_obj['name'] == want_obj['name']:
break
else:
delete_obj.append(have_obj)
if delete_obj:
interface_xmls_obj.extend(self._state_deleted(delete_obj, have))
return interface_xmls_obj
def _state_merged(self, want, have):
""" The xml configuration generator when state is merged
:rtype: A list
:returns: the xml configuration necessary to merge the provided into
the current configuration
"""
intf_xml = []
for config in want:
intf = build_root_xml_node('interface')
build_child_xml_node(intf, 'name', config['name'])
intf_fields = ['description', 'speed']
if not config['name'].startswith('fxp'):
intf_fields.append('mtu')
for field in intf_fields:
if config.get(field):
build_child_xml_node(intf, field, config[field])
if config.get('duplex'):
build_child_xml_node(intf, 'link-mode', config['duplex'])
if config.get('enabled') is False:
build_child_xml_node(intf, 'disable')
holdtime = config.get('hold_time')
if holdtime:
holdtime_ele = build_child_xml_node(intf, 'hold-time')
for holdtime_field in ['up', 'down']:
build_child_xml_node(holdtime_ele, holdtime_field, holdtime.get(holdtime_field, ''))
intf_xml.append(intf)
return intf_xml
def _state_deleted(self, want, have):
""" The xml configuration generator when state is deleted
:rtype: A list
:returns: the xml configuration necessary to remove the current configuration
of the provided objects
"""
intf_xml = []
intf_obj = want
if not intf_obj:
# delete base interfaces attribute from all the existing interface
intf_obj = have
for config in intf_obj:
intf = build_root_xml_node('interface')
build_child_xml_node(intf, 'name', config['name'])
intf_fields = ['description']
if not config['name'].startswith('lo'):
intf_fields.append('speed')
if not any([config['name'].startswith('fxp'), config['name'].startswith('lo')]):
intf_fields.append('mtu')
for field in intf_fields:
build_child_xml_node(intf, field, None, {'delete': 'delete'})
if not config['name'].startswith('lo'):
build_child_xml_node(intf, 'link-mode', None, {'delete': 'delete'})
build_child_xml_node(intf, 'disable', None, {'delete': 'delete'})
holdtime_ele = build_child_xml_node(intf, 'hold-time')
for holdtime_field in ['up', 'down']:
build_child_xml_node(holdtime_ele, holdtime_field, None, {'delete': 'delete'})
intf_xml.append(intf)
return intf_xml

@ -1,256 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos_l2_interfaces class
It is in this file where the current configuration (as dict)
is compared to the provided configuration (as dict) and the command set
necessary to bring the current configuration to it's desired end-state is
created
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.junos.junos import locked_config, load_config, commit_configuration, discard_changes, tostring
from ansible.module_utils.network.junos.facts.facts import Facts
from ansible.module_utils.network.junos.utils.utils import get_resource_config
from ansible.module_utils.network.common.netconf import build_root_xml_node, build_child_xml_node, build_subtree
class L2_interfaces(ConfigBase):
"""
The junos_l2_interfaces class
"""
gather_subset = [
'!all',
'!min',
]
gather_network_resources = [
'l2_interfaces',
]
def __init__(self, module):
super(L2_interfaces, self).__init__(module)
def get_l2_interfaces_facts(self):
""" Get the 'facts' (the current configuration)
:rtype: A dictionary
:returns: The current configuration as a dictionary
"""
facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
l2_interfaces_facts = facts['ansible_network_resources'].get('l2_interfaces')
if not l2_interfaces_facts:
return []
return l2_interfaces_facts
def execute_module(self):
""" Execute the module
:rtype: A dictionary
:returns: The result from module execution
"""
result = {'changed': False}
existing_l2_interfaces_facts = self.get_l2_interfaces_facts()
config_xmls = self.set_config(existing_l2_interfaces_facts)
with locked_config(self._module):
for config_xml in to_list(config_xmls):
diff = load_config(self._module, config_xml, [])
commit = not self._module.check_mode
if diff:
if commit:
commit_configuration(self._module)
else:
discard_changes(self._module)
result['changed'] = True
if self._module._diff:
result['diff'] = {'prepared': diff}
result['commands'] = config_xmls
changed_l2_interfaces_facts = self.get_l2_interfaces_facts()
result['before'] = existing_l2_interfaces_facts
if result['changed']:
result['after'] = changed_l2_interfaces_facts
return result
def set_config(self, existing_l2_interfaces_facts):
""" Collect the configuration from the args passed to the module,
collect the current configuration (as a dict from facts)
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
want = self._module.params['config']
have = existing_l2_interfaces_facts
resp = self.set_state(want, have)
return to_list(resp)
def set_state(self, want, have):
""" Select the appropriate function based on the state provided
:param want: the desired configuration as a dictionary
:param have: the current configuration as a dictionary
:rtype: A list
:returns: the list xml configuration necessary to migrate the current configuration
to the desired configuration
"""
root = build_root_xml_node('interfaces')
state = self._module.params['state']
if state == 'overridden':
config_xmls = self._state_overridden(want, have)
elif state == 'deleted':
config_xmls = self._state_deleted(want, have)
elif state == 'merged':
config_xmls = self._state_merged(want, have)
elif state == 'replaced':
config_xmls = self._state_replaced(want, have)
for xml in config_xmls:
root.append(xml)
return tostring(root)
def _state_replaced(self, want, have):
""" The xml configuration generator when state is replaced
:rtype: A list
:returns: the xml configuration necessary to migrate the current configuration
to the desired configuration
"""
l2_intf_xml = []
l2_intf_xml.extend(self._state_deleted(want, have))
l2_intf_xml.extend(self._state_merged(want, have))
return l2_intf_xml
def _state_overridden(self, want, have):
""" The xml configuration generator when state is overridden
:rtype: A list
:returns: the xml configuration necessary to migrate the current configuration
to the desired configuration
"""
l2_interface_xmls_obj = []
# replace interface config with data in want
l2_interface_xmls_obj.extend(self._state_replaced(want, have))
# delete interface config if interface in have not present in want
delete_obj = []
for have_obj in have:
for want_obj in want:
if have_obj['name'] == want_obj['name']:
break
else:
delete_obj.append(have_obj)
if delete_obj:
l2_interface_xmls_obj.extend(self._state_deleted(delete_obj, have))
return l2_interface_xmls_obj
def _state_merged(self, want, have):
""" The xml configuration generator when state is merged
:rtype: A list
:returns: the xml configuration necessary to merge the provided into
the current configuration
"""
intf_xml = []
for config in want:
enhanced_layer = True
if config.get('enhanced_layer') is False:
enhanced_layer = False
mode = 'interface-mode' if enhanced_layer else 'port-mode'
intf = build_root_xml_node('interface')
build_child_xml_node(intf, 'name', config['name'])
unit_node = build_child_xml_node(intf, 'unit')
unit = config['unit'] if config['unit'] else '0'
build_child_xml_node(unit_node, 'name', unit)
eth_node = build_subtree(unit_node, 'family/ethernet-switching')
if config.get('access'):
vlan = config['access'].get('vlan')
if vlan:
build_child_xml_node(eth_node, mode, 'access')
vlan_node = build_child_xml_node(eth_node, 'vlan')
build_child_xml_node(vlan_node, 'members', vlan)
intf_xml.append(intf)
elif config.get('trunk'):
allowed_vlans = config['trunk'].get('allowed_vlans')
native_vlan = config['trunk'].get('native_vlan')
if allowed_vlans:
build_child_xml_node(eth_node, mode, 'trunk')
vlan_node = build_child_xml_node(eth_node, 'vlan')
for vlan in allowed_vlans:
build_child_xml_node(vlan_node, 'members', vlan)
if native_vlan:
build_child_xml_node(intf, 'native-vlan-id', native_vlan)
if allowed_vlans or native_vlan:
intf_xml.append(intf)
return intf_xml
def _state_deleted(self, want, have):
""" The xml configuration generator when state is deleted
:rtype: A list
:returns: the xml configuration necessary to remove the current configuration
of the provided objects
"""
l2_intf_xml = []
l2_intf_obj = want
config_filter = """
<configuration>
<interfaces/>
</configuration>
"""
data = get_resource_config(self._connection, config_filter=config_filter)
if not l2_intf_obj:
# delete l2 interfaces attribute from all the existing interface having l2 config
l2_intf_obj = have
for config in l2_intf_obj:
name = config['name']
enhanced_layer = True
l2_mode = data.xpath("configuration/interfaces/interface[name='%s']/unit/family/ethernet-switching/interface-mode" % name)
if not len(l2_mode):
l2_mode = data.xpath("configuration/interfaces/interface[name='%s']/unit/family/ethernet-switching/port-mode" % name)
enhanced_layer = False
if len(l2_mode):
mode = 'interface-mode' if enhanced_layer else 'port-mode'
intf = build_root_xml_node('interface')
build_child_xml_node(intf, 'name', name)
unit_node = build_child_xml_node(intf, 'unit')
unit = config['unit'] if config['unit'] else '0'
build_child_xml_node(unit_node, 'name', unit)
eth_node = build_subtree(unit_node, 'family/ethernet-switching')
build_child_xml_node(eth_node, mode, None, {'delete': 'delete'})
build_child_xml_node(eth_node, 'vlan', None, {'delete': 'delete'})
build_child_xml_node(intf, 'native-vlan-id', None, {'delete': 'delete'})
l2_intf_xml.append(intf)
return l2_intf_xml

@ -1,234 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos_l3_interfaces class
It is in this file where the current configuration (as dict)
is compared to the provided configuration (as dict) and the command set
necessary to bring the current configuration to it's desired end-state is
created
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.network.junos.facts.facts import Facts
from ansible.module_utils.network.junos.junos import (
locked_config, load_config, commit_configuration, discard_changes,
tostring)
from ansible.module_utils.network.common.netconf import (build_root_xml_node,
build_child_xml_node)
class L3_interfaces(ConfigBase):
"""
The junos_l3_interfaces class
"""
gather_subset = [
'!all',
'!min',
]
gather_network_resources = [
'l3_interfaces',
]
def __init__(self, module):
super(L3_interfaces, self).__init__(module)
def get_l3_interfaces_facts(self):
""" Get the 'facts' (the current configuration)
:rtype: A dictionary
:returns: The current configuration as a dictionary
"""
facts, _warnings = Facts(self._module).get_facts(
self.gather_subset, self.gather_network_resources)
l3_interfaces_facts = facts['ansible_network_resources'].get(
'l3_interfaces')
if not l3_interfaces_facts:
return []
return l3_interfaces_facts
def execute_module(self):
""" Execute the module
:rtype: A dictionary
:returns: The result from module execution
"""
result = {'changed': False}
warnings = list()
existing_interfaces_facts = self.get_l3_interfaces_facts()
config_xmls = self.set_config(existing_interfaces_facts)
with locked_config(self._module):
for config_xml in to_list(config_xmls):
diff = load_config(self._module, config_xml, warnings)
commit = not self._module.check_mode
if diff:
if commit:
commit_configuration(self._module)
else:
discard_changes(self._module)
result['changed'] = True
if self._module._diff:
result['diff'] = {'prepared': diff}
result['commands'] = config_xmls
changed_interfaces_facts = self.get_l3_interfaces_facts()
result['before'] = existing_interfaces_facts
if result['changed']:
result['after'] = changed_interfaces_facts
result['warnings'] = warnings
return result
def set_config(self, existing_l3_interfaces_facts):
""" Collect the configuration from the args passed to the module,
collect the current configuration (as a dict from facts)
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
want = self._module.params['config']
have = existing_l3_interfaces_facts
resp = self.set_state(want, have)
return to_list(resp)
def set_state(self, want, have):
""" Select the appropriate function based on the state provided
:param want: the desired configuration as a dictionary
:param have: the current configuration as a dictionary
:rtype: A list
:returns: the list xml configuration necessary to migrate the current
configuration
to the desired configuration
"""
root = build_root_xml_node('interfaces')
state = self._module.params['state']
if state == 'overridden':
config_xmls = self._state_overridden(want, have)
elif state == 'deleted':
config_xmls = self._state_deleted(want, have)
elif state == 'merged':
config_xmls = self._state_merged(want, have)
elif state == 'replaced':
config_xmls = self._state_replaced(want, have)
for xml in config_xmls:
root.append(xml)
return tostring(root)
def _get_common_xml_node(self, name):
root_node = build_root_xml_node('interface')
build_child_xml_node(root_node, 'name', name)
intf_unit_node = build_child_xml_node(root_node, 'unit')
return root_node, intf_unit_node
def _state_replaced(self, want, have):
""" The xml generator when state is replaced
:rtype: A list
:returns: the xml necessary to migrate the current configuration
to the desired configuration
"""
intf_xml = []
intf_xml.extend(self._state_deleted(want, have))
intf_xml.extend(self._state_merged(want, have))
return intf_xml
def _state_overridden(self, want, have):
""" The xml generator when state is overridden
:rtype: A list
:returns: the xml necessary to migrate the current configuration
to the desired configuration
"""
intf_xml = []
intf_xml.extend(self._state_deleted(have, have))
intf_xml.extend(self._state_merged(want, have))
return intf_xml
def _state_merged(self, want, have):
""" The xml generator when state is merged
:rtype: A list
:returns: the xml necessary to merge the provided into
the current configuration
"""
intf_xml = []
for config in want:
root_node, unit_node = self._get_common_xml_node(config['name'])
build_child_xml_node(unit_node, 'name',
str(config['unit']))
if config.get('ipv4'):
self.build_ipaddr_et(config, unit_node)
if config.get('ipv6'):
self.build_ipaddr_et(config, unit_node, protocol='ipv6')
intf_xml.append(root_node)
return intf_xml
def build_ipaddr_et(self, config, unit_node, protocol='ipv4',
delete=False):
family = build_child_xml_node(unit_node, 'family')
inet = 'inet'
if protocol == 'ipv6':
inet = 'inet6'
ip_protocol = build_child_xml_node(family, inet)
for ip_addr in config[protocol]:
if ip_addr['address'] == 'dhcp' and protocol == 'ipv4':
build_child_xml_node(ip_protocol, 'dhcp')
else:
ip_addresses = build_child_xml_node(
ip_protocol, 'address')
build_child_xml_node(
ip_addresses, 'name', ip_addr['address'])
def _state_deleted(self, want, have):
""" The xml configuration generator when state is deleted
:rtype: A list
:returns: the xml configuration necessary to remove the current
configuration of the provided objects
"""
intf_xml = []
existing_l3_intfs = [l3_intf['name'] for l3_intf in have]
if not want:
want = have
for config in want:
if config['name'] not in existing_l3_intfs:
continue
else:
root_node, unit_node = self._get_common_xml_node(
config['name'])
build_child_xml_node(unit_node, 'name',
str(config['unit']))
family = build_child_xml_node(unit_node, 'family')
ipv4 = build_child_xml_node(family, 'inet')
intf = next(
(intf for intf in have if intf['name'] == config['name']),
None)
if 'ipv4' in intf:
if 'dhcp' in [x['address'] for x in intf.get('ipv4') if intf.get('ipv4') is not None]:
build_child_xml_node(ipv4, 'dhcp', None, {'delete': 'delete'})
else:
build_child_xml_node(
ipv4, 'address', None, {'delete': 'delete'})
ipv6 = build_child_xml_node(family, 'inet6')
build_child_xml_node(ipv6, 'address', None, {'delete': 'delete'})
intf_xml.append(root_node)
return intf_xml

@ -1,185 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos_lacp class
It is in this file where the current configuration (as dict)
is compared to the provided configuration (as dict) and the command set
necessary to bring the current configuration to it's desired end-state is
created
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.common.netconf import build_root_xml_node, build_child_xml_node, build_subtree
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.network.junos.facts.facts import Facts
from ansible.module_utils.network.junos.junos import locked_config, load_config, commit_configuration, discard_changes, tostring
class Lacp(ConfigBase):
"""
The junos_lacp class
"""
gather_subset = [
'!all',
'!min',
]
gather_network_resources = [
'lacp',
]
def __init__(self, module):
super(Lacp, self).__init__(module)
def get_lacp_facts(self):
""" Get the 'facts' (the current configuration)
:rtype: A dictionary
:returns: The current configuration as a dictionary
"""
facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
lacp_facts = facts['ansible_network_resources'].get('lacp')
if not lacp_facts:
return {}
return lacp_facts
def execute_module(self):
""" Execute the module
:rtype: A dictionary
:returns: The result from module execution
"""
result = {'changed': False}
existing_lacp_facts = self.get_lacp_facts()
config_xmls = self.set_config(existing_lacp_facts)
with locked_config(self._module):
for config_xml in to_list(config_xmls):
diff = load_config(self._module, config_xml, [])
commit = not self._module.check_mode
if diff:
if commit:
commit_configuration(self._module)
else:
discard_changes(self._module)
result['changed'] = True
if self._module._diff:
result['diff'] = {'prepared': diff}
result['commands'] = config_xmls
changed_lacp_facts = self.get_lacp_facts()
result['before'] = existing_lacp_facts
if result['changed']:
result['after'] = changed_lacp_facts
return result
def set_config(self, existing_lacp_facts):
""" Collect the configuration from the args passed to the module,
collect the current configuration (as a dict from facts)
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
want = self._module.params['config']
have = existing_lacp_facts
resp = self.set_state(want, have)
return to_list(resp)
def set_state(self, want, have):
""" Select the appropriate function based on the state provided
:param want: the desired configuration as a dictionary
:param have: the current configuration as a dictionary
:rtype: A list
:returns: the list xml configuration necessary to migrate the current configuration
to the desired configuration
"""
root = build_root_xml_node('chassis')
ethernet_ele = build_subtree(root, 'aggregated-devices/ethernet')
state = self._module.params['state']
if state == 'overridden':
config_xmls = self._state_overridden(want, have)
elif state == 'deleted':
config_xmls = self._state_deleted(want, have)
elif state == 'merged':
config_xmls = self._state_merged(want, have)
elif state == 'replaced':
config_xmls = self._state_replaced(want, have)
for xml in config_xmls:
ethernet_ele.append(xml)
return tostring(root)
def _state_replaced(self, want, have):
""" The xml configuration generator when state is merged
:rtype: A list
:returns: the xml configuration necessary to merge the provided into
the current configuration
"""
lacp_xml = []
lacp_xml.extend(self._state_deleted(want, have))
lacp_xml.extend(self._state_merged(want, have))
return lacp_xml
def _state_overridden(self, want, have):
""" The command generator when state is overridden
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
lacp_xml = []
lacp_xml.extend(self._state_deleted(want, have))
lacp_xml.extend(self._state_merged(want, have))
return lacp_xml
def _state_merged(self, want, have):
""" Select the appropriate function based on the state provided
:param want: the desired configuration as a dictionary
:param have: the current configuration as a dictionary
:rtype: A list
:returns: the list xml configuration necessary to migrate the current configuration
to the desired configuration
"""
lacp_xml = []
lacp_root = build_root_xml_node('lacp')
build_child_xml_node(lacp_root, 'system-priority', want.get('system_priority'))
if want.get('link_protection') == 'non-revertive':
build_subtree(lacp_root, 'link-protection/non-revertive')
elif want.get('link_protection') == 'revertive':
link_root = build_child_xml_node(lacp_root, 'link-protection')
build_child_xml_node(link_root, 'non-revertive', None, {'delete': 'delete'})
lacp_xml.append(lacp_root)
return lacp_xml
def _state_deleted(self, want, have):
""" The command generator when state is deleted
:rtype: A list
:returns: the commands necessary to remove the current configuration
of the provided objects
"""
lacp_xml = []
lacp_root = build_root_xml_node('lacp')
build_child_xml_node(lacp_root, 'system-priority', None, {'delete': 'delete'})
element = build_child_xml_node(lacp_root, 'link-protection', None, {'delete': 'delete'})
build_child_xml_node(element, 'non-revertive', None, {'delete': 'delete'})
lacp_xml.append(lacp_root)
return lacp_xml

@ -1,227 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos_lacp_interfaces class
It is in this file where the current configuration (as dict)
is compared to the provided configuration (as dict) and the command set
necessary to bring the current configuration to it's desired end-state is
created
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.network.junos.facts.facts import Facts
from ansible.module_utils.network.junos.junos import locked_config, load_config, commit_configuration, discard_changes, tostring
from ansible.module_utils.network.common.netconf import build_root_xml_node, build_child_xml_node, build_subtree
class Lacp_interfaces(ConfigBase):
"""
The junos_lacp_interfaces class
"""
gather_subset = [
'!all',
'!min',
]
gather_network_resources = [
'lacp_interfaces',
]
def __init__(self, module):
super(Lacp_interfaces, self).__init__(module)
def get_lacp_interfaces_facts(self):
""" Get the 'facts' (the current configuration)
:rtype: A dictionary
:returns: The current configuration as a dictionary
"""
facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
lacp_interfaces_facts = facts['ansible_network_resources'].get('lacp_interfaces')
if not lacp_interfaces_facts:
return []
return lacp_interfaces_facts
def execute_module(self):
""" Execute the module
:rtype: A dictionary
:returns: The result from module execution
"""
result = {'changed': False}
existing_lacp_interfaces_facts = self.get_lacp_interfaces_facts()
config_xmls = self.set_config(existing_lacp_interfaces_facts)
with locked_config(self._module):
for config_xml in to_list(config_xmls):
diff = load_config(self._module, config_xml, [])
commit = not self._module.check_mode
if diff:
if commit:
commit_configuration(self._module)
else:
discard_changes(self._module)
result['changed'] = True
if self._module._diff:
result['diff'] = {'prepared': diff}
result['commands'] = config_xmls
changed_lacp_interfaces_facts = self.get_lacp_interfaces_facts()
result['before'] = existing_lacp_interfaces_facts
if result['changed']:
result['after'] = changed_lacp_interfaces_facts
return result
def set_config(self, existing_lacp_interfaces_facts):
""" Collect the configuration from the args passed to the module,
collect the current configuration (as a dict from facts)
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
want = self._module.params['config']
have = existing_lacp_interfaces_facts
resp = self.set_state(want, have)
return to_list(resp)
def set_state(self, want, have):
""" Select the appropriate function based on the state provided
:param want: the desired configuration as a dictionary
:param have: the current configuration as a dictionary
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
root = build_root_xml_node('interfaces')
state = self._module.params['state']
if state == 'overridden':
config_xmls = self._state_overridden(want, have)
elif state == 'deleted':
config_xmls = self._state_deleted(want, have)
elif state == 'merged':
config_xmls = self._state_merged(want, have)
elif state == 'replaced':
config_xmls = self._state_replaced(want, have)
for xml in config_xmls:
root.append(xml)
return tostring(root)
def _state_replaced(self, want, have):
""" The xml configuration generator when state is replaced
:rtype: A list
:returns: the xml configuration necessary to migrate the current configuration
to the desired configuration
"""
intf_xml = []
intf_xml.extend(self._state_deleted(want, have))
intf_xml.extend(self._state_merged(want, have))
return intf_xml
def _state_overridden(self, want, have):
""" The xml configuration generator when state is overridden
:rtype: A list
:returns: the xml configuration necessary to migrate the current configuration
to the desired configuration
"""
interface_xmls_obj = []
# replace interface config with data in want
interface_xmls_obj.extend(self._state_replaced(want, have))
# delete interface config if interface in have not present in want
delete_obj = []
for have_obj in have:
for want_obj in want:
if have_obj['name'] == want_obj['name']:
break
else:
delete_obj.append(have_obj)
if delete_obj:
interface_xmls_obj.extend(self._state_deleted(delete_obj, have))
return interface_xmls_obj
def _state_merged(self, want, have):
""" The xml configuration generator when state is merged
:rtype: A list
:returns: the xml configuration necessary to merge the provided into
the current configuration
"""
intf_xml = []
for config in want:
lacp_intf_name = config['name']
lacp_intf_root = build_root_xml_node('interface')
build_child_xml_node(lacp_intf_root, 'name', lacp_intf_name)
if lacp_intf_name.startswith('ae'):
element = build_subtree(lacp_intf_root, 'aggregated-ether-options/lacp')
if config['period']:
build_child_xml_node(element, 'periodic', config['period'])
if config['sync_reset']:
build_child_xml_node(element, 'sync-reset', config['sync_reset'])
system = config['system']
if system:
mac = system.get('mac')
if mac:
if mac.get('address'):
build_child_xml_node(element, 'system-id', mac['address'])
if system.get('priority'):
build_child_xml_node(element, 'system-priority', system['priority'])
intf_xml.append(lacp_intf_root)
elif config['port_priority'] or config['force_up'] is not None:
element = build_subtree(lacp_intf_root, 'ether-options/ieee-802.3ad/lacp')
build_child_xml_node(element, 'port-priority', config['port_priority'])
if config['force_up'] is False:
build_child_xml_node(element, 'force-up', None, {'delete': 'delete'})
else:
build_child_xml_node(element, 'force-up')
intf_xml.append(lacp_intf_root)
return intf_xml
def _state_deleted(self, want, have):
""" The xml configuration generator when state is deleted
:rtype: A list
:returns: the xml configuration necessary to remove the current configuration
of the provided objects
"""
intf_xml = []
intf_obj = want
if not intf_obj:
# delete lag interfaces attribute for all the interface
intf_obj = have
for config in intf_obj:
lacp_intf_name = config['name']
lacp_intf_root = build_root_xml_node('interface')
build_child_xml_node(lacp_intf_root, 'name', lacp_intf_name)
if lacp_intf_name.startswith('ae'):
element = build_subtree(lacp_intf_root, 'aggregated-ether-options/lacp')
build_child_xml_node(element, 'periodic', None, {'delete': 'delete'})
build_child_xml_node(element, 'sync-reset', None, {'delete': 'delete'})
build_child_xml_node(element, 'system-id', None, {'delete': 'delete'})
build_child_xml_node(element, 'system-priority', None, {'delete': 'delete'})
else:
element = build_subtree(lacp_intf_root, 'ether-options/ieee-802.3ad/lacp')
build_child_xml_node(element, 'port-priority', None, {'delete': 'delete'})
build_child_xml_node(element, 'force-up', None, {'delete': 'delete'})
intf_xml.append(lacp_intf_root)
return intf_xml

@ -1,253 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos_lag_interfaces class
It is in this file where the current configuration (as dict)
is compared to the provided configuration (as dict) and the command set
necessary to bring the current configuration to it's desired end-state is
created
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.network.junos.facts.facts import Facts
from ansible.module_utils.network.junos.junos import locked_config, load_config, commit_configuration, discard_changes, tostring
from ansible.module_utils.network.junos.utils.utils import get_resource_config
from ansible.module_utils.network.common.netconf import build_root_xml_node, build_child_xml_node, build_subtree
class Lag_interfaces(ConfigBase):
"""
The junos_lag_interfaces class
"""
gather_subset = [
'!all',
'!min',
]
gather_network_resources = [
'lag_interfaces',
]
def __init__(self, module):
super(Lag_interfaces, self).__init__(module)
def get_lag_interfaces_facts(self):
""" Get the 'facts' (the current configuration)
:rtype: A dictionary
:returns: The current configuration as a dictionary
"""
facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
lag_interfaces_facts = facts['ansible_network_resources'].get('lag_interfaces')
if not lag_interfaces_facts:
return []
return lag_interfaces_facts
def execute_module(self):
""" Execute the module
:rtype: A dictionary
:returns: The result from module execution
"""
result = {'changed': False}
warnings = list()
existing_lag_interfaces_facts = self.get_lag_interfaces_facts()
config_xmls = self.set_config(existing_lag_interfaces_facts)
with locked_config(self._module):
for config_xml in to_list(config_xmls):
diff = load_config(self._module, config_xml, warnings)
commit = not self._module.check_mode
if diff:
if commit:
commit_configuration(self._module)
else:
discard_changes(self._module)
result['changed'] = True
if self._module._diff:
result['diff'] = {'prepared': diff}
result['commands'] = config_xmls
changed_lag_interfaces_facts = self.get_lag_interfaces_facts()
result['before'] = existing_lag_interfaces_facts
if result['changed']:
result['after'] = changed_lag_interfaces_facts
return result
def set_config(self, existing_lag_interfaces_facts):
""" Collect the configuration from the args passed to the module,
collect the current configuration (as a dict from facts)
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
want = self._module.params['config']
have = existing_lag_interfaces_facts
resp = self.set_state(want, have)
return to_list(resp)
def set_state(self, want, have):
""" Select the appropriate function based on the state provided
:param want: the desired configuration as a dictionary
:param have: the current configuration as a dictionary
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
root = build_root_xml_node('interfaces')
state = self._module.params['state']
if state == 'overridden':
config_xmls = self._state_overridden(want, have)
elif state == 'deleted':
config_xmls = self._state_deleted(want, have)
elif state == 'merged':
config_xmls = self._state_merged(want, have)
elif state == 'replaced':
config_xmls = self._state_replaced(want, have)
for xml in config_xmls:
root.append(xml)
return tostring(root)
def _state_replaced(self, want, have):
""" The xml configuration generator when state is replaced
:rtype: A list
:returns: the xml configuration necessary to migrate the current configuration
to the desired configuration
"""
intf_xml = []
intf_xml.extend(self._state_deleted(want, have))
intf_xml.extend(self._state_merged(want, have))
return intf_xml
def _state_overridden(self, want, have):
""" The xml configuration generator when state is overridden
:rtype: A list
:returns: the xml configuration necessary to migrate the current configuration
to the desired configuration
"""
interface_xmls_obj = []
# replace interface config with data in want
interface_xmls_obj.extend(self._state_replaced(want, have))
# delete interface config if interface in have not present in want
delete_obj = []
for have_obj in have:
for want_obj in want:
if have_obj['name'] == want_obj['name']:
break
else:
delete_obj.append(have_obj)
if delete_obj:
interface_xmls_obj.extend(self._state_deleted(delete_obj, have))
return interface_xmls_obj
def _state_merged(self, want, have):
""" The xml configuration generator when state is merged
:rtype: A list
:returns: the xml configuration necessary to merge the provided into
the current configuration
"""
intf_xml = []
config_filter = """
<configuration>
<interfaces/>
</configuration>
"""
data = get_resource_config(self._connection, config_filter=config_filter)
for config in want:
lag_name = config['name']
# if lag interface not already configured fail module.
if not data.xpath("configuration/interfaces/interface[name='%s']" % lag_name):
self._module.fail_json(msg="lag interface %s not configured, configure interface"
" %s before assigning members to lag" % (lag_name, lag_name))
lag_intf_root = build_root_xml_node('interface')
build_child_xml_node(lag_intf_root, 'name', lag_name)
ether_options_node = build_subtree(lag_intf_root, 'aggregated-ether-options')
if config['mode']:
lacp_node = build_child_xml_node(ether_options_node, 'lacp')
build_child_xml_node(lacp_node, config['mode'])
link_protection = config['link_protection']
if link_protection:
build_child_xml_node(ether_options_node, 'link-protection')
elif link_protection is False:
build_child_xml_node(ether_options_node, 'link-protection', None, {'delete': 'delete'})
intf_xml.append(lag_intf_root)
members = config['members']
for member in members:
lag_member_intf_root = build_root_xml_node('interface')
build_child_xml_node(lag_member_intf_root, 'name', member['member'])
lag_node = build_subtree(lag_member_intf_root, 'ether-options/ieee-802.3ad')
build_child_xml_node(lag_node, 'bundle', config['name'])
link_type = member.get('link_type')
if link_type == "primary":
build_child_xml_node(lag_node, 'primary')
elif link_type == "backup":
build_child_xml_node(lag_node, 'backup')
intf_xml.append(lag_member_intf_root)
return intf_xml
def _state_deleted(self, want, have):
""" The xml configuration generator when state is deleted
:rtype: A list
:returns: the xml configuration necessary to remove the current configuration
of the provided objects
"""
intf_xml = []
intf_obj = want
if not intf_obj:
# delete lag interfaces attribute for all the interface
intf_obj = have
for config in intf_obj:
lag_name = config['name']
lag_intf_root = build_root_xml_node('interface')
build_child_xml_node(lag_intf_root, 'name', lag_name)
lag_node = build_subtree(lag_intf_root, 'aggregated-ether-options')
build_child_xml_node(lag_node, 'link-protection', None, {'delete': 'delete'})
lacp_node = build_child_xml_node(lag_node, 'lacp')
build_child_xml_node(lacp_node, 'active', None, {'delete': 'delete'})
build_child_xml_node(lacp_node, 'passive', None, {'delete': 'delete'})
intf_xml.append(lag_intf_root)
# delete lag configuration from member interfaces
for interface_obj in have:
if lag_name == interface_obj['name']:
for member in interface_obj.get('members', []):
lag_member_intf_root = build_root_xml_node('interface')
build_child_xml_node(lag_member_intf_root, 'name', member['member'])
lag_node = build_subtree(lag_member_intf_root, 'ether-options/ieee-802.3ad')
build_child_xml_node(lag_node, 'bundle', None, {'delete': 'delete'})
build_child_xml_node(lag_node, 'primary', None, {'delete': 'delete'})
build_child_xml_node(lag_node, 'backup', None, {'delete': 'delete'})
intf_xml.append(lag_member_intf_root)
return intf_xml

@ -1,177 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos_lldp class
It is in this file where the current configuration (as dict)
is compared to the provided configuration (as dict) and the command set
necessary to bring the current configuration to it's desired end-state is
created
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.junos.junos import locked_config, load_config, commit_configuration, discard_changes, tostring
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.network.junos.facts.facts import Facts
from ansible.module_utils.network.common.netconf import build_root_xml_node, build_child_xml_node
class Lldp_global(ConfigBase):
"""
The junos_lldp class
"""
gather_subset = [
'!all',
'!min',
]
gather_network_resources = [
'lldp_global',
]
def __init__(self, module):
super(Lldp_global, self).__init__(module)
def get_lldp_global_facts(self):
""" Get the 'facts' (the current configuration)
:rtype: A dictionary
:returns: The current configuration as a dictionary
"""
facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
lldp_facts = facts['ansible_network_resources'].get('lldp_global')
if not lldp_facts:
return {}
return lldp_facts
def execute_module(self):
""" Execute the module
:rtype: A dictionary
:returns: The result from module execution
"""
result = {'changed': False}
existing_lldp_global_facts = self.get_lldp_global_facts()
config_xmls = self.set_config(existing_lldp_global_facts)
with locked_config(self._module):
for config_xml in to_list(config_xmls):
diff = load_config(self._module, config_xml, [])
commit = not self._module.check_mode
if diff:
if commit:
commit_configuration(self._module)
else:
discard_changes(self._module)
result['changed'] = True
if self._module._diff:
result['diff'] = {'prepared': diff}
result['commands'] = config_xmls
changed_lldp_global_facts = self.get_lldp_global_facts()
result['before'] = existing_lldp_global_facts
if result['changed']:
result['after'] = changed_lldp_global_facts
return result
def set_config(self, existing_lldp_global_facts):
""" Collect the configuration from the args passed to the module,
collect the current configuration (as a dict from facts)
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
want = self._module.params['config']
have = existing_lldp_global_facts
resp = self.set_state(want, have)
return to_list(resp)
def set_state(self, want, have):
""" Select the appropriate function based on the state provided
:param want: the desired configuration as a dictionary
:param have: the current configuration as a dictionary
:rtype: A list
:returns: the list xml configuration necessary to migrate the current configuration
to the desired configuration
"""
root = build_root_xml_node('protocols')
state = self._module.params['state']
if state == 'deleted':
config_xmls = self._state_deleted(want, have)
elif state == 'merged':
config_xmls = self._state_merged(want, have)
elif state == 'replaced':
config_xmls = self._state_replaced(want, have)
for xml in config_xmls:
root.append(xml)
return tostring(root)
def _state_replaced(self, want, have):
""" The xml configuration generator when state is merged
:rtype: A list
:returns: the xml configuration necessary to merge the provided into
the current configuration
"""
lldp_xml = []
lldp_xml.extend(self._state_deleted(want, have))
lldp_xml.extend(self._state_merged(want, have))
return lldp_xml
def _state_merged(self, want, have):
""" Select the appropriate function based on the state provided
:param want: the desired configuration as a dictionary
:param have: the current configuration as a dictionary
:rtype: A list
:returns: the list xml configuration necessary to migrate the current configuration
to the desired configuration
"""
lldp_xml = []
lldp_root = build_root_xml_node('lldp')
if want.get('address'):
build_child_xml_node(lldp_root, 'management-address', want['address'])
if want.get('interval'):
build_child_xml_node(lldp_root, 'advertisement-interval', want['interval'])
if want.get('transmit_delay'):
build_child_xml_node(lldp_root, 'transmit-delay', want['transmit_delay'])
if want.get('hold_multiplier'):
build_child_xml_node(lldp_root, 'hold-multiplier', want['hold_multiplier'])
enable = want.get('enable')
if enable is not None:
if enable is False:
build_child_xml_node(lldp_root, 'disable')
else:
build_child_xml_node(lldp_root, 'disable', None, {'delete': 'delete'})
else:
build_child_xml_node(lldp_root, 'disable', None, {'delete': 'delete'})
lldp_xml.append(lldp_root)
return lldp_xml
def _state_deleted(self, want, have):
""" The command generator when state is deleted
:rtype: A list
:returns: the commands necessary to remove the current configuration
of the provided objects
"""
lldp_xml = []
lldp_root = build_root_xml_node('lldp')
build_child_xml_node(lldp_root, 'management-address', None, {'delete': 'delete'})
build_child_xml_node(lldp_root, 'advertisement-interval', None, {'delete': 'delete'})
build_child_xml_node(lldp_root, 'transmit-delay', None, {'delete': 'delete'})
build_child_xml_node(lldp_root, 'hold-multiplier', None, {'delete': 'delete'})
build_child_xml_node(lldp_root, 'disable', None, {'delete': 'delete'})
lldp_xml.append(lldp_root)
return lldp_xml

@ -1,205 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos_lldp_interfaces class
It is in this file where the current configuration (as dict)
is compared to the provided configuration (as dict) and the command set
necessary to bring the current configuration to it's desired end-state is
created
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.network.junos.facts.facts import Facts
from ansible.module_utils.network.junos.junos import locked_config, load_config, commit_configuration, discard_changes, tostring
from ansible.module_utils.network.common.netconf import build_root_xml_node, build_child_xml_node, build_subtree
class Lldp_interfaces(ConfigBase):
"""
The junos_lldp_interfaces class
"""
gather_subset = [
'!all',
'!min',
]
gather_network_resources = [
'lldp_interfaces',
]
def __init__(self, module):
super(Lldp_interfaces, self).__init__(module)
def get_lldp_interfaces_facts(self):
""" Get the 'facts' (the current configuration)
:rtype: A dictionary
:returns: The current configuration as a dictionary
"""
facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
lldp_interfaces_facts = facts['ansible_network_resources'].get('lldp_interfaces')
if not lldp_interfaces_facts:
return []
return lldp_interfaces_facts
def execute_module(self):
""" Execute the module
:rtype: A dictionary
:returns: The result from module execution
"""
result = {'changed': False}
warnings = list()
existing_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
config_xmls = self.set_config(existing_lldp_interfaces_facts)
with locked_config(self._module):
for config_xml in to_list(config_xmls):
diff = load_config(self._module, config_xml, warnings)
commit = not self._module.check_mode
if diff:
if commit:
commit_configuration(self._module)
else:
discard_changes(self._module)
result['changed'] = True
if self._module._diff:
result['diff'] = {'prepared': diff}
result['commands'] = config_xmls
changed_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
result['before'] = existing_lldp_interfaces_facts
if result['changed']:
result['after'] = changed_lldp_interfaces_facts
return result
def set_config(self, existing_lldp_interfaces_facts):
""" Collect the configuration from the args passed to the module,
collect the current configuration (as a dict from facts)
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
want = self._module.params['config']
have = existing_lldp_interfaces_facts
resp = self.set_state(want, have)
return to_list(resp)
def set_state(self, want, have):
""" Select the appropriate function based on the state provided
:param want: the desired configuration as a dictionary
:param have: the current configuration as a dictionary
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
root = build_root_xml_node('protocols')
lldp_intf_ele = build_subtree(root, 'lldp')
state = self._module.params['state']
if state == 'overridden':
config_xmls = self._state_overridden(want, have)
elif state == 'deleted':
config_xmls = self._state_deleted(want, have)
elif state == 'merged':
config_xmls = self._state_merged(want, have)
elif state == 'replaced':
config_xmls = self._state_replaced(want, have)
for xml in config_xmls:
lldp_intf_ele.append(xml)
return tostring(root)
def _state_replaced(self, want, have):
""" The xml configuration generator when state is replaced
:rtype: A list
:returns: the xml configuration necessary to migrate the current configuration
to the desired configuration
"""
lldp_intf_xml = []
lldp_intf_xml.extend(self._state_deleted(want, have))
lldp_intf_xml.extend(self._state_merged(want, have))
return lldp_intf_xml
def _state_overridden(self, want, have):
""" The xml configuration generator when state is overridden
:rtype: A list
:returns: the xml configuration necessary to migrate the current configuration
to the desired configuration
"""
lldp_intf_xmls_obj = []
# replace interface config with data in want
lldp_intf_xmls_obj.extend(self._state_replaced(want, have))
# delete interface config if interface in have not present in want
delete_obj = []
for have_obj in have:
for want_obj in want:
if have_obj['name'] == want_obj['name']:
break
else:
delete_obj.append(have_obj)
if len(delete_obj):
lldp_intf_xmls_obj.extend(self._state_deleted(delete_obj, have))
return lldp_intf_xmls_obj
def _state_merged(self, want, have):
""" The xml configuration generator when state is merged
:rtype: A list
:returns: the xml configuration necessary to merge the provided into
the current configuration
"""
lldp_intf_xml = []
for config in want:
lldp_intf_root = build_root_xml_node('interface')
if config.get('name'):
build_child_xml_node(lldp_intf_root, 'name', config['name'])
if config.get('enabled') is not None:
if config['enabled'] is False:
build_child_xml_node(lldp_intf_root, 'disable')
else:
build_child_xml_node(lldp_intf_root, 'disable', None, {'delete': 'delete'})
else:
build_child_xml_node(lldp_intf_root, 'disable', None, {'delete': 'delete'})
lldp_intf_xml.append(lldp_intf_root)
return lldp_intf_xml
def _state_deleted(self, want, have):
""" The xml configuration generator when state is deleted
:rtype: A list
:returns: the xml configuration necessary to remove the current configuration
of the provided objects
"""
lldp_intf_xml = []
intf_obj = want
if not intf_obj:
# delete lldp interfaces attribute from all the existing interface
intf_obj = have
for config in intf_obj:
lldp_intf_root = build_root_xml_node('interface')
lldp_intf_root.attrib.update({'delete': 'delete'})
build_child_xml_node(lldp_intf_root, 'name', config['name'])
lldp_intf_xml.append(lldp_intf_root)
return lldp_intf_xml

@ -1,235 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos_static_routes class
It is in this file where the current configuration (as dict)
is compared to the provided configuration (as dict) and the command set
necessary to bring the current configuration to it's desired end-state is
created
"""
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.network.junos.facts.facts import Facts
from ansible.module_utils.network.junos.junos import (locked_config,
load_config,
commit_configuration,
discard_changes,
tostring)
from ansible.module_utils.network.common.netconf import (build_root_xml_node,
build_child_xml_node)
class Static_routes(ConfigBase):
"""
The junos_static_routes class
"""
gather_subset = [
'!all',
'!min',
]
gather_network_resources = [
'static_routes',
]
def __init__(self, module):
super(Static_routes, self).__init__(module)
def get_static_routes_facts(self):
""" Get the 'facts' (the current configuration)
:rtype: A dictionary
:returns: The current configuration as a dictionary
"""
facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
static_routes_facts = facts['ansible_network_resources'].get('static_routes')
if not static_routes_facts:
return []
return static_routes_facts
def execute_module(self):
""" Execute the module
:rtype: A dictionary
:returns: The result from module execution
"""
result = {'changed': False}
warnings = list()
existing_static_routes_facts = self.get_static_routes_facts()
config_xmls = self.set_config(existing_static_routes_facts)
with locked_config(self._module):
for config_xml in to_list(config_xmls):
diff = load_config(self._module, config_xml, [])
commit = not self._module.check_mode
if diff:
if commit:
commit_configuration(self._module)
else:
discard_changes(self._module)
result['changed'] = True
if self._module._diff:
result['diff'] = {'prepared': diff}
result['xml'] = config_xmls
changed_static_routes_facts = self.get_static_routes_facts()
result['before'] = existing_static_routes_facts
if result['changed']:
result['after'] = changed_static_routes_facts
result['warnings'] = warnings
return result
def set_config(self, existing_static_routes_facts):
""" Collect the configuration from the args passed to the module,
collect the current configuration (as a dict from facts)
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
want = self._module.params['config']
have = existing_static_routes_facts
resp = self.set_state(want, have)
return to_list(resp)
def set_state(self, want, have):
""" Select the appropriate function based on the state provided
:param want: the desired configuration as a dictionary
:param have: the current configuration as a dictionary
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
state = self._module.params['state']
root = build_root_xml_node('configuration')
routing_options = build_child_xml_node(root, 'routing-options')
routing_instances = build_child_xml_node(root, 'routing-instances')
if state == 'overridden':
config_xmls = self._state_overridden(want, have)
elif state == 'deleted':
config_xmls = self._state_deleted(want, have)
elif state == 'merged':
config_xmls = self._state_merged(want, have)
elif state == 'replaced':
config_xmls = self._state_replaced(want, have)
for xml in config_xmls:
if xml['root_type'] == 'routing-options':
routing_options.append(xml['static_route_xml'])
elif xml['root_type'] == 'routing-instances':
routing_instances.append(xml['static_route_xml'])
return [tostring(xml) for xml in root.getchildren()]
def _state_replaced(self, want, have):
""" The command generator when state is replaced
:rtype: A list
:returns: the xml necessary to migrate the current configuration
to the desired configuration
"""
static_route_xml = []
static_route_xml.extend(self._state_deleted(want, have))
static_route_xml.extend(self._state_merged(want, have))
return static_route_xml
def _state_overridden(self, want, have):
""" The command generator when state is overridden
:rtype: A list
:returns: the xml necessary to migrate the current configuration
to the desired configuration
"""
static_route_xml = []
static_route_xml.extend(self._state_deleted(have, have))
static_route_xml.extend(self._state_merged(want, have))
return static_route_xml
def _state_deleted(self, want, have):
""" The command generator when state is deleted
:rtype: A list
:returns: the xml necessary to migrate the current configuration
to the desired configuration
"""
if not want:
want = have
static_route_xml = self._state_merged(want, have, delete={'delete': 'delete'})
return static_route_xml
def _state_merged(self, want, have, delete=None):
""" The command generator when state is merged
:rtype: A list
:returns: the xml necessary to migrate the current configuration
to the desired configuration
"""
static_route_xml = []
root_type = ""
vrf_name = None
for config in want:
if config.get('vrf'):
vrf_name = config['vrf']
if vrf_name:
root_type = 'routing-instances'
instance = build_root_xml_node('instance')
build_child_xml_node(instance, 'name', vrf_name)
routing_options = build_child_xml_node(instance, 'routing-options')
else:
root_type = 'routing-options'
for afi in config['address_families']:
protocol = afi['afi']
if protocol == 'ipv6':
if vrf_name:
rib_route_root = build_child_xml_node(routing_options, 'rib')
build_child_xml_node(rib_route_root, 'name', vrf_name + '.inet6.0')
else:
rib_route_root = build_root_xml_node('rib')
build_child_xml_node(rib_route_root, 'name', 'inet6.0')
static_route_root = build_child_xml_node(rib_route_root, 'static')
elif protocol == 'ipv4':
if vrf_name:
static_route_root = build_child_xml_node(routing_options, 'static')
else:
static_route_root = build_root_xml_node('static')
if afi.get('routes'):
for route in afi['routes']:
route_node = build_child_xml_node(static_route_root, 'route')
if delete:
route_node.attrib.update(delete)
if route.get('dest'):
build_child_xml_node(route_node, 'name', route['dest'])
if not delete:
if route.get('metric'):
build_child_xml_node(route_node, 'metric', route['metric'])
if route.get('next_hop'):
for hop in route['next_hop']:
build_child_xml_node(route_node, 'next-hop', hop['forward_router_address'])
elif delete:
if vrf_name:
instance.attrib.update(delete)
static_route_root.attrib.update(delete)
if vrf_name:
static_route_xml.append({'root_type': root_type, 'static_route_xml': instance})
else:
if protocol == 'ipv6':
static_route_xml.append({'root_type': root_type, 'static_route_xml': rib_route_root})
else:
static_route_xml.append({'root_type': root_type, 'static_route_xml': static_route_root})
return static_route_xml

@ -1,208 +0,0 @@
# Copyright (C) 2019 Red Hat, Inc.
#
# This program 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.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
"""
The junos_vlans class
It is in this file where the current configuration (as dict)
is compared to the provided configuration (as dict) and the command set
necessary to bring the current configuration to it's desired end-state is
created
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.network.junos.facts.facts import Facts
from ansible.module_utils.network.junos.junos import (locked_config,
load_config,
commit_configuration,
discard_changes,
tostring)
from ansible.module_utils.network.common.netconf import (build_root_xml_node,
build_child_xml_node)
class Vlans(ConfigBase):
"""
The junos_vlans class
"""
gather_subset = [
'!all',
'!min',
]
gather_network_resources = [
'vlans',
]
def __init__(self, module):
super(Vlans, self).__init__(module)
def get_vlans_facts(self):
""" Get the 'facts' (the current configuration)
:rtype: A dictionary
:returns: The current configuration as a dictionary
"""
facts, _warnings = Facts(self._module).get_facts(
self.gather_subset, self.gather_network_resources)
vlans_facts = facts['ansible_network_resources'].get('vlans')
if not vlans_facts:
return []
return vlans_facts
def execute_module(self):
""" Execute the module
:rtype: A dictionary
:returns: The result from module execution
"""
result = {'changed': False}
warnings = list()
existing_vlans_facts = self.get_vlans_facts()
config_xmls = self.set_config(existing_vlans_facts)
with locked_config(self._module):
for config_xml in to_list(config_xmls):
diff = load_config(self._module, config_xml, warnings)
commit = not self._module.check_mode
if diff:
if commit:
commit_configuration(self._module)
else:
discard_changes(self._module)
result['changed'] = True
if self._module._diff:
result['diff'] = {'prepared': diff}
result['commands'] = config_xmls
changed_vlans_facts = self.get_vlans_facts()
result['before'] = existing_vlans_facts
if result['changed']:
result['after'] = changed_vlans_facts
result['warnings'] = warnings
return result
def set_config(self, existing_vlans_facts):
""" Collect the configuration from the args passed to the module,
collect the current configuration (as a dict from facts)
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
want = self._module.params['config']
have = existing_vlans_facts
resp = self.set_state(want, have)
return to_list(resp)
def set_state(self, want, have):
""" Select the appropriate function based on the state provided
:param want: the desired configuration as a dictionary
:param have: the current configuration as a dictionary
:rtype: A list
:returns: the commands necessary to migrate the current configuration
to the desired configuration
"""
root = build_root_xml_node('vlans')
state = self._module.params['state']
if state == 'overridden':
config_xmls = self._state_overridden(want, have)
elif state == 'deleted':
config_xmls = self._state_deleted(want, have)
elif state == 'merged':
config_xmls = self._state_merged(want, have)
elif state == 'replaced':
config_xmls = self._state_replaced(want, have)
for xml in config_xmls:
root.append(xml)
return tostring(root)
def _state_replaced(self, want, have):
""" The command generator when state is replaced
:rtype: A list
:returns: the xml necessary to migrate the current configuration
to the desired configuration
"""
intf_xml = []
intf_xml.extend(self._state_deleted(want, have))
intf_xml.extend(self._state_merged(want, have))
return intf_xml
def _state_overridden(self, want, have):
""" The command generator when state is overridden
:rtype: A list
:returns: the xml necessary to migrate the current configuration
to the desired configuration
"""
intf_xml = []
intf_xml.extend(self._state_deleted(have, have))
intf_xml.extend(self._state_merged(want, have))
return intf_xml
def _state_merged(self, want, have):
""" The command generator when state is merged
:rtype: A list
:returns: the xml necessary to merge the provided into
the current configuration
"""
intf_xml = []
for config in want:
vlan_name = str(config['name'])
vlan_id = str(config['vlan_id'])
vlan_description = config.get('description')
vlan_root = build_root_xml_node('vlan')
build_child_xml_node(vlan_root, 'name', vlan_name)
build_child_xml_node(vlan_root, 'vlan-id', vlan_id)
if vlan_description:
build_child_xml_node(vlan_root, 'description',
vlan_description)
intf_xml.append(vlan_root)
return intf_xml
def _state_deleted(self, want, have):
""" The command generator when state is deleted
:rtype: A list
:returns: the xml necessary to remove the current configuration
of the provided objects
"""
intf_xml = []
if not want:
want = have
for config in want:
vlan_name = config['name']
vlan_root = build_root_xml_node('vlan')
vlan_root.attrib.update({'delete': 'delete'})
build_child_xml_node(vlan_root, 'name', vlan_name)
intf_xml.append(vlan_root)
return intf_xml

@ -1,83 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The facts class for junos
this file validates each subset of facts and selectively
calls the appropriate facts gathering function
"""
from ansible.module_utils.network.common.facts.facts import FactsBase
from ansible.module_utils.network.junos.junos import HAS_PYEZ
from ansible.module_utils.network.junos.facts.legacy.base import Default, Hardware, Config, Interfaces, OFacts
from ansible.module_utils.network.junos.facts.interfaces.interfaces import InterfacesFacts
from ansible.module_utils.network.junos.facts.lacp.lacp import LacpFacts
from ansible.module_utils.network.junos.facts.lacp_interfaces.lacp_interfaces import Lacp_interfacesFacts
from ansible.module_utils.network.junos.facts.lag_interfaces.lag_interfaces import Lag_interfacesFacts
from ansible.module_utils.network.junos.facts.l3_interfaces.l3_interfaces import L3_interfacesFacts
from ansible.module_utils.network.junos.facts.lldp_global.lldp_global import Lldp_globalFacts
from ansible.module_utils.network.junos.facts.lldp_interfaces.lldp_interfaces import Lldp_interfacesFacts
from ansible.module_utils.network.junos.facts.vlans.vlans import VlansFacts
from ansible.module_utils.network.junos.facts.l2_interfaces.l2_interfaces import L2_interfacesFacts
from ansible.module_utils.network.junos.facts.static_routes.static_routes import Static_routesFacts
FACT_LEGACY_SUBSETS = dict(
default=Default,
hardware=Hardware,
config=Config,
interfaces=Interfaces,
)
FACT_RESOURCE_SUBSETS = dict(
interfaces=InterfacesFacts,
lacp=LacpFacts,
lacp_interfaces=Lacp_interfacesFacts,
lag_interfaces=Lag_interfacesFacts,
l2_interfaces=L2_interfacesFacts,
l3_interfaces=L3_interfacesFacts,
lldp_global=Lldp_globalFacts,
lldp_interfaces=Lldp_interfacesFacts,
vlans=VlansFacts,
static_routes=Static_routesFacts
)
class Facts(FactsBase):
""" The fact class for junos
"""
VALID_LEGACY_GATHER_SUBSETS = frozenset(FACT_LEGACY_SUBSETS.keys())
VALID_RESOURCE_SUBSETS = frozenset(FACT_RESOURCE_SUBSETS.keys())
def __init__(self, module):
super(Facts, self).__init__(module)
def get_facts(self, legacy_facts_type=None, resource_facts_type=None, data=None):
""" Collect the facts for junos
:param legacy_facts_type: List of legacy facts types
:param resource_facts_type: List of resource fact types
:param data: previously collected conf
:rtype: dict
:return: the facts gathered
"""
if self.VALID_RESOURCE_SUBSETS:
self.get_network_resources_facts(FACT_RESOURCE_SUBSETS, resource_facts_type, data)
if not legacy_facts_type:
legacy_facts_type = self._gather_subset
# fetch old style facts only when explicitly mentioned in gather_subset option
if 'ofacts' in legacy_facts_type:
if HAS_PYEZ:
self.ansible_facts.update(OFacts(self._module).populate())
else:
self._warnings.extend([
'junos-eznc is required to gather old style facts but does not appear to be installed. '
'It can be installed using `pip install junos-eznc`'])
self.ansible_facts['ansible_net_gather_subset'].append('ofacts')
legacy_facts_type.remove('ofacts')
if self.VALID_LEGACY_GATHER_SUBSETS:
self.get_network_legacy_facts(FACT_LEGACY_SUBSETS, legacy_facts_type)
return self.ansible_facts, self._warnings

@ -1,111 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos interfaces fact class
It is in this file the configuration is collected from the device
for a given resource, parsed, and the facts tree is populated
based on the configuration.
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from copy import deepcopy
from ansible.module_utils._text import to_bytes
from ansible.module_utils.network.common import utils
from ansible.module_utils.network.junos.argspec.interfaces.interfaces import InterfacesArgs
from ansible.module_utils.network.junos.utils.utils import get_resource_config
from ansible.module_utils.six import string_types
try:
from lxml import etree
HAS_LXML = True
except ImportError:
HAS_LXML = False
class InterfacesFacts(object):
""" The junos interfaces fact class
"""
def __init__(self, module, subspec='config', options='options'):
self._module = module
self.argument_spec = InterfacesArgs.argument_spec
spec = deepcopy(self.argument_spec)
if subspec:
if options:
facts_argument_spec = spec[subspec][options]
else:
facts_argument_spec = spec[subspec]
else:
facts_argument_spec = spec
self.generated_spec = utils.generate_dict(facts_argument_spec)
def populate_facts(self, connection, ansible_facts, data=None):
""" Populate the facts for interfaces
:param connection: the device connection
:param data: previously collected configuration as lxml ElementTree root instance
or valid xml sting
:rtype: dictionary
:returns: facts
"""
if not HAS_LXML:
self._module.fail_json(msg='lxml is not installed.')
if not data:
config_filter = """
<configuration>
<interfaces/>
</configuration>
"""
data = get_resource_config(connection, config_filter=config_filter)
if isinstance(data, string_types):
data = etree.fromstring(to_bytes(data, errors='surrogate_then_replace'))
resources = data.xpath('configuration/interfaces/interface')
objs = []
for resource in resources:
if resource is not None:
obj = self.render_config(self.generated_spec, resource)
if obj:
objs.append(obj)
facts = {}
if objs:
facts['interfaces'] = []
params = utils.validate_config(self.argument_spec, {'config': objs})
for cfg in params['config']:
facts['interfaces'].append(utils.remove_empties(cfg))
ansible_facts['ansible_network_resources'].update(facts)
return ansible_facts
def render_config(self, spec, conf):
"""
Render config as dictionary structure and delete keys
from spec for null values
:param spec: The facts tree, generated from the argspec
:param conf: The ElementTree instance of configuration object
:rtype: dictionary
:returns: The generated config
"""
config = deepcopy(spec)
config['name'] = utils.get_xml_conf_arg(conf, 'name')
config['description'] = utils.get_xml_conf_arg(conf, 'description')
mtu = utils.get_xml_conf_arg(conf, 'mtu')
config['mtu'] = int(mtu) if mtu else None
config['speed'] = utils.get_xml_conf_arg(conf, 'speed')
config['duplex'] = utils.get_xml_conf_arg(conf, 'link-mode')
config['hold_time']['down'] = utils.get_xml_conf_arg(conf, 'hold-time/down')
config['hold_time']['up'] = utils.get_xml_conf_arg(conf, 'hold-time/up')
disable = utils.get_xml_conf_arg(conf, 'disable', data='tag')
if disable:
config['enabled'] = False
else:
config['enabled'] = True
return utils.remove_empties(config)

@ -1,124 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos l2_interfaces fact class
It is in this file the configuration is collected from the device
for a given resource, parsed, and the facts tree is populated
based on the configuration.
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from copy import deepcopy
from ansible.module_utils._text import to_bytes
from ansible.module_utils.network.common import utils
from ansible.module_utils.network.junos.argspec.l2_interfaces.l2_interfaces import L2_interfacesArgs
from ansible.module_utils.network.junos.utils.utils import get_resource_config
from ansible.module_utils.six import string_types
try:
from lxml import etree
HAS_LXML = True
except ImportError:
HAS_LXML = False
class L2_interfacesFacts(object):
""" The junos l2_interfaces fact class
"""
def __init__(self, module, subspec='config', options='options'):
self._module = module
self.argument_spec = L2_interfacesArgs.argument_spec
spec = deepcopy(self.argument_spec)
if subspec:
if options:
facts_argument_spec = spec[subspec][options]
else:
facts_argument_spec = spec[subspec]
else:
facts_argument_spec = spec
self.generated_spec = utils.generate_dict(facts_argument_spec)
def populate_facts(self, connection, ansible_facts, data=None):
""" Populate the facts for interfaces
:param connection: the device connection
:param data: previously collected configuration as lxml ElementTree root instance
or valid xml sting
:rtype: dictionary
:returns: facts
"""
if not HAS_LXML:
self._module.fail_json(msg='lxml is not installed.')
if not data:
config_filter = """
<configuration>
<interfaces/>
</configuration>
"""
data = get_resource_config(connection, config_filter=config_filter)
if isinstance(data, string_types):
data = etree.fromstring(to_bytes(data, errors='surrogate_then_replace'))
self._resources = data.xpath('configuration/interfaces/interface')
objs = []
for resource in self._resources:
if resource is not None:
obj = self.render_config(self.generated_spec, resource)
if obj:
objs.append(obj)
facts = {}
if objs:
facts['l2_interfaces'] = []
params = utils.validate_config(self.argument_spec, {'config': objs})
for cfg in params['config']:
facts['l2_interfaces'].append(utils.remove_empties(cfg))
ansible_facts['ansible_network_resources'].update(facts)
return ansible_facts
def render_config(self, spec, conf):
"""`
Render config as dictionary structure and delete keys
from spec for null values
:param spec: The facts tree, generated from the argspec
:param conf: The ElementTree instance of configuration object
:rtype: dictionary
:returns: The generated config
"""
config = deepcopy(spec)
enhanced_layer = True
mode = utils.get_xml_conf_arg(conf, 'unit/family/ethernet-switching/interface-mode')
if mode is None:
mode = utils.get_xml_conf_arg(conf, 'unit/family/ethernet-switching/port-mode')
enhanced_layer = False
# Layer 2 is configured on interface
if mode:
config['name'] = utils.get_xml_conf_arg(conf, 'name')
unit = utils.get_xml_conf_arg(conf, 'unit/name')
config['unit'] = unit if unit else 0
config['enhanced_layer'] = enhanced_layer
if mode == 'access':
config['access'] = {}
config['access']['vlan'] = utils.get_xml_conf_arg(conf, "unit/family/ethernet-switching/vlan/members")
elif mode == 'trunk':
config['trunk'] = {}
vlan_members = conf.xpath('unit/family/ethernet-switching/vlan/members')
if vlan_members:
config['trunk']['allowed_vlans'] = []
for vlan_member in vlan_members:
config['trunk']['allowed_vlans'].append(vlan_member.text)
config['trunk']['native_vlan'] = utils.get_xml_conf_arg(conf, "native-vlan-id")
return utils.remove_empties(config)

@ -1,134 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos l3_interfaces fact class
It is in this file the configuration is collected from the device
for a given resource, parsed, and the facts tree is populated
based on the configuration.
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from copy import deepcopy
from ansible.module_utils._text import to_bytes
from ansible.module_utils.network.common import utils
from ansible.module_utils.network.junos.argspec.l3_interfaces.l3_interfaces import L3_interfacesArgs
from ansible.module_utils.six import string_types
try:
from lxml import etree
HAS_LXML = True
except ImportError:
HAS_LXML = False
class L3_interfacesFacts(object):
""" The junos l3_interfaces fact class
"""
def __init__(self, module, subspec='config', options='options'):
self._module = module
self.argument_spec = L3_interfacesArgs.argument_spec
spec = deepcopy(self.argument_spec)
if subspec:
if options:
facts_argument_spec = spec[subspec][options]
else:
facts_argument_spec = spec[subspec]
else:
facts_argument_spec = spec
self.generated_spec = utils.generate_dict(facts_argument_spec)
def populate_facts(self, connection, ansible_facts, data=None):
""" Populate the facts for l3_interfaces
:param connection: the device connection
:param ansible_facts: Facts dictionary
:param data: previously collected conf
:rtype: dictionary
:returns: facts
"""
if not HAS_LXML:
self._module.fail_json(msg='lxml is not installed.')
if not data:
config_filter = """
<configuration>
<interfaces/>
</configuration>
"""
data = connection.get_configuration(filter=config_filter)
if isinstance(data, string_types):
data = etree.fromstring(to_bytes(data, errors='surrogate_then_replace'))
resources = data.xpath('configuration/interfaces/interface')
objs = []
if resources:
objs = self.parse_l3_if_resources(resources)
config = []
if objs:
for l3_if_obj in objs:
config.append(self.render_config(
self.generated_spec, l3_if_obj))
facts = {}
facts['l3_interfaces'] = config
ansible_facts['ansible_network_resources'].update(facts)
return ansible_facts
def parse_l3_if_resources(self, l3_if_resources):
l3_ifaces = []
for iface in l3_if_resources:
interface = {}
interface['name'] = iface.find('name').text
if iface.find('description') is not None:
interface['description'] = iface.find('description').text
interface['unit'] = iface.find('unit/name').text
family = iface.find('unit/family/')
if family is not None and family.tag != 'ethernet-switching':
ipv4 = iface.findall('unit/family/inet/address')
dhcp = iface.findall('unit/family/inet/dhcp')
ipv6 = iface.findall('unit/family/inet6/address')
if dhcp:
interface['ipv4'] = [{'address': 'dhcp'}]
if ipv4:
interface['ipv4'] = self.get_ip_addresses(ipv4)
elif not dhcp:
interface['ipv4'] = None
if ipv6:
interface['ipv6'] = self.get_ip_addresses(ipv6)
l3_ifaces.append(interface)
return l3_ifaces
def get_ip_addresses(self, ip_addr):
address_list = []
for ip in ip_addr:
for addr in ip:
address_list.append({'address': addr.text})
return address_list
def render_config(self, spec, conf):
"""
Render config as dictionary structure and delete keys
from spec for null values
:param spec: The facts tree, generated from the argspec
:param conf: The configuration
:rtype: dictionary
:returns: The generated config
"""
config = deepcopy(spec)
config['name'] = conf['name']
config['description'] = conf.get('description')
config['unit'] = conf.get('unit', 0)
config['ipv4'] = conf.get('ipv4')
config['ipv6'] = conf.get('ipv6')
return utils.remove_empties(config)

@ -1,96 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos lacp fact class
It is in this file the configuration is collected from the device
for a given resource, parsed, and the facts tree is populated
based on the configuration.
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from copy import deepcopy
from ansible.module_utils._text import to_bytes
from ansible.module_utils.network.common import utils
from ansible.module_utils.network.junos.argspec.lacp.lacp import LacpArgs
from ansible.module_utils.network.junos.utils.utils import get_resource_config
from ansible.module_utils.six import string_types
try:
from lxml import etree
HAS_LXML = True
except ImportError:
HAS_LXML = False
class LacpFacts(object):
""" The junos lacp fact class
"""
def __init__(self, module, subspec='config', options='options'):
self._module = module
self.argument_spec = LacpArgs.argument_spec
spec = deepcopy(self.argument_spec)
if subspec:
if options:
facts_argument_spec = spec[subspec][options]
else:
facts_argument_spec = spec[subspec]
else:
facts_argument_spec = spec
self.generated_spec = utils.generate_dict(facts_argument_spec)
def populate_facts(self, connection, ansible_facts, data=None):
""" Populate the facts for interfaces
:param connection: the device connection
:param data: previously collected configuration as lxml ElementTree root instance
or valid xml sting
:rtype: dictionary
:returns: facts
"""
if not HAS_LXML:
self._module.fail_json(msg='lxml is not installed.')
if not data:
config_filter = """
<configuration>
<chassis>
<aggregated-devices>
<ethernet>
<lacp>
</lacp>
</ethernet>
</aggregated-devices>
</chassis>
</configuration>
"""
data = get_resource_config(connection, config_filter=config_filter)
if isinstance(data, string_types):
data = etree.fromstring(to_bytes(data, errors='surrogate_then_replace'))
facts = {}
config = deepcopy(self.generated_spec)
resources = data.xpath('configuration/chassis/aggregated-devices/ethernet/lacp')
if resources:
lacp_root = resources[0]
config['system_priority'] = utils.get_xml_conf_arg(lacp_root, 'system-priority')
if utils.get_xml_conf_arg(lacp_root, 'link-protection/non-revertive', data='tag'):
config['link_protection'] = "non-revertive"
elif utils.get_xml_conf_arg(lacp_root, 'link-protection'):
config['link_protection'] = "revertive"
params = utils.validate_config(self.argument_spec, {'config': utils.remove_empties(config)})
facts['lacp'] = {}
facts['lacp'].update(utils.remove_empties(params['config']))
ansible_facts['ansible_network_resources'].update(facts)
return ansible_facts

@ -1,113 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos lacp_interfaces fact class
It is in this file the configuration is collected from the device
for a given resource, parsed, and the facts tree is populated
based on the configuration.
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from copy import deepcopy
from ansible.module_utils._text import to_bytes
from ansible.module_utils.network.common import utils
from ansible.module_utils.network.junos.argspec.lacp_interfaces.lacp_interfaces import Lacp_interfacesArgs
from ansible.module_utils.network.junos.utils.utils import get_resource_config
from ansible.module_utils.six import string_types
try:
from lxml import etree
HAS_LXML = True
except ImportError:
HAS_LXML = False
class Lacp_interfacesFacts(object):
""" The junos lacp_interfaces fact class
"""
def __init__(self, module, subspec='config', options='options'):
self._module = module
self.argument_spec = Lacp_interfacesArgs.argument_spec
spec = deepcopy(self.argument_spec)
if subspec:
if options:
facts_argument_spec = spec[subspec][options]
else:
facts_argument_spec = spec[subspec]
else:
facts_argument_spec = spec
self.generated_spec = utils.generate_dict(facts_argument_spec)
def populate_facts(self, connection, ansible_facts, data=None):
""" Populate the facts for interfaces
:param connection: the device connection
:param data: previously collected configuration as lxml ElementTree root instance
or valid xml sting
:rtype: dictionary
:returns: facts
"""
if not HAS_LXML:
self._module.fail_json(msg='lxml is not installed.')
if not data:
config_filter = """
<configuration>
<interfaces/>
</configuration>
"""
data = get_resource_config(connection, config_filter=config_filter)
if isinstance(data, string_types):
data = etree.fromstring(to_bytes(data, errors='surrogate_then_replace'))
self._resources = data.xpath('configuration/interfaces/interface')
objs = []
for resource in self._resources:
if resource is not None:
obj = self.render_config(self.generated_spec, resource)
if obj:
objs.append(obj)
facts = {}
if objs:
facts['lacp_interfaces'] = []
params = utils.validate_config(self.argument_spec, {'config': objs})
for cfg in params['config']:
facts['lacp_interfaces'].append(utils.remove_empties(cfg))
ansible_facts['ansible_network_resources'].update(facts)
return ansible_facts
def render_config(self, spec, conf):
"""
Render config as dictionary structure and delete keys
from spec for null values
:param spec: The facts tree, generated from the argspec
:param conf: The ElementTree instance of configuration object
:rtype: dictionary
:returns: The generated config
"""
config = deepcopy(spec)
config['name'] = utils.get_xml_conf_arg(conf, 'name')
config['period'] = utils.get_xml_conf_arg(conf, 'aggregated-ether-options/lacp/periodic')
config['sync_reset'] = utils.get_xml_conf_arg(conf, 'aggregated-ether-options/lacp/sync-reset')
force_up = utils.get_xml_conf_arg(conf, 'ether-options/ieee-802.3ad/lacp/force-up', data='tag')
if force_up:
config['force_up'] = True
config['port_priority'] = utils.get_xml_conf_arg(conf, 'ether-options/ieee-802.3ad/lacp/port-priority')
config['system']['priority'] = utils.get_xml_conf_arg(conf, 'aggregated-ether-options/lacp/system-priority')
address = utils.get_xml_conf_arg(conf, 'aggregated-ether-options/lacp/system-id')
if address:
config['system'].update({'mac': {'address': address}})
lacp_intf_cfg = utils.remove_empties(config)
# if lacp config is not present for interface return empty dict
if len(lacp_intf_cfg) == 1:
return {}
else:
return lacp_intf_cfg

@ -1,127 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos lag_interfaces fact class
It is in this file the configuration is collected from the device
for a given resource, parsed, and the facts tree is populated
based on the configuration.
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from copy import deepcopy
from ansible.module_utils._text import to_bytes
from ansible.module_utils.network.common import utils
from ansible.module_utils.network.junos.argspec.lag_interfaces.lag_interfaces import Lag_interfacesArgs
from ansible.module_utils.network.junos.utils.utils import get_resource_config
from ansible.module_utils.six import string_types
try:
from lxml import etree
HAS_LXML = True
except ImportError:
HAS_LXML = False
class Lag_interfacesFacts(object):
""" The junos lag_interfaces fact class
"""
def __init__(self, module, subspec='config', options='options'):
self._module = module
self.argument_spec = Lag_interfacesArgs.argument_spec
spec = deepcopy(self.argument_spec)
if subspec:
if options:
facts_argument_spec = spec[subspec][options]
else:
facts_argument_spec = spec[subspec]
else:
facts_argument_spec = spec
self.generated_spec = utils.generate_dict(facts_argument_spec)
def populate_facts(self, connection, ansible_facts, data=None):
""" Populate the facts for interfaces
:param connection: the device connection
:param data: previously collected configuration as lxml ElementTree root instance
or valid xml sting
:rtype: dictionary
:returns: facts
"""
if not HAS_LXML:
self._module.fail_json(msg='lxml is not installed.')
if not data:
config_filter = """
<configuration>
<interfaces/>
</configuration>
"""
data = get_resource_config(connection, config_filter=config_filter)
if isinstance(data, string_types):
data = etree.fromstring(to_bytes(data, errors='surrogate_then_replace'))
self._resources = data.xpath('configuration/interfaces/interface')
objs = []
for resource in self._resources:
if resource is not None:
obj = self.render_config(self.generated_spec, resource)
if obj:
objs.append(obj)
facts = {}
if objs:
facts['lag_interfaces'] = []
params = utils.validate_config(self.argument_spec, {'config': objs})
for cfg in params['config']:
facts['lag_interfaces'].append(utils.remove_empties(cfg))
ansible_facts['ansible_network_resources'].update(facts)
return ansible_facts
def render_config(self, spec, conf):
"""
Render config as dictionary structure and delete keys
from spec for null values
:param spec: The facts tree, generated from the argspec
:param conf: The ElementTree instance of configuration object
:rtype: dictionary
:returns: The generated config
"""
config = deepcopy(spec)
intf_name = utils.get_xml_conf_arg(conf, 'name')
if intf_name.startswith('ae'):
config['name'] = intf_name
config['members'] = []
for interface_obj in self._resources:
lag_interface_member = utils.get_xml_conf_arg(interface_obj, "ether-options/ieee-802.3ad[bundle='%s']/../../name" % intf_name)
if lag_interface_member:
member_config = {}
member_config['member'] = lag_interface_member
if utils.get_xml_conf_arg(interface_obj, "ether-options/ieee-802.3ad/primary", data='tag'):
member_config['link_type'] = "primary"
elif utils.get_xml_conf_arg(interface_obj, "ether-options/ieee-802.3ad/backup", data='tag'):
member_config['link_type'] = "backup"
if member_config:
config['members'].append(member_config)
for m in ['active', 'passive']:
if utils.get_xml_conf_arg(conf, "aggregated-ether-options/lacp/%s" % m, data='tag'):
config['mode'] = m
break
link_protection = utils.get_xml_conf_arg(conf, "aggregated-ether-options/link-protection", data='tag')
if link_protection:
config['link_protection'] = True
lag_intf_cfg = utils.remove_empties(config)
# if lag interfaces config is not present return empty dict
if len(lag_intf_cfg) == 1:
return {}
else:
return lag_intf_cfg

@ -1,195 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos interfaces fact class
It is in this file the configuration is collected from the device
for a given resource, parsed, and the facts tree is populated
based on the configuration.
"""
import platform
from ansible.module_utils.network.common.netconf import exec_rpc
from ansible.module_utils.network.junos.junos import tostring
from ansible.module_utils.network.junos.junos import get_configuration, get_capabilities, get_device
from ansible.module_utils._text import to_text
try:
from lxml.etree import Element, SubElement
except ImportError:
from xml.etree.ElementTree import Element, SubElement
class FactsBase(object):
def __init__(self, module):
self.module = module
self.facts = dict()
self.warnings = []
def populate(self):
raise NotImplementedError
def cli(self, command):
reply = command(self.module, command)
output = reply.find('.//output')
if not output:
self.module.fail_json(msg='failed to retrieve facts for command %s' % command)
return to_text(output.text).strip()
def rpc(self, rpc):
return exec_rpc(self.module, tostring(Element(rpc)))
def get_text(self, ele, tag):
try:
return to_text(ele.find(tag).text).strip()
except AttributeError:
pass
class Default(FactsBase):
def populate(self):
self.facts.update(self.platform_facts())
reply = self.rpc('get-chassis-inventory')
data = reply.find('.//chassis-inventory/chassis')
self.facts['serialnum'] = self.get_text(data, 'serial-number')
def platform_facts(self):
platform_facts = {}
resp = get_capabilities(self.module)
device_info = resp['device_info']
platform_facts['system'] = device_info['network_os']
for item in ('model', 'image', 'version', 'platform', 'hostname'):
val = device_info.get('network_os_%s' % item)
if val:
platform_facts[item] = val
platform_facts['api'] = resp['network_api']
platform_facts['python_version'] = platform.python_version()
return platform_facts
class Config(FactsBase):
def populate(self):
config_format = self.module.params['config_format']
reply = get_configuration(self.module, format=config_format)
if config_format == 'xml':
config = tostring(reply.find('configuration')).strip()
elif config_format == 'text':
config = self.get_text(reply, 'configuration-text')
elif config_format == 'json':
config = self.module.from_json(reply.text.strip())
elif config_format == 'set':
config = self.get_text(reply, 'configuration-set')
self.facts['config'] = config
class Hardware(FactsBase):
def populate(self):
reply = self.rpc('get-system-memory-information')
data = reply.find('.//system-memory-information/system-memory-summary-information')
self.facts.update({
'memfree_mb': int(self.get_text(data, 'system-memory-free')),
'memtotal_mb': int(self.get_text(data, 'system-memory-total'))
})
reply = self.rpc('get-system-storage')
data = reply.find('.//system-storage-information')
filesystems = list()
for obj in data:
filesystems.append(self.get_text(obj, 'filesystem-name'))
self.facts['filesystems'] = filesystems
reply = self.rpc('get-route-engine-information')
data = reply.find('.//route-engine-information')
routing_engines = dict()
for obj in data:
slot = self.get_text(obj, 'slot')
routing_engines.update({slot: {}})
routing_engines[slot].update({'slot': slot})
for child in obj:
if child.text != "\n":
routing_engines[slot].update({child.tag.replace("-", "_"): child.text})
self.facts['routing_engines'] = routing_engines
if len(data) > 1:
self.facts['has_2RE'] = True
else:
self.facts['has_2RE'] = False
reply = self.rpc('get-chassis-inventory')
data = reply.findall('.//chassis-module')
modules = list()
for obj in data:
mod = dict()
for child in obj:
if child.text != "\n":
mod.update({child.tag.replace("-", "_"): child.text})
modules.append(mod)
self.facts['modules'] = modules
class Interfaces(FactsBase):
def populate(self):
ele = Element('get-interface-information')
SubElement(ele, 'detail')
reply = exec_rpc(self.module, tostring(ele))
interfaces = {}
for item in reply[0]:
name = self.get_text(item, 'name')
obj = {
'oper-status': self.get_text(item, 'oper-status'),
'admin-status': self.get_text(item, 'admin-status'),
'speed': self.get_text(item, 'speed'),
'macaddress': self.get_text(item, 'hardware-physical-address'),
'mtu': self.get_text(item, 'mtu'),
'type': self.get_text(item, 'if-type'),
}
interfaces[name] = obj
self.facts['interfaces'] = interfaces
class OFacts(FactsBase):
def populate(self):
device = get_device(self.module)
facts = dict(device.facts)
if '2RE' in facts:
facts['has_2RE'] = facts['2RE']
del facts['2RE']
facts['version_info'] = dict(facts['version_info'])
if 'junos_info' in facts:
for key, value in facts['junos_info'].items():
if 'object' in value:
value['object'] = dict(value['object'])
return facts

@ -1,89 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos lldp fact class
It is in this file the configuration is collected from the device
for a given resource, parsed, and the facts tree is populated
based on the configuration.
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from copy import deepcopy
from ansible.module_utils._text import to_bytes
from ansible.module_utils.network.common import utils
from ansible.module_utils.network.junos.argspec.lldp_global.lldp_global import Lldp_globalArgs
from ansible.module_utils.network.junos.utils.utils import get_resource_config
from ansible.module_utils.six import string_types
try:
from lxml import etree
HAS_LXML = True
except ImportError:
HAS_LXML = False
class Lldp_globalFacts(object):
""" The junos lldp fact class
"""
def __init__(self, module, subspec='config', options='options'):
self._module = module
self.argument_spec = Lldp_globalArgs.argument_spec
spec = deepcopy(self.argument_spec)
if subspec:
if options:
facts_argument_spec = spec[subspec][options]
else:
facts_argument_spec = spec[subspec]
else:
facts_argument_spec = spec
self.generated_spec = utils.generate_dict(facts_argument_spec)
def populate_facts(self, connection, ansible_facts, data=None):
""" Populate the facts for interfaces
:param connection: the device connection
:param data: previously collected configuration as lxml ElementTree root instance
or valid xml sting
:rtype: dictionary
:returns: facts
"""
if not HAS_LXML:
self._module.fail_json(msg='lxml is not installed.')
if not data:
config_filter = """
<configuration>
<protocols>
<lldp>
</lldp>
</protocols>
</configuration>
"""
data = get_resource_config(connection, config_filter=config_filter)
if isinstance(data, string_types):
data = etree.fromstring(to_bytes(data, errors='surrogate_then_replace'))
facts = {}
config = deepcopy(self.generated_spec)
resources = data.xpath('configuration/protocols/lldp')
if resources:
lldp_root = resources[0]
config['address'] = utils.get_xml_conf_arg(lldp_root, 'management-address')
config['interval'] = utils.get_xml_conf_arg(lldp_root, 'advertisement-interval')
config['transmit_delay'] = utils.get_xml_conf_arg(lldp_root, 'transmit-delay')
config['hold_multiplier'] = utils.get_xml_conf_arg(lldp_root, 'hold-multiplier')
if utils.get_xml_conf_arg(lldp_root, 'disable', data='tag'):
config['enable'] = False
params = utils.validate_config(self.argument_spec, {'config': utils.remove_empties(config)})
facts['lldp_global'] = utils.remove_empties(params['config'])
ansible_facts['ansible_network_resources'].update(facts)
return ansible_facts

@ -1,104 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos lldp_interfaces fact class
It is in this file the configuration is collected from the device
for a given resource, parsed, and the facts tree is populated
based on the configuration.
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from copy import deepcopy
from ansible.module_utils._text import to_bytes
from ansible.module_utils.network.common import utils
from ansible.module_utils.network.junos.argspec.lldp_interfaces.lldp_interfaces import Lldp_interfacesArgs
from ansible.module_utils.network.junos.utils.utils import get_resource_config
from ansible.module_utils.six import string_types
try:
from lxml import etree
HAS_LXML = True
except ImportError:
HAS_LXML = False
class Lldp_interfacesFacts(object):
""" The junos lldp_interfaces fact class
"""
def __init__(self, module, subspec='config', options='options'):
self._module = module
self.argument_spec = Lldp_interfacesArgs.argument_spec
spec = deepcopy(self.argument_spec)
if subspec:
if options:
facts_argument_spec = spec[subspec][options]
else:
facts_argument_spec = spec[subspec]
else:
facts_argument_spec = spec
self.generated_spec = utils.generate_dict(facts_argument_spec)
def populate_facts(self, connection, ansible_facts, data=None):
""" Populate the facts for interfaces
:param connection: the device connection
:param data: previously collected configuration as lxml ElementTree root instance
or valid xml sting
:rtype: dictionary
:returns: facts
"""
if not HAS_LXML:
self._module.fail_json(msg='lxml is not installed.')
if not data:
config_filter = """
<configuration>
<protocols>
<lldp>
<interface>
</interface>
</lldp>
</protocols>
</configuration>
"""
data = get_resource_config(connection, config_filter=config_filter)
if isinstance(data, string_types):
data = etree.fromstring(to_bytes(data, errors='surrogate_then_replace'))
self._resources = data.xpath('configuration/protocols/lldp/interface')
objs = []
for resource in self._resources:
if resource is not None:
obj = self.render_config(self.generated_spec, resource)
if obj:
objs.append(obj)
facts = {}
if objs:
facts['lldp_interfaces'] = []
params = utils.validate_config(self.argument_spec, {'config': objs})
for cfg in params['config']:
facts['lldp_interfaces'].append(utils.remove_empties(cfg))
ansible_facts['ansible_network_resources'].update(facts)
return ansible_facts
def render_config(self, spec, conf):
"""
Render config as dictionary structure and delete keys
from spec for null values
:param spec: The facts tree, generated from the argspec
:param conf: The ElementTree instance of configuration object
:rtype: dictionary
:returns: The generated config
"""
config = deepcopy(spec)
config['name'] = utils.get_xml_conf_arg(conf, 'name')
if utils.get_xml_conf_arg(conf, 'disable', data='tag'):
config['enabled'] = False
return utils.remove_empties(config)

@ -1,152 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos static_routes fact class
It is in this file the configuration is collected from the device
for a given resource, parsed, and the facts tree is populated
based on the configuration.
"""
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from copy import deepcopy
from ansible.module_utils._text import to_bytes
from ansible.module_utils.network.common import utils
from ansible.module_utils.network.junos.argspec.static_routes.static_routes import Static_routesArgs
from ansible.module_utils.six import string_types
try:
from lxml import etree
HAS_LXML = True
except ImportError:
HAS_LXML = False
try:
import xmltodict
HAS_XMLTODICT = True
except ImportError:
HAS_XMLTODICT = False
class Static_routesFacts(object):
""" The junos static_routes fact class
"""
def __init__(self, module, subspec='config', options='options'):
self._module = module
self.argument_spec = Static_routesArgs.argument_spec
spec = deepcopy(self.argument_spec)
if subspec:
if options:
facts_argument_spec = spec[subspec][options]
else:
facts_argument_spec = spec[subspec]
else:
facts_argument_spec = spec
self.generated_spec = utils.generate_dict(facts_argument_spec)
def populate_facts(self, connection, ansible_facts, data=None):
""" Populate the facts for static_routes
:param connection: the device connection
:param ansible_facts: Facts dictionary
:param data: previously collected conf
:rtype: dictionary
:returns: facts
"""
if not HAS_LXML:
self._module.fail_json(msg='lxml is not installed.')
if not HAS_XMLTODICT:
self._module.fail_json(msg='xmltodict is not installed.')
if not data:
config_filter = """
<configuration>
<routing-instances/>
<routing-options/>
</configuration>
"""
data = connection.get_configuration(filter=config_filter)
if isinstance(data, string_types):
data = etree.fromstring(to_bytes(data,
errors='surrogate_then_replace'))
resources = data.xpath('configuration/routing-options')
vrf_resources = data.xpath('configuration/routing-instances')
resources.extend(vrf_resources)
objs = []
for resource in resources:
if resource is not None:
xml = self._get_xml_dict(resource)
obj = self.render_config(self.generated_spec, xml)
if obj:
objs.append(obj)
facts = {}
if objs:
facts['static_routes'] = []
params = utils.validate_config(self.argument_spec,
{'config': objs})
for cfg in params['config']:
facts['static_routes'].append(utils.remove_empties(cfg))
ansible_facts['ansible_network_resources'].update(facts)
return ansible_facts
def _get_xml_dict(self, xml_root):
xml_dict = xmltodict.parse(etree.tostring(xml_root), dict_constructor=dict)
return xml_dict
def _create_route_dict(self, afi, route_path):
routes_dict = {'afi': afi,
'routes': []}
if isinstance(route_path, dict):
route_path = [route_path]
for route in route_path:
route_dict = {}
route_dict['dest'] = route['name']
if route.get('metric'):
route_dict['metric'] = route['metric']['metric-value']
route_dict['next_hop'] = []
route_dict['next_hop'].append({'forward_router_address': route['next-hop']})
routes_dict['routes'].append(route_dict)
return routes_dict
def render_config(self, spec, conf):
"""
Render config as dictionary structure and delete keys
from spec for null values
:param spec: The facts tree, generated from the argspec
:param conf: The configuration
:rtype: dictionary
:returns: The generated config
"""
config = deepcopy(spec)
routes = []
config['address_families'] = []
if conf.get('routing-options'):
if conf['routing-options'].get('rib'):
if conf['routing-options'].get('rib').get('name') == 'inet6.0':
if conf['routing-options'].get('rib').get('static'):
route_path = conf['routing-options']['rib']['static'].get('route')
routes.append(self._create_route_dict('ipv6', route_path))
if conf['routing-options'].get('static'):
route_path = conf['routing-options']['static'].get('route')
routes.append(self._create_route_dict('ipv4', route_path))
if conf.get('routing-instances'):
config['vrf'] = conf['routing-instances']['instance']['name']
if conf['routing-instances'].get('instance').get('routing-options').get('rib').get('name') == config['vrf'] + '.inet6.0':
if conf['routing-instances']['instance']['routing-options']['rib'].get('static'):
route_path = conf['routing-instances']['instance']['routing-options']['rib']['static'].get('route')
routes.append(self._create_route_dict('ipv6', route_path))
if conf['routing-instances'].get('instance').get('routing-options').get('static'):
route_path = conf['routing-instances']['instance']['routing-options']['static'].get('route')
routes.append(self._create_route_dict('ipv4', route_path))
config['address_families'].extend(routes)
return utils.remove_empties(config)

@ -1,103 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The junos vlans fact class
It is in this file the configuration is collected from the device
for a given resource, parsed, and the facts tree is populated
based on the configuration.
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from copy import deepcopy
from ansible.module_utils._text import to_bytes
from ansible.module_utils.network.common import utils
from ansible.module_utils.network.junos.argspec.vlans.vlans import VlansArgs
from ansible.module_utils.network.junos.utils.utils import get_resource_config
from ansible.module_utils.six import string_types
try:
from lxml import etree
HAS_LXML = True
except ImportError:
HAS_LXML = False
class VlansFacts(object):
""" The junos vlans fact class
"""
def __init__(self, module, subspec='config', options='options'):
self._module = module
self.argument_spec = VlansArgs.argument_spec
spec = deepcopy(self.argument_spec)
if subspec:
if options:
facts_argument_spec = spec[subspec][options]
else:
facts_argument_spec = spec[subspec]
else:
facts_argument_spec = spec
self.generated_spec = utils.generate_dict(facts_argument_spec)
def populate_facts(self, connection, ansible_facts, data=None):
""" Populate the facts for vlans
:param connection: the device connection
:param ansible_facts: Facts dictionary
:param data: previously collected conf
:rtype: dictionary
:returns: facts
"""
if not HAS_LXML:
self._module.fail_json(msg='lxml is not installed.')
if not data:
config_filter = """
<configuration>
<vlans>
</vlans>
</configuration>
"""
data = get_resource_config(connection, config_filter=config_filter)
if isinstance(data, string_types):
data = etree.fromstring(to_bytes(data,
errors='surrogate_then_replace'))
resources = data.xpath('configuration/vlans/vlan')
objs = []
for resource in resources:
if resource is not None:
obj = self.render_config(self.generated_spec, resource)
if obj:
objs.append(obj)
facts = {}
if objs:
facts['vlans'] = []
params = utils.validate_config(self.argument_spec,
{'config': objs})
for cfg in params['config']:
facts['vlans'].append(utils.remove_empties(cfg))
ansible_facts['ansible_network_resources'].update(facts)
return ansible_facts
def render_config(self, spec, conf):
"""
Render config as dictionary structure and delete keys
from spec for null values
:param spec: The facts tree, generated from the argspec
:param conf: The configuration
:rtype: dictionary
:returns: The generated config
"""
config = deepcopy(spec)
config['name'] = utils.get_xml_conf_arg(conf, 'name')
config['vlan_id'] = utils.get_xml_conf_arg(conf, 'vlan-id')
config['description'] = utils.get_xml_conf_arg(conf, 'description')
return utils.remove_empties(config)

@ -1,465 +0,0 @@
#
# (c) 2017 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
import collections
import json
from contextlib import contextmanager
from copy import deepcopy
from ansible.module_utils.basic import env_fallback
from ansible.module_utils.connection import Connection, ConnectionError
from ansible.module_utils.network.common.netconf import NetconfConnection
from ansible.module_utils._text import to_text
try:
from lxml.etree import Element, SubElement, tostring as xml_to_string
HAS_LXML = True
except ImportError:
from xml.etree.ElementTree import Element, SubElement, tostring as xml_to_string
HAS_LXML = False
try:
from jnpr.junos import Device
from jnpr.junos.exception import ConnectError
HAS_PYEZ = True
except ImportError:
HAS_PYEZ = False
ACTIONS = frozenset(['merge', 'override', 'replace', 'update', 'set'])
JSON_ACTIONS = frozenset(['merge', 'override', 'update'])
FORMATS = frozenset(['xml', 'text', 'json'])
CONFIG_FORMATS = frozenset(['xml', 'text', 'json', 'set'])
junos_provider_spec = {
'host': dict(),
'port': dict(type='int'),
'username': dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
'password': dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True),
'ssh_keyfile': dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
'timeout': dict(type='int'),
'transport': dict(default='netconf', choices=['cli', 'netconf'])
}
junos_argument_spec = {
'provider': dict(type='dict', options=junos_provider_spec, removed_in_version=2.14),
}
def tostring(element, encoding='UTF-8'):
if HAS_LXML:
return xml_to_string(element, encoding='unicode')
else:
return to_text(xml_to_string(element, encoding), encoding=encoding)
def get_provider_argspec():
return junos_provider_spec
def get_connection(module):
if hasattr(module, '_junos_connection'):
return module._junos_connection
capabilities = get_capabilities(module)
network_api = capabilities.get('network_api')
if network_api == 'cliconf':
module._junos_connection = Connection(module._socket_path)
elif network_api == 'netconf':
module._junos_connection = NetconfConnection(module._socket_path)
else:
module.fail_json(msg='Invalid connection type %s' % network_api)
return module._junos_connection
def get_capabilities(module):
if hasattr(module, '_junos_capabilities'):
return module._junos_capabilities
try:
capabilities = Connection(module._socket_path).get_capabilities()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
module._junos_capabilities = json.loads(capabilities)
return module._junos_capabilities
def get_device(module):
provider = module.params.get("provider") or {}
host = provider.get('host')
kwargs = {
'port': provider.get('port') or 830,
'user': provider.get('username')
}
if 'password' in provider:
kwargs['passwd'] = provider.get('password')
if 'ssh_keyfile' in provider:
kwargs['ssh_private_key_file'] = provider.get('ssh_keyfile')
if module.params.get('ssh_config'):
kwargs['ssh_config'] = module.params['ssh_config']
if module.params.get('ssh_private_key_file'):
kwargs['ssh_private_key_file'] = module.params['ssh_private_key_file']
kwargs['gather_facts'] = False
try:
device = Device(host, **kwargs)
device.open()
device.timeout = provider.get('timeout') or 10
except ConnectError as exc:
module.fail_json('unable to connect to %s: %s' % (host, to_text(exc)))
return device
def is_netconf(module):
capabilities = get_capabilities(module)
return True if capabilities.get('network_api') == 'netconf' else False
def _validate_rollback_id(module, value):
try:
if not 0 <= int(value) <= 49:
raise ValueError
except ValueError:
module.fail_json(msg='rollback must be between 0 and 49')
def load_configuration(module, candidate=None, action='merge', rollback=None, format='xml'):
if all((candidate is None, rollback is None)):
module.fail_json(msg='one of candidate or rollback must be specified')
elif all((candidate is not None, rollback is not None)):
module.fail_json(msg='candidate and rollback are mutually exclusive')
if format not in FORMATS:
module.fail_json(msg='invalid format specified')
if format == 'json' and action not in JSON_ACTIONS:
module.fail_json(msg='invalid action for format json')
elif format in ('text', 'xml') and action not in ACTIONS:
module.fail_json(msg='invalid action format %s' % format)
if action == 'set' and format != 'text':
module.fail_json(msg='format must be text when action is set')
conn = get_connection(module)
try:
if rollback is not None:
_validate_rollback_id(module, rollback)
obj = Element('load-configuration', {'rollback': str(rollback)})
conn.execute_rpc(tostring(obj))
else:
return conn.load_configuration(config=candidate, action=action, format=format)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
def get_configuration(module, compare=False, format='xml', rollback='0', filter=None):
if format not in CONFIG_FORMATS:
module.fail_json(msg='invalid config format specified')
conn = get_connection(module)
try:
if compare:
xattrs = {'format': format}
_validate_rollback_id(module, rollback)
xattrs['compare'] = 'rollback'
xattrs['rollback'] = str(rollback)
reply = conn.execute_rpc(tostring(Element('get-configuration', xattrs)))
else:
reply = conn.get_configuration(format=format, filter=filter)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return reply
def commit_configuration(module, confirm=False, check=False, comment=None, confirm_timeout=None, synchronize=False, at_time=None):
conn = get_connection(module)
try:
if check:
reply = conn.validate()
else:
if is_netconf(module):
reply = conn.commit(confirmed=confirm, timeout=confirm_timeout, comment=comment, synchronize=synchronize, at_time=at_time)
else:
reply = conn.commit(comment=comment, confirmed=confirm, at_time=at_time, synchronize=synchronize)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return reply
def command(module, cmd, format='text', rpc_only=False):
conn = get_connection(module)
if rpc_only:
cmd += ' | display xml rpc'
try:
response = conn.command(command=cmd, format=format)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return response
def lock_configuration(module):
conn = get_connection(module)
try:
response = conn.lock()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return response
def unlock_configuration(module):
conn = get_connection(module)
try:
response = conn.unlock()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return response
@contextmanager
def locked_config(module):
try:
lock_configuration(module)
yield
finally:
unlock_configuration(module)
def discard_changes(module):
conn = get_connection(module)
try:
response = conn.discard_changes()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return response
def get_diff(module, rollback='0'):
reply = get_configuration(module, compare=True, format='text', rollback=rollback)
# 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='latin-1').strip()
def load_config(module, candidate, warnings, action='merge', format='xml'):
get_connection(module)
if not candidate:
return
if isinstance(candidate, list):
candidate = '\n'.join(candidate)
reply = load_configuration(module, candidate, action=action, format=format)
if isinstance(reply, list):
warnings.extend(reply)
module._junos_connection.validate()
return get_diff(module)
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
the xpath.
Acceptable metadata keys:
'value': Value of param.
'tag_only': Value is indicated by tag only in xml hierarchy.
'leaf_only': If operation is to be added at leaf node only.
'value_req': If value(text) is required for leaf node.
'is_key': If the field is key or not.
eg: Output
{
'name': [{'value': 'ge-0/0/1'}]
'disable': [{'value': True, tag_only': True}]
}
:param module:
: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 param:
is_attribute_dict = False
value = param[key]
if not isinstance(value, (list, tuple)):
value = [value]
if isinstance(attribute, dict):
xpath = attribute.get('xpath')
is_attribute_dict = True
else:
xpath = attribute
if not obj.get(xpath):
obj[xpath] = list()
for val in value:
if is_attribute_dict:
attr = deepcopy(attribute)
del attr['xpath']
attr.update({'value': val})
obj[xpath].append(attr)
else:
obj[xpath].append({'value': val})
return obj
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])
if len(top_ele) > 1:
for item in top_ele[1:-1]:
ele = SubElement(ele, item)
container = ele
state = param.get('state')
active = param.get('active')
if active:
oper = 'active'
else:
oper = 'inactive'
# build xml subtree
if container.tag != top_ele[-1]:
node = SubElement(container, top_ele[-1])
else:
node = container
for fxpath, attributes in want.items():
for attr in attributes:
tag_only = attr.get('tag_only', False)
leaf_only = attr.get('leaf_only', False)
value_req = attr.get('value_req', False)
is_key = attr.get('is_key', False)
parent_attrib = attr.get('parent_attrib', True)
value = attr.get('value')
field_top = attr.get('top')
# operation 'delete' is added as element attribute
# only if it is key or leaf only node
if state == 'absent' and not (is_key or leaf_only):
continue
# convert param value to device specific value
if value_map and fxpath in value_map:
value = value_map[fxpath].get(value)
if (value is not None) or tag_only or leaf_only:
ele = node
if field_top:
# eg: top = 'system/syslog/file'
# field_top = 'system/syslog/file/contents'
# <file>
# <name>test</name>
# <contents>
# </contents>
# </file>
ele_list = root.xpath(top + '/' + field_top)
if not len(ele_list):
fields = field_top.split('/')
ele = node
for item in fields:
inner_ele = root.xpath(top + '/' + item)
if len(inner_ele):
ele = inner_ele[0]
else:
ele = SubElement(ele, item)
else:
ele = ele_list[0]
if value is not None and not isinstance(value, bool):
value = to_text(value, errors='surrogate_then_replace')
if fxpath:
tags = fxpath.split('/')
for item in tags:
ele = SubElement(ele, item)
if tag_only:
if state == 'present':
if not value:
# if value of tag_only node is false, delete the node
ele.set('delete', 'delete')
elif leaf_only:
if state == 'present':
ele.set(oper, oper)
ele.text = value
else:
ele.set('delete', 'delete')
# Add value of leaf node if required while deleting.
# in some cases if value is present while deleting, it
# can result in error, hence the check
if value_req:
ele.text = value
if is_key:
par = ele.getparent()
par.set('delete', 'delete')
else:
ele.text = value
par = ele.getparent()
if parent_attrib:
if state == 'present':
# set replace attribute at parent node
if not par.attrib.get('replace'):
par.set('replace', 'replace')
# set active/inactive at parent node
if not par.attrib.get(oper):
par.set(oper, oper)
else:
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]

@ -1,28 +0,0 @@
#
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# utils
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.network.junos.junos import tostring
try:
from ncclient.xml_ import new_ele, to_ele
HAS_NCCLIENT = True
except ImportError:
HAS_NCCLIENT = False
def get_resource_config(connection, config_filter=None, attrib=None):
if attrib is None:
attrib = {'inherit': 'inherit'}
get_ele = new_ele('get-configuration', attrib)
if config_filter:
get_ele.append(to_ele(config_filter))
return connection.execute_rpc(tostring(get_ele))

@ -1,392 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['deprecated'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_interface
version_added: "2.4"
author: "Ganesh Nalawade (@ganeshrn)"
short_description: Manage Interface on Juniper JUNOS network devices
description:
- This module provides declarative management of Interfaces
on Juniper JUNOS network devices.
deprecated:
removed_in: "2.13"
why: Updated modules released with more functionality
alternative: Use M(junos_interfaces) instead.
options:
name:
description:
- Name of the Interface.
required: true
description:
description:
- Description of Interface.
enabled:
description:
- Configure interface link status.
type: bool
speed:
description:
- Interface link speed.
mtu:
description:
- Maximum size of transmit packet.
duplex:
description:
- Interface link status.
default: auto
choices: ['full', 'half', 'auto']
tx_rate:
description:
- Transmit rate in bits per second (bps).
- This is state check parameter only.
- Supports conditionals, see L(Conditionals in Networking Modules,../network/user_guide/network_working_with_command_output.html)
rx_rate:
description:
- Receiver rate in bits per second (bps).
- This is state check parameter only.
- Supports conditionals, see L(Conditionals in Networking Modules,../network/user_guide/network_working_with_command_output.html)
neighbors:
description:
- Check the operational state of given interface C(name) for LLDP neighbor.
- The following suboptions are available.
suboptions:
host:
description:
- "LLDP neighbor host for given interface C(name)."
port:
description:
- "LLDP neighbor port to which given interface C(name) is connected."
delay:
description:
- Time in seconds to wait before checking for the operational state on remote
device. This wait is applicable for operational state argument which are
I(state) with values C(up)/C(down), I(tx_rate) and I(rx_rate).
default: 10
aggregate:
description: List of Interfaces definitions.
state:
description:
- 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']
active:
description:
- Specifies whether or not the configuration is active or deactivated
default: True
type: bool
requirements:
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
extends_documentation_fragment: junos
"""
EXAMPLES = """
- name: configure interface
junos_interface:
name: ge-0/0/1
description: test-interface
- name: remove interface
junos_interface:
name: ge-0/0/1
state: absent
- name: make interface down
junos_interface:
name: ge-0/0/1
enabled: False
- name: make interface up
junos_interface:
name: ge-0/0/1
enabled: True
- name: Deactivate interface config
junos_interface:
name: ge-0/0/1
state: present
active: False
- name: Activate interface config
net_interface:
name: ge-0/0/1
state: present
active: True
- name: Configure interface speed, mtu, duplex
junos_interface:
name: ge-0/0/1
state: present
speed: 1g
mtu: 256
duplex: full
- name: Create interface using aggregate
junos_interface:
aggregate:
- name: ge-0/0/1
description: test-interface-1
- name: ge-0/0/2
description: test-interface-2
speed: 1g
duplex: full
mtu: 512
- name: Delete interface using aggregate
junos_interface:
aggregate:
- name: ge-0/0/1
- name: ge-0/0/2
state: absent
- name: Check intent arguments
junos_interface:
name: "{{ name }}"
state: up
tx_rate: ge(0)
rx_rate: le(0)
- name: Check neighbor intent
junos_interface:
name: xe-0/1/1
neighbors:
- port: Ethernet1/0/1
host: netdev
- name: Config + intent
junos_interface:
name: "{{ name }}"
enabled: False
state: down
"""
RETURN = """
diff.prepared:
description: Configuration difference before and after applying change.
returned: when configuration is changed and diff option is enabled.
type: str
sample: >
[edit interfaces]
+ ge-0/0/1 {
+ description test-interface;
+ }
"""
import collections
from copy import deepcopy
from time import sleep
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.common.netconf import exec_rpc
from ansible.module_utils.network.common.utils import remove_default_spec
from ansible.module_utils.network.common.utils import conditional
from ansible.module_utils.network.junos.junos import junos_argument_spec, tostring
from ansible.module_utils.network.junos.junos import load_config, map_params_to_obj, map_obj_to_ele
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes, locked_config, to_param_list
try:
from lxml.etree import Element, SubElement
except ImportError:
from xml.etree.ElementTree import Element, SubElement
USE_PERSISTENT_CONNECTION = True
def validate_mtu(value, module):
if value and not 256 <= value <= 9192:
module.fail_json(msg='mtu must be between 256 and 9192')
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(param.get(key), module)
def main():
""" main entry point for module execution
"""
neighbors_spec = dict(
host=dict(),
port=dict()
)
element_spec = dict(
name=dict(),
description=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(),
neighbors=dict(type='list', elements='dict', options=neighbors_spec),
delay=dict(default=10, type='int'),
state=dict(default='present', choices=['present', 'absent', 'up', 'down']),
active=dict(default=True, type='bool')
)
aggregate_spec = deepcopy(element_spec)
aggregate_spec['name'] = dict(required=True)
# remove default in aggregate spec, to handle common arguments
remove_default_spec(aggregate_spec)
argument_spec = dict(
aggregate=dict(type='list', elements='dict', options=aggregate_spec),
)
argument_spec.update(element_spec)
argument_spec.update(junos_argument_spec)
required_one_of = [['name', 'aggregate']]
mutually_exclusive = [['name', 'aggregate']]
module = AnsibleModule(argument_spec=argument_spec,
required_one_of=required_one_of,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True)
warnings = list()
result = {'changed': False}
if warnings:
result['warnings'] = warnings
top = 'interfaces/interface'
param_to_xpath_map = collections.OrderedDict()
param_to_xpath_map.update([
('name', {'xpath': 'name', 'is_key': True}),
('description', 'description'),
('speed', 'speed'),
('mtu', 'mtu'),
('duplex', 'link-mode'),
('disable', {'xpath': 'disable', 'tag_only': True})
])
choice_to_value_map = {
'link-mode': {'full': 'full-duplex', 'half': 'half-duplex', 'auto': 'automatic'}
}
params = to_param_list(module)
requests = list()
for param in params:
# if key doesn't exist in the item, get it from module.params
for key in param:
if param.get(key) is None:
param[key] = module.params[key]
item = param.copy()
state = item.get('state')
item['disable'] = True if not item.get('enabled') else False
if state in ('present', 'up', 'down'):
item['state'] = 'present'
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):
for req in requests:
diff = load_config(module, tostring(req), warnings, action='merge')
# issue commit after last configuration change is done
commit = not module.check_mode
if diff:
if commit:
commit_configuration(module)
else:
discard_changes(module)
result['changed'] = True
if module._diff:
result['diff'] = {'prepared': diff}
failed_conditions = []
neighbors = None
for item in params:
state = item.get('state')
tx_rate = item.get('tx_rate')
rx_rate = item.get('rx_rate')
want_neighbors = item.get('neighbors')
if state not in ('up', 'down') and tx_rate is None and rx_rate is None and want_neighbors 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 = exec_rpc(module, tostring(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 want_neighbors:
if neighbors is None:
element = Element('get-lldp-interface-neighbors')
intf_name = SubElement(element, 'interface-device')
intf_name.text = item.get('name')
reply = exec_rpc(module, tostring(element), ignore_warning=False)
have_host = [item.text for item in reply.xpath('lldp-neighbors-information/lldp-neighbor-information/lldp-remote-system-name')]
have_port = [item.text for item in reply.xpath('lldp-neighbors-information/lldp-neighbor-information/lldp-remote-port-id')]
for neighbor in want_neighbors:
host = neighbor.get('host')
port = neighbor.get('port')
if host and host not in have_host:
failed_conditions.append('host ' + host)
if port and port not in have_port:
failed_conditions.append('port ' + port)
if failed_conditions:
msg = 'One or more conditional statements have not been satisfied'
module.fail_json(msg=msg, failed_conditions=failed_conditions)
module.exit_json(**result)
if __name__ == "__main__":
main()

@ -1,287 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['deprecated'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_l2_interface
version_added: "2.5"
author: "Ganesh Nalawade (@ganeshrn)"
short_description: Manage Layer-2 interface on Juniper JUNOS network devices
description:
- This module provides declarative management of Layer-2 interface
on Juniper JUNOS network devices.
deprecated:
removed_in: "2.13"
why: Updated modules released with more functionality
alternative: Use M(junos_l2_interfaces) instead.
options:
name:
description:
- Name of the interface excluding any logical unit number.
description:
description:
- Description of Interface.
aggregate:
description:
- List of Layer-2 interface definitions.
mode:
description:
- Mode in which interface needs to be configured.
choices: ['access', 'trunk']
access_vlan:
description:
- Configure given VLAN in access port. The value of C(access_vlan) should
be vlan name.
trunk_vlans:
description:
- List of VLAN names to be configured in trunk port. The value of C(trunk_vlans) should
be list of vlan names.
native_vlan:
description:
- Native VLAN to be configured in trunk port. The value of C(native_vlan)
should be vlan id.
enhanced_layer:
description:
- True if your device has Enhanced Layer 2 Software (ELS).
default: True
type: bool
version_added: "2.7"
unit:
description:
- Logical interface number. Value of C(unit) should be of type
integer.
default: 0
filter_input:
description:
- The name of input filter of ethernet-switching.
version_added: "2.8"
filter_output:
description:
- The name of output filter of ethernet-switching.
version_added: "2.8"
state:
description:
- State of the Layer-2 Interface configuration.
default: present
choices: ['present', 'absent',]
active:
description:
- Specifies whether or not the configuration is active or deactivated
default: True
type: bool
requirements:
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
extends_documentation_fragment: junos
"""
EXAMPLES = """
- name: Configure interface in access mode
junos_l2_interface:
name: ge-0/0/1
description: interface-access
mode: access
access_vlan: red
active: True
state: present
- name: Configure interface in trunk mode
junos_l2_interface:
name: ge-0/0/1
description: interface-trunk
mode: trunk
trunk_vlans:
- blue
- green
native_vlan: 100
active: True
state: present
- name: Configure interface in access and trunk mode using aggregate
junos_l2_interface:
aggregate:
- name: ge-0/0/1
description: test-interface-access
mode: access
access_vlan: red
- name: ge-0/0/2
description: test-interface-trunk
mode: trunk
trunk_vlans:
- blue
- green
native_vlan: 100
active: True
state: present
"""
RETURN = """
diff:
description: Configuration difference before and after applying change.
returned: when configuration is changed and diff option is enabled.
type: str
sample: >
[edit interfaces]
+ ge-0/0/1 {
+ description "l2 interface configured by Ansible";
+ unit 0 {
+ family ethernet-switching {
+ interface-mode access;
+ vlan {
+ members red;
+ }
+ }
+ }
+ }
"""
import collections
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.common.utils import remove_default_spec
from ansible.module_utils.network.junos.junos import junos_argument_spec, tostring
from ansible.module_utils.network.junos.junos import load_config, map_params_to_obj, map_obj_to_ele
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes, locked_config, to_param_list
USE_PERSISTENT_CONNECTION = True
def validate_vlan_id(value, module):
if value and not 0 <= value <= 4094:
module.fail_json(msg='vlan_id must be between 1 and 4094')
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(param.get(key), module)
def main():
""" main entry point for module execution
"""
element_spec = dict(
name=dict(),
mode=dict(choices=['access', 'trunk']),
access_vlan=dict(),
native_vlan=dict(type='int'),
trunk_vlans=dict(type='list'),
unit=dict(default=0, type='int'),
filter_input=dict(),
filter_output=dict(),
description=dict(),
enhanced_layer=dict(default=True, type='bool'),
state=dict(default='present', choices=['present', 'absent']),
active=dict(default=True, type='bool')
)
aggregate_spec = deepcopy(element_spec)
aggregate_spec['name'] = dict(required=True)
# remove default in aggregate spec, to handle common arguments
remove_default_spec(aggregate_spec)
required_one_of = [['name', 'aggregate']]
mutually_exclusive = [['name', 'aggregate'],
['access_vlan', 'trunk_vlans'],
['access_vlan', 'native_vlan']]
required_if = [('mode', 'access', ('access_vlan',)),
('mode', 'trunk', ('trunk_vlans',))]
argument_spec = dict(
aggregate=dict(type='list', elements='dict', options=aggregate_spec, mutually_exclusive=mutually_exclusive, required_if=required_if),
)
argument_spec.update(element_spec)
argument_spec.update(junos_argument_spec)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True,
mutually_exclusive=mutually_exclusive,
required_one_of=required_one_of,
required_if=required_if)
warnings = list()
result = {'changed': False}
if warnings:
result['warnings'] = warnings
top = 'interfaces/interface'
param_to_xpath_map = collections.OrderedDict()
param_to_xpath_map.update([
('name', {'xpath': 'name', 'is_key': True}),
('unit', {'xpath': 'name', 'top': 'unit', 'is_key': True}),
('mode', {'xpath': 'interface-mode', 'top': 'unit/family/ethernet-switching'}),
('access_vlan', {'xpath': 'members', 'top': 'unit/family/ethernet-switching/vlan'}),
('trunk_vlans', {'xpath': 'members', 'top': 'unit/family/ethernet-switching/vlan'}),
('filter_input', {'xpath': 'input', 'top': 'unit/family/ethernet-switching/filter'}),
('filter_output', {'xpath': 'output', 'top': 'unit/family/ethernet-switching/filter'}),
('native_vlan', {'xpath': 'native-vlan-id'}),
('description', 'description')
])
params = to_param_list(module)
requests = list()
for param in params:
# if key doesn't exist in the item, get it from module.params
for key in param:
if param.get(key) is None:
param[key] = module.params[key]
item = param.copy()
validate_param_values(module, param_to_xpath_map, param=item)
param_to_xpath_map['mode']['xpath'] = \
'interface-mode' if param['enhanced_layer'] else 'port-mode'
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):
for req in requests:
diff = load_config(module, tostring(req), warnings, action='replace')
commit = not module.check_mode
if diff:
if commit:
commit_configuration(module)
else:
discard_changes(module)
result['changed'] = True
if module._diff:
result['diff'] = {'prepared': diff}
module.exit_json(**result)
if __name__ == "__main__":
main()

@ -1,229 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['deprecated'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_l3_interface
version_added: "2.4"
author: "Ganesh Nalawade (@ganeshrn)"
short_description: Manage L3 interfaces on Juniper JUNOS network devices
description:
- This module provides declarative management of L3 interfaces
on Juniper JUNOS network devices.
deprecated:
removed_in: "2.13"
why: Updated modules released with more functionality
alternative: Use M(junos_l3_interfaces) instead.
options:
name:
description:
- Name of the L3 interface.
ipv4:
description:
- IPv4 of the L3 interface.
ipv6:
description:
- IPv6 of the L3 interface.
unit:
description:
- Logical interface number.
default: 0
filter_input:
description:
- The name of input filter.
version_added: "2.8"
filter_output:
description:
- The name of output filter.
version_added: "2.8"
filter6_input:
description:
- The name of input filter for ipv6.
version_added: "2.8"
filter6_output:
description:
- The name of output filter for ipv6.
version_added: "2.8"
aggregate:
description: List of L3 interfaces definitions
state:
description:
- State of the L3 interface configuration.
default: present
choices: ['present', 'absent']
active:
description:
- Specifies whether or not the configuration is active or deactivated
default: True
type: bool
requirements:
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
extends_documentation_fragment: junos
"""
EXAMPLES = """
- name: Set ge-0/0/1 IPv4 address
junos_l3_interface:
name: ge-0/0/1
ipv4: 192.168.0.1
- name: Remove ge-0/0/1 IPv4 address
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: 192.0.2.1
- name: ge-0/0/2
ipv4: 192.0.2.2
ipv6: fd5d:12c9:2201:2::2
- name: Delete ipv4 address using aggregate
junos_l3_interface:
aggregate:
- name: ge-0/0/1
ipv4: 192.0.2.1
- name: ge-0/0/2
ipv4: 192.0.2.2
state: absent
"""
RETURN = """
diff:
description: Configuration difference before and after applying change.
returned: when configuration is changed and diff option is enabled.
type: str
sample: >
[edit interfaces ge-0/0/1 unit 0 family inet]
+ address 192.0.2.1/32;
[edit interfaces ge-0/0/1 unit 0 family inet6]
+ address fd5d:12c9:2201:1::1/128;
"""
import collections
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.common.utils import remove_default_spec
from ansible.module_utils.network.junos.junos import junos_argument_spec, tostring
from ansible.module_utils.network.junos.junos import load_config, map_params_to_obj, map_obj_to_ele
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes, locked_config, to_param_list
USE_PERSISTENT_CONNECTION = True
def main():
""" main entry point for module execution
"""
element_spec = dict(
name=dict(),
ipv4=dict(),
ipv6=dict(),
filter_input=dict(),
filter_output=dict(),
filter6_input=dict(),
filter6_output=dict(),
unit=dict(default=0, type='int'),
state=dict(default='present', choices=['present', 'absent']),
active=dict(default=True, type='bool')
)
aggregate_spec = deepcopy(element_spec)
aggregate_spec['name'] = dict(required=True)
# remove default in aggregate spec, to handle common arguments
remove_default_spec(aggregate_spec)
argument_spec = dict(
aggregate=dict(type='list', elements='dict', options=aggregate_spec),
)
argument_spec.update(element_spec)
argument_spec.update(junos_argument_spec)
required_one_of = [['name', 'aggregate']]
mutually_exclusive = [['name', 'aggregate']]
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True,
mutually_exclusive=mutually_exclusive,
required_one_of=required_one_of)
warnings = list()
result = {'changed': False}
if warnings:
result['warnings'] = warnings
top = 'interfaces/interface'
param_to_xpath_map = collections.OrderedDict()
param_to_xpath_map.update([
('name', {'xpath': 'name', 'parent_attrib': False, 'is_key': True}),
('unit', {'xpath': 'name', 'top': 'unit', 'parent_attrib': False, 'is_key': True}),
('ipv4', {'xpath': 'inet/address/name', 'top': 'unit/family', 'is_key': True}),
('ipv6', {'xpath': 'inet6/address/name', 'top': 'unit/family', 'is_key': True}),
('filter_input', {'xpath': 'inet/filter/input', 'top': 'unit/family'}),
('filter_output', {'xpath': 'inet/filter/output', 'top': 'unit/family'}),
('filter6_input', {'xpath': 'inet6/filter/input', 'top': 'unit/family'}),
('filter6_output', {'xpath': 'inet6/filter/output', 'top': 'unit/family'}),
])
params = to_param_list(module)
requests = list()
for param in params:
# if key doesn't exist in the item, get it from module.params
for key in param:
if param.get(key) is None:
param[key] = module.params[key]
item = param.copy()
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):
for req in requests:
diff = load_config(module, tostring(req), warnings, action='merge')
commit = not module.check_mode
if diff:
if commit:
commit_configuration(module)
else:
discard_changes(module)
result['changed'] = True
if module._diff:
result['diff'] = {'prepared': diff}
module.exit_json(**result)
if __name__ == "__main__":
main()

@ -1,347 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['deprecated'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_linkagg
version_added: "2.4"
author: "Ganesh Nalawade (@ganeshrn)"
short_description: Manage link aggregation groups on Juniper JUNOS network devices
description:
- This module provides declarative management of link aggregation groups
on Juniper JUNOS network devices.
deprecated:
removed_in: "2.13"
why: Updated modules released with more functionality
alternative: Use M(junos_lag_interfaces) instead.
options:
name:
description:
- Name of the link aggregation group.
required: true
mode:
description:
- Mode of the link aggregation group. A value of C(on) will enable LACP in C(passive) mode.
C(active) configures the link to actively information about the state of the link,
or it can be configured in C(passive) mode ie. send link state information only when
received them from another link. A value of C(off) will disable LACP.
default: off
choices: ['on', 'off', 'active', 'passive']
members:
description:
- List of members interfaces of the link aggregation group. The value can be
single interface or list of interfaces.
required: true
min_links:
description:
- Minimum members that should be up
before bringing up the link aggregation group.
device_count:
description:
- Number of aggregated ethernet devices that can be configured.
Acceptable integer value is between 1 and 128.
description:
description:
- Description of Interface.
aggregate:
description: List of link aggregation definitions.
state:
description:
- State of the link aggregation group.
default: present
choices: ['present', 'absent', 'up', 'down']
active:
description:
- Specifies whether or not the configuration is active or deactivated
default: True
type: bool
requirements:
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
extends_documentation_fragment: junos
"""
EXAMPLES = """
- name: configure link aggregation
junos_linkagg:
name: ae11
members:
- ge-0/0/5
- ge-0/0/6
- ge-0/0/7
lacp: active
device_count: 4
state: present
- name: delete link aggregation
junos_linkagg:
name: ae11
members:
- ge-0/0/5
- ge-0/0/6
- ge-0/0/7
lacp: active
device_count: 4
state: delete
- name: deactivate link aggregation
junos_linkagg:
name: ae11
members:
- ge-0/0/5
- ge-0/0/6
- ge-0/0/7
lacp: active
device_count: 4
state: present
active: False
- name: Activate link aggregation
junos_linkagg:
name: ae11
members:
- ge-0/0/5
- ge-0/0/6
- ge-0/0/7
lacp: active
device_count: 4
state: present
active: True
- name: Disable link aggregation
junos_linkagg:
name: ae11
state: down
- name: Enable link aggregation
junos_linkagg:
name: ae11
state: up
"""
RETURN = """
diff:
description: Configuration difference before and after applying change.
returned: when configuration is changed and diff option is enabled.
type: str
sample: >
[edit interfaces]
+ ge-0/0/6 {
+ ether-options {
+ 802.3ad ae0;
+ }
+ }
[edit interfaces ge-0/0/7]
+ ether-options {
+ 802.3ad ae0;
+ }
[edit interfaces]
+ ae0 {
+ description "configured by junos_linkagg";
+ aggregated-ether-options {
+ lacp {
+ active;
+ }
+ }
+ }
"""
import collections
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.common.utils import remove_default_spec
from ansible.module_utils.network.junos.junos import junos_argument_spec, tostring
from ansible.module_utils.network.junos.junos import load_config, map_params_to_obj, map_obj_to_ele, to_param_list
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes, locked_config, get_configuration
USE_PERSISTENT_CONNECTION = True
def validate_device_count(value, module):
if value and not 1 <= value <= 128:
module.fail_json(msg='device_count must be between 1 and 128')
def validate_min_links(value, module):
if value and not 1 <= value <= 8:
module.fail_json(msg='min_links must be between 1 and 8')
def validate_param_values(module, obj, item):
for key in obj:
# validate the param value (if validator func exists)
validator = globals().get('validate_%s' % key)
if callable(validator):
validator(item.get(key), module)
def configure_lag_params(module, requests, item):
top = 'interfaces/interface'
param_lag_to_xpath_map = collections.OrderedDict()
param_lag_to_xpath_map.update([
('name', {'xpath': 'name', 'is_key': True}),
('description', 'description'),
('min_links', {'xpath': 'minimum-links', 'top': 'aggregated-ether-options'}),
('disable', {'xpath': 'disable', 'tag_only': True}),
('mode', {'xpath': item['mode'], 'tag_only': True, 'top': 'aggregated-ether-options/lacp'}),
])
validate_param_values(module, param_lag_to_xpath_map, item)
want = map_params_to_obj(module, param_lag_to_xpath_map, param=item)
ele = map_obj_to_ele(module, want, top, param=item)
requests.append(ele)
if item['device_count']:
top = 'chassis/aggregated-devices/ethernet'
device_count_to_xpath_map = {'device_count': {'xpath': 'device-count', 'leaf_only': True}}
validate_param_values(module, device_count_to_xpath_map, item)
want = map_params_to_obj(module, device_count_to_xpath_map, param=item)
ele = map_obj_to_ele(module, want, top, param=item)
requests.append(ele)
def configure_member_params(module, requests, item):
top = 'interfaces/interface'
members = item['members']
if members:
member_to_xpath_map = collections.OrderedDict()
member_to_xpath_map.update([
('name', {'xpath': 'name', 'is_key': True, 'parent_attrib': False}),
('bundle', {'xpath': 'bundle', 'leaf_only': True, 'top': 'ether-options/ieee-802.3ad', 'is_key': True}),
])
# link aggregation bundle assigned to member
item['bundle'] = item['name']
for member in members:
if item['state'] == 'absent':
# if link aggregate bundle is not assigned to member, trying to
# delete it results in rpc-reply error, hence if is not assigned
# skip deleting it and continue to next member.
resp = get_configuration(module)
bundle = resp.xpath("configuration/interfaces/interface[name='%s']/ether-options/"
"ieee-802.3ad[bundle='%s']" % (member, item['bundle']))
if not bundle:
continue
# Name of member to be assigned to link aggregation bundle
item['name'] = member
validate_param_values(module, member_to_xpath_map, item)
want = map_params_to_obj(module, member_to_xpath_map, param=item)
ele = map_obj_to_ele(module, want, top, param=item)
requests.append(ele)
def main():
""" main entry point for module execution
"""
element_spec = dict(
name=dict(),
mode=dict(default='on', choices=['on', 'off', 'active', 'passive']),
members=dict(type='list'),
min_links=dict(type='int'),
device_count=dict(type='int'),
description=dict(),
state=dict(default='present', choices=['present', 'absent', 'up', 'down']),
active=dict(default=True, type='bool')
)
aggregate_spec = deepcopy(element_spec)
aggregate_spec['name'] = dict(required=True)
# remove default in aggregate spec, to handle common arguments
remove_default_spec(aggregate_spec)
argument_spec = dict(
aggregate=dict(type='list', elements='dict', options=aggregate_spec),
)
argument_spec.update(element_spec)
argument_spec.update(junos_argument_spec)
required_one_of = [['name', 'aggregate']]
mutually_exclusive = [['name', 'aggregate']]
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True,
required_one_of=required_one_of,
mutually_exclusive=mutually_exclusive)
warnings = list()
result = {'changed': False}
if warnings:
result['warnings'] = warnings
params = to_param_list(module)
requests = list()
for param in params:
# if key doesn't exist in the item, get it from module.params
for key in param:
if param.get(key) is None:
param[key] = module.params[key]
item = param.copy()
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
mode = item.get('mode')
if mode == 'off':
item['mode'] = ''
elif mode == 'on':
item['mode'] = 'passive'
configure_lag_params(module, requests, item)
configure_member_params(module, requests, item)
diff = None
with locked_config(module):
for req in requests:
diff = load_config(module, tostring(req), warnings, action='merge')
commit = not module.check_mode
if diff:
if commit:
commit_configuration(module)
else:
discard_changes(module)
result['changed'] = True
if module._diff:
result['diff'] = {'prepared': diff}
module.exit_json(**result)
if __name__ == "__main__":
main()

@ -1,199 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['deprecated'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_lldp
version_added: "2.4"
author: "Ganesh Nalawade (@ganeshrn)"
short_description: Manage LLDP configuration on Juniper JUNOS network devices
description:
- This module provides declarative management of LLDP service
on Juniper JUNOS network devices.
deprecated:
removed_in: "2.13"
why: Updated modules released with more functionality
alternative: Use M(junos_lldp_global) instead.
options:
interval:
description:
- Frequency at which LLDP advertisements are sent (in seconds).
transmit_delay:
description:
- Specify the number of seconds the device waits before sending
advertisements to neighbors after a change is made in local system.
hold_multiplier:
description:
- Specify the number of seconds that LLDP information is held before it is
discarded. The multiplier value is used in combination with the
C(interval) value.
state:
description:
- Value of C(present) ensures given LLDP configuration
is present on device and LLDP is enabled, for value of C(absent)
LLDP configuration is deleted and LLDP is in disabled state.
Value C(enabled) ensures LLDP protocol is enabled and LLDP configuration
if any is configured on remote device, for value of C(disabled) it ensures
LLDP protocol is disabled any LLDP configuration if any is still present.
default: present
choices: ['present', 'absent', 'enabled', 'disabled']
active:
description:
- Specifies whether or not the configuration is active or deactivated
default: True
type: bool
requirements:
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
extends_documentation_fragment: junos
"""
EXAMPLES = """
- name: Enable LLDP service
junos_lldp:
state: enabled
- name: Disable LLDP service
junos_lldp:
state: disabled
- name: Set LLDP parameters
junos_lldp:
interval: 10
hold_multiplier: 5
transmit_delay: 30
state: present
- name: Delete LLDP parameters
junos_lldp:
interval: 10
hold_multiplier: 5
transmit_delay: 30
state: absent
"""
RETURN = """
diff.prepared:
description: Configuration difference before and after applying change.
returned: when configuration is changed and diff option is enabled.
type: str
sample: >
[edit]
+ protocols {
+ lldp {
+ disable;
+ }
+ }
"""
import collections
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.junos import junos_argument_spec, tostring
from ansible.module_utils.network.junos.junos import load_config, map_params_to_obj, map_obj_to_ele
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes, locked_config
USE_PERSISTENT_CONNECTION = True
def validate_interval(value, module):
if not 5 <= value <= 32768:
module.fail_json(msg='interval must be between 5 and 32768')
def validate_hold_multiplier(value, module):
if not 5 <= value <= 32768:
module.fail_json(msg='hold_multiplier must be between 2 and 10')
def validate_transmit_delay(value, module):
if not 1 <= value <= 8192:
module.fail_json(msg='transmit_delay must be between 2 and 10')
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(
interval=dict(type='int'),
transmit_delay=dict(type='int'),
hold_multiplier=dict(type='int'),
state=dict(default='present', choices=['present', 'absent', 'enabled', 'disabled']),
active=dict(default=True, type='bool')
)
argument_spec.update(junos_argument_spec)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
warnings = list()
result = {'changed': False}
if warnings:
result['warnings'] = warnings
top = 'protocols/lldp'
param_to_xpath_map = collections.OrderedDict()
param_to_xpath_map.update([
('interval', {'xpath': 'advertisement-interval', 'leaf_only': True}),
('transmit_delay', {'xpath': 'transmit-delay', 'leaf_only': True}),
('hold_multiplier', {'xpath': 'hold-multiplier', 'leaf_only': True}),
('disable', {'xpath': 'disable', 'tag_only': True, 'is_key': True})
])
item = module.params.copy()
state = item.get('state')
item['disable'] = True if state in ('disabled', 'absent') else False
if state in ('enabled', 'disabled'):
item['state'] = 'present'
want = map_params_to_obj(module, param_to_xpath_map, param=item)
ele = map_obj_to_ele(module, want, top, param=item)
with locked_config(module):
diff = load_config(module, tostring(ele), warnings, action='merge')
commit = not module.check_mode
if diff:
if commit:
commit_configuration(module)
else:
discard_changes(module)
result['changed'] = True
if module._diff:
result['diff'] = {'prepared': diff}
module.exit_json(**result)
if __name__ == "__main__":
main()

@ -1,166 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['deprecated'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_lldp_interface
version_added: "2.4"
author: "Ganesh Nalawade (@ganeshrn)"
short_description: Manage LLDP interfaces configuration on Juniper JUNOS network devices
description:
- This module provides declarative management of LLDP interfaces
configuration on Juniper JUNOS network devices.
deprecated:
removed_in: "2.13"
why: Updated modules released with more functionality
alternative: Use M(junos_lldp_interfaces) instead.
options:
name:
description:
- Name of the interface LLDP should be configured on.
state:
description:
- Value of C(present) ensures given LLDP configured on given I(interfaces)
and is enabled, for value of C(absent) LLDP configuration on given I(interfaces) deleted.
Value C(enabled) ensures LLDP protocol is enabled on given I(interfaces) and
for value of C(disabled) it ensures LLDP is disabled on given I(interfaces).
default: present
choices: ['present', 'absent', 'enabled', 'disabled']
active:
description:
- Specifies whether or not the configuration is active or deactivated
default: True
type: bool
requirements:
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
extends_documentation_fragment: junos
"""
EXAMPLES = """
- name: Configure LLDP on specific interfaces
junos_lldp_interface:
name: ge-0/0/5
state: present
- name: Disable LLDP on specific interfaces
junos_lldp_interface:
name: ge-0/0/5
state: disabled
- name: Enable LLDP on specific interfaces
junos_lldp_interface:
name: ge-0/0/5
state: enabled
- name: Delete LLDP configuration on specific interfaces
junos_lldp_interface:
name: ge-0/0/5
state: present
- name: Deactivate LLDP on specific interfaces
junos_lldp_interface:
name: ge-0/0/5
state: present
active: False
- name: Activate LLDP on specific interfaces
junos_lldp_interface:
name: ge-0/0/5
state: present
active: True
"""
RETURN = """
diff.prepared:
description: Configuration difference before and after applying change.
returned: when configuration is changed and diff option is enabled.
type: str
sample: >
[edit protocols lldp]
+ interface ge-0/0/5;
"""
import collections
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.junos import junos_argument_spec
from ansible.module_utils.network.junos.junos import load_config, map_params_to_obj, map_obj_to_ele, tostring
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes, locked_config
USE_PERSISTENT_CONNECTION = True
def main():
""" main entry point for module execution
"""
argument_spec = dict(
name=dict(),
state=dict(default='present', choices=['present', 'absent', 'enabled', 'disabled']),
active=dict(default=True, type='bool')
)
argument_spec.update(junos_argument_spec)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
warnings = list()
result = {'changed': False}
if warnings:
result['warnings'] = warnings
top = 'protocols/lldp/interface'
param_to_xpath_map = collections.OrderedDict()
param_to_xpath_map.update([
('name', {'xpath': 'name', 'is_key': True}),
('disable', {'xpath': 'disable', 'tag_only': True})
])
item = module.params.copy()
state = item.get('state')
item['disable'] = True if state in ('disabled', 'absent') else False
if state in ('enabled', 'disabled'):
item['state'] = 'present'
want = map_params_to_obj(module, param_to_xpath_map, param=item)
ele = map_obj_to_ele(module, want, top, param=item)
with locked_config(module):
diff = load_config(module, tostring(ele), warnings, action='merge')
commit = not module.check_mode
if diff:
if commit:
commit_configuration(module)
else:
discard_changes(module)
result['changed'] = True
if module._diff:
result['diff'] = {'prepared': diff}
module.exit_json(**result)
if __name__ == "__main__":
main()

@ -1,240 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['deprecated'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_static_route
version_added: "2.4"
author: "Ganesh Nalawade (@ganeshrn)"
short_description: Manage static IP routes on Juniper JUNOS network devices
description:
- This module provides declarative management of static
IP routes on Juniper JUNOS network devices.
deprecated:
removed_in: "2.13"
why: Updated modules released with more functionality
alternative: Use M(junos_static_routes) instead.
options:
address:
description:
- Network address with prefix of the static route.
required: true
aliases: ['prefix']
next_hop:
description:
- Next hop IP of the static route.
required: true
qualified_next_hop:
description:
- Qualified next hop IP of the static route. Qualified next hops allow
to associate preference with a particular next-hop address.
preference:
description:
- Global admin preference of the static route.
aliases: ['admin_distance']
qualified_preference:
description:
- Assign preference for qualified next hop.
aggregate:
description: List of static route definitions
state:
description:
- State of the static route configuration.
default: present
choices: ['present', 'absent']
active:
description:
- Specifies whether or not the configuration is active or deactivated
default: True
type: bool
requirements:
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
extends_documentation_fragment: junos
"""
EXAMPLES = """
- name: configure static route
junos_static_route:
address: 192.168.2.0/24
next_hop: 10.0.0.1
preference: 10
qualified_next_hop: 10.0.0.2
qualified_preference: 3
state: present
- name: delete static route
junos_static_route:
address: 192.168.2.0/24
state: absent
- name: deactivate static route configuration
junos_static_route:
address: 192.168.2.0/24
next_hop: 10.0.0.1
preference: 10
qualified_next_hop: 10.0.0.2
qualified_preference: 3
state: present
active: False
- name: activate static route configuration
junos_static_route:
address: 192.168.2.0/24
next_hop: 10.0.0.1
preference: 10
qualified_next_hop: 10.0.0.2
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, qualified_next_hop: 5.5.5.5, qualified_preference: 30 }
- { address: 5.5.5.0/24, next_hop: 6.6.6.6, qualified_next_hop: 7.7.7.7, qualified_preference: 12 }
preference: 10
- name: Delete static route using aggregate
junos_static_route:
aggregate:
- address: 4.4.4.0/24
- address: 5.5.5.0/24
state: absent
"""
RETURN = """
diff.prepared:
description: Configuration difference before and after applying change.
returned: when configuration is changed and diff option is enabled.
type: str
sample: >
[edit routing-options static]
route 2.2.2.0/24 { ... }
+ route 4.4.4.0/24 {
next-hop 3.3.3.3;
qualified-next-hop 5.5.5.5 {
+ preference 30;
}
+ preference 10;
+ }
"""
import collections
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.common.utils import remove_default_spec
from ansible.module_utils.network.junos.junos import junos_argument_spec, tostring
from ansible.module_utils.network.junos.junos import load_config, map_params_to_obj, map_obj_to_ele, to_param_list
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes, locked_config
USE_PERSISTENT_CONNECTION = True
def main():
""" main entry point for module execution
"""
element_spec = dict(
address=dict(aliases=['prefix']),
next_hop=dict(),
preference=dict(type='int', aliases=['admin_distance']),
qualified_next_hop=dict(type='str'),
qualified_preference=dict(type='int'),
state=dict(default='present', choices=['present', 'absent']),
active=dict(default=True, type='bool')
)
aggregate_spec = deepcopy(element_spec)
aggregate_spec['address'] = dict(required=True)
# remove default in aggregate spec, to handle common arguments
remove_default_spec(aggregate_spec)
argument_spec = dict(
aggregate=dict(type='list', elements='dict', options=aggregate_spec),
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']]
module = AnsibleModule(argument_spec=argument_spec,
required_one_of=required_one_of,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True)
warnings = list()
result = {'changed': False}
if warnings:
result['warnings'] = warnings
top = 'routing-options/static/route'
param_to_xpath_map = collections.OrderedDict()
param_to_xpath_map.update([
('address', {'xpath': 'name', 'is_key': True}),
('next_hop', 'next-hop'),
('preference', 'preference/metric-value'),
('qualified_next_hop', {'xpath': 'name', 'top': 'qualified-next-hop'}),
('qualified_preference', {'xpath': 'preference', 'top': 'qualified-next-hop'})
])
params = to_param_list(module)
requests = list()
for param in params:
# if key doesn't exist in the item, get it from module.params
for key in param:
if param.get(key) is None:
param[key] = module.params[key]
item = param.copy()
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, param=item)
requests.append(map_obj_to_ele(module, want, top, param=item))
with locked_config(module):
for req in requests:
diff = load_config(module, tostring(req), warnings, action='merge')
commit = not module.check_mode
if diff:
if commit:
commit_configuration(module)
else:
discard_changes(module)
result['changed'] = True
if module._diff:
result['diff'] = {'prepared': diff}
module.exit_json(**result)
if __name__ == "__main__":
main()

@ -1,251 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['deprecated'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_vlan
version_added: "2.4"
author: "Ganesh Nalawade (@ganeshrn)"
short_description: Manage VLANs on Juniper JUNOS network devices
description:
- This module provides declarative management of VLANs
on Juniper JUNOS network devices.
deprecated:
removed_in: "2.13"
why: Updated modules released with more functionality
alternative: Use M(junos_vlans) instead.
options:
name:
description:
- Name of the VLAN.
required: true
vlan_id:
description:
- ID of the VLAN. Range 1-4094.
required: true
l3_interface:
description:
- Name of logical layer 3 interface.
version_added: "2.7"
filter_input:
description:
- The name of input filter.
version_added: "2.8"
filter_output:
description:
- The name of output filter.
version_added: "2.8"
description:
description:
- Text description of VLANs.
interfaces:
description:
- List of interfaces to check the VLAN has been
configured correctly.
aggregate:
description: List of VLANs definitions.
state:
description:
- State of the VLAN configuration.
default: present
choices: ['present', 'absent']
active:
description:
- Specifies whether or not the configuration is active or deactivated
default: True
type: bool
requirements:
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
extends_documentation_fragment: junos
"""
EXAMPLES = """
- name: configure VLAN ID and name
junos_vlan:
name: test
vlan_id: 20
- name: Link to logical layer 3 interface
junos_vlan:
name: test
vlan_id: 20
l3-interface: vlan.20
- name: remove VLAN configuration
junos_vlan:
name: test
state: absent
- name: deactive VLAN configuration
junos_vlan:
name: test
state: present
active: False
- name: activate VLAN configuration
junos_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 }
- { vlan_id: 160, name: test_vlan_2, description: test vlan-2 }
- name: Delete vlan configuration using aggregate
junos_vlan:
aggregate:
- { vlan_id: 159, name: test_vlan_1 }
- { vlan_id: 160, name: test_vlan_2 }
state: absent
"""
RETURN = """
diff.prepared:
description: Configuration difference before and after applying change.
returned: when configuration is changed and diff option is enabled.
type: str
sample: >
[edit vlans]
+ test-vlan-1 {
+ vlan-id 60;
+ }
"""
import collections
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.common.utils import remove_default_spec
from ansible.module_utils.network.junos.junos import junos_argument_spec, tostring
from ansible.module_utils.network.junos.junos import load_config, map_params_to_obj, map_obj_to_ele, to_param_list
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes, locked_config
USE_PERSISTENT_CONNECTION = True
def validate_vlan_id(value, module):
if value and not 1 <= value <= 4094:
module.fail_json(msg='vlan_id must be between 1 and 4094')
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(param.get(key), module)
def main():
""" main entry point for module execution
"""
element_spec = dict(
name=dict(),
vlan_id=dict(type='int'),
description=dict(),
interfaces=dict(),
l3_interface=dict(),
filter_input=dict(),
filter_output=dict(),
state=dict(default='present', choices=['present', 'absent']),
active=dict(default=True, type='bool')
)
aggregate_spec = deepcopy(element_spec)
aggregate_spec['name'] = dict(required=True)
# remove default in aggregate spec, to handle common arguments
remove_default_spec(aggregate_spec)
argument_spec = dict(
aggregate=dict(type='list', elements='dict', options=aggregate_spec)
)
argument_spec.update(element_spec)
argument_spec.update(junos_argument_spec)
required_one_of = [['aggregate', 'name']]
mutually_exclusive = [['aggregate', 'name']]
module = AnsibleModule(argument_spec=argument_spec,
required_one_of=required_one_of,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True)
warnings = list()
result = {'changed': False}
if warnings:
result['warnings'] = warnings
top = 'vlans/vlan'
param_to_xpath_map = collections.OrderedDict()
param_to_xpath_map.update([
('name', {'xpath': 'name', 'is_key': True}),
('vlan_id', 'vlan-id'),
('l3_interface', 'l3-interface'),
('filter_input', 'forwarding-options/filter/input'),
('filter_output', 'forwarding-options/filter/output'),
('description', 'description')
])
params = to_param_list(module)
requests = list()
for param in params:
# if key doesn't exist in the item, get it from module.params
for key in param:
if param.get(key) is None:
param[key] = module.params[key]
item = param.copy()
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):
for req in requests:
diff = load_config(module, tostring(req), warnings, action='merge')
commit = not module.check_mode
if diff:
if commit:
commit_configuration(module)
else:
discard_changes(module)
result['changed'] = True
if module._diff:
result['diff'] = {'prepared': diff}
module.exit_json(**result)
if __name__ == "__main__":
main()

@ -1,177 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_banner
version_added: "2.4"
author: "Ganesh Nalawade (@ganeshrn)"
short_description: Manage multiline banners on Juniper JUNOS devices
description:
- This will configure both login and motd banners on network devices.
It allows playbooks to add or remote
banner text from the active running configuration.
options:
banner:
description:
- Specifies which banner that should be
configured on the remote device. Value C(login) indicates
system login message prior to authenticating, C(motd) is login
announcement after successful authentication.
required: true
choices: ['login', 'motd']
text:
description:
- The banner text that should be
present in the remote device running configuration. This argument
accepts a multiline string, with no empty lines. Requires I(state=present).
state:
description:
- Specifies whether or not the configuration is
present in the current devices active running configuration.
default: present
choices: ['present', 'absent']
active:
description:
- Specifies whether or not the configuration is active or deactivated
type: bool
default: 'yes'
requirements:
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
extends_documentation_fragment: junos
"""
EXAMPLES = """
- name: configure the login banner
junos_banner:
banner: login
text: |
this is my login banner
that contains a multiline
string
state: present
- name: remove the motd banner
junos_banner:
banner: motd
state: absent
- name: deactivate the motd banner
junos_banner:
banner: motd
state: present
active: False
- name: activate the motd banner
junos_banner:
banner: motd
state: present
active: True
- name: Configure banner from file
junos_banner:
banner: motd
text: "{{ lookup('file', './config_partial/raw_banner.cfg') }}"
state: present
"""
RETURN = """
diff.prepared:
description: Configuration difference before and after applying change.
returned: when configuration is changed and diff option is enabled.
type: str
sample: >
[edit system login]
+ message \"this is my login banner\";
"""
import collections
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.junos import junos_argument_spec, tostring
from ansible.module_utils.network.junos.junos import load_config, map_params_to_obj, map_obj_to_ele
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes, locked_config
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(
banner=dict(required=True, choices=['login', 'motd']),
text=dict(),
state=dict(default='present', choices=['present', 'absent']),
active=dict(default=True, type='bool')
)
argument_spec.update(junos_argument_spec)
required_if = [('state', 'present', ('text',))]
module = AnsibleModule(argument_spec=argument_spec,
required_if=required_if,
supports_check_mode=True)
warnings = list()
result = {'changed': False}
if warnings:
result['warnings'] = warnings
top = 'system/login'
param_to_xpath_map = collections.OrderedDict()
param_to_xpath_map.update([
('text', {'xpath': 'message' if module.params['banner'] == 'login' else 'announcement', 'leaf_only': True})
])
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)
with locked_config(module):
diff = load_config(module, tostring(ele), warnings, action='merge')
commit = not module.check_mode
if diff:
if commit:
commit_configuration(module)
else:
discard_changes(module)
result['changed'] = True
if module._diff:
result['diff'] = {'prepared': diff}
module.exit_json(**result)
if __name__ == "__main__":
main()

@ -1,443 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_command
version_added: "2.1"
author: "Peter Sprygada (@privateip)"
short_description: Run arbitrary commands on an Juniper JUNOS device
description:
- Sends an arbitrary set of commands to an JUNOS node and returns the results
read from the device. This module includes an
argument that will cause the module to wait for a specific condition
before returning or timing out if the condition is not met.
extends_documentation_fragment: junos
options:
commands:
description:
- The commands to send to the remote junos device over the
configured provider. The resulting output from the command
is returned. If the I(wait_for) argument is provided, the
module is not returned until the condition is satisfied or
the number of I(retries) has been exceeded.
rpcs:
description:
- The C(rpcs) argument accepts a list of RPCs to be executed
over a netconf session and the results from the RPC execution
is return to the playbook via the modules results dictionary.
version_added: "2.3"
wait_for:
description:
- Specifies what to evaluate from the output of the command
and what conditionals to apply. This argument will cause
the task to wait for a particular conditional to be true
before moving forward. If the conditional is not true
by the configured retries, the task fails. See examples.
aliases: ['waitfor']
version_added: "2.2"
match:
description:
- The I(match) argument is used in conjunction with the
I(wait_for) argument to specify the match policy. Valid
values are C(all) or C(any). If the value is set to C(all)
then all conditionals in the I(wait_for) must be satisfied. If
the value is set to C(any) then only one of the values must be
satisfied.
default: all
choices: ['any', 'all']
version_added: "2.2"
retries:
description:
- Specifies the number of retries a command should be tried
before it is considered failed. The command is run on the
target device every retry and evaluated against the I(wait_for)
conditionals.
default: 10
interval:
description:
- Configures the interval in seconds to wait between retries
of the command. If the command does not pass the specified
conditional, the interval indicates how to long to wait before
trying the command again.
default: 1
display:
description:
- Encoding scheme to use when serializing output from the device.
This handles how to properly understand the output and apply the
conditionals path to the result set. For I(rpcs) argument default
display is C(xml) and for I(commands) argument default display
is C(text). Value C(set) is applicable only for fetching configuration
from device.
default: depends on input argument I(rpcs) or I(commands)
aliases: ['format', 'output']
choices: ['text', 'json', 'xml', 'set']
version_added: "2.3"
requirements:
- jxmlease
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(network_cli) connections and with C(local) connections for legacy playbooks.
"""
EXAMPLES = """
- name: run show version on remote devices
junos_command:
commands: show version
- name: run show version and check to see if output contains Juniper
junos_command:
commands: show version
wait_for: result[0] contains Juniper
- name: run multiple commands on remote nodes
junos_command:
commands:
- show version
- show interfaces
- name: run multiple commands and evaluate the output
junos_command:
commands:
- show version
- show interfaces
wait_for:
- result[0] contains Juniper
- result[1] contains Loopback0
- name: run commands and specify the output format
junos_command:
commands: show version
display: json
- name: run rpc on the remote device
junos_command:
commands: show configuration
display: set
- name: run rpc on the remote device
junos_command:
rpcs: get-software-information
"""
RETURN = """
stdout:
description: The set of responses from the commands
returned: always apart from low level errors (such as action plugin)
type: list
sample: ['...', '...']
stdout_lines:
description: The value of stdout split into a list
returned: always apart from low level errors (such as action plugin)
type: list
sample: [['...', '...'], ['...'], ['...']]
output:
description: The set of transformed xml to json format from the commands responses
returned: If the I(display) is in C(xml) format.
type: list
sample: ['...', '...']
failed_conditions:
description: The list of conditionals that have failed
returned: failed
type: list
sample: ['...', '...']
"""
import re
import shlex
import time
from ansible.module_utils._text import to_text
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import ConnectionError
from ansible.module_utils.network.common.netconf import exec_rpc
from ansible.module_utils.network.junos.junos import junos_argument_spec, get_configuration, get_connection, get_capabilities, tostring
from ansible.module_utils.network.common.parsing import Conditional, FailedConditionalError
from ansible.module_utils.network.common.utils import to_lines
from ansible.module_utils.six import iteritems
try:
from lxml.etree import Element, SubElement
except ImportError:
from xml.etree.ElementTree import Element, SubElement
try:
import jxmlease
HAS_JXMLEASE = True
except ImportError:
HAS_JXMLEASE = False
USE_PERSISTENT_CONNECTION = True
def rpc(module, items):
responses = list()
for item in items:
name = item['name']
xattrs = item['xattrs']
fetch_config = False
args = item.get('args')
text = item.get('text')
name = str(name).replace('_', '-')
if all((module.check_mode, not name.startswith('get'))):
module.fail_json(msg='invalid rpc for running in check_mode')
if name == 'command' and text.startswith('show configuration') or name == 'get-configuration':
fetch_config = True
element = Element(name, xattrs)
if text:
element.text = text
elif args:
for key, value in iteritems(args):
key = str(key).replace('_', '-')
if isinstance(value, list):
for item in value:
child = SubElement(element, key)
if item is not True:
child.text = item
else:
child = SubElement(element, key)
if value is not True:
child.text = value
if fetch_config:
reply = get_configuration(module, format=xattrs['format'])
else:
reply = exec_rpc(module, tostring(element), ignore_warning=False)
if xattrs['format'] == 'text':
if fetch_config:
data = reply.find('.//configuration-text')
else:
data = reply.find('.//output')
if data is None:
module.fail_json(msg=tostring(reply))
responses.append(data.text.strip())
elif xattrs['format'] == 'json':
responses.append(module.from_json(reply.text.strip()))
elif xattrs['format'] == 'set':
data = reply.find('.//configuration-set')
if data is None:
module.fail_json(msg="Display format 'set' is not supported by remote device.")
responses.append(data.text.strip())
else:
responses.append(tostring(reply))
return responses
def split(value):
lex = shlex.shlex(value)
lex.quotes = '"'
lex.whitespace_split = True
lex.commenters = ''
return list(lex)
def parse_rpcs(module):
items = list()
for rpc in (module.params['rpcs'] or list()):
parts = shlex.split(rpc)
name = parts.pop(0)
args = dict()
for item in parts:
key, value = item.split('=')
if str(value).upper() in ['TRUE', 'FALSE']:
args[key] = bool(value)
elif re.match(r'^[0-9]+$', value):
args[key] = int(value)
else:
args[key] = str(value)
display = module.params['display'] or 'xml'
if display == 'set' and rpc != 'get-configuration':
module.fail_json(msg="Invalid display option '%s' given for rpc '%s'" % ('set', name))
xattrs = {'format': display}
items.append({'name': name, 'args': args, 'xattrs': xattrs})
return items
def parse_commands(module, warnings):
items = list()
for command in (module.params['commands'] or list()):
if module.check_mode and not command.startswith('show'):
warnings.append(
'Only show commands are supported when using check_mode, not '
'executing %s' % command
)
continue
parts = command.split('|')
text = parts[0]
display = module.params['display'] or 'text'
if '| display json' in command:
display = 'json'
elif '| display xml' in command:
display = 'xml'
if display == 'set' or '| display set' in command:
if command.startswith('show configuration'):
display = 'set'
else:
module.fail_json(msg="Invalid display option '%s' given for command '%s'" % ('set', command))
xattrs = {'format': display}
items.append({'name': 'command', 'xattrs': xattrs, 'text': text})
return items
def main():
"""entry point for module execution
"""
argument_spec = dict(
commands=dict(type='list'),
rpcs=dict(type='list'),
display=dict(choices=['text', 'json', 'xml', 'set'], aliases=['format', 'output']),
wait_for=dict(type='list', aliases=['waitfor']),
match=dict(default='all', choices=['all', 'any']),
retries=dict(default=10, type='int'),
interval=dict(default=1, type='int')
)
argument_spec.update(junos_argument_spec)
required_one_of = [('commands', 'rpcs')]
module = AnsibleModule(argument_spec=argument_spec,
required_one_of=required_one_of,
supports_check_mode=True)
warnings = list()
conn = get_connection(module)
capabilities = get_capabilities(module)
if capabilities.get('network_api') == 'cliconf':
if any((module.params['wait_for'], module.params['match'], module.params['rpcs'])):
module.warn('arguments wait_for, match, rpcs are not supported when using transport=cli')
commands = module.params['commands']
output = list()
display = module.params['display']
for cmd in commands:
# if display format is not mentioned in command, add the display format
# from the modules params
if ('display json' not in cmd) and ('display xml' not in cmd):
if display and display != 'text':
cmd += ' | display {0}'.format(display)
try:
output.append(conn.get(command=cmd))
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
lines = [out.split('\n') for out in output]
result = {'changed': False, 'stdout': output, 'stdout_lines': lines}
module.exit_json(**result)
items = list()
items.extend(parse_commands(module, warnings))
items.extend(parse_rpcs(module))
wait_for = module.params['wait_for'] or list()
conditionals = [Conditional(c) for c in wait_for]
retries = module.params['retries']
interval = module.params['interval']
match = module.params['match']
while retries > 0:
responses = rpc(module, items)
transformed = list()
output = list()
for item, resp in zip(items, responses):
if item['xattrs']['format'] == 'xml':
if not HAS_JXMLEASE:
module.fail_json(msg='jxmlease is required but does not appear to be installed. '
'It can be installed using `pip install jxmlease`')
try:
json_resp = jxmlease.parse(resp)
transformed.append(json_resp)
output.append(json_resp)
except Exception:
raise ValueError(resp)
else:
transformed.append(resp)
for item in list(conditionals):
try:
if item(transformed):
if match == 'any':
conditionals = list()
break
conditionals.remove(item)
except FailedConditionalError:
pass
if not conditionals:
break
time.sleep(interval)
retries -= 1
if conditionals:
failed_conditions = [item.raw for item in conditionals]
msg = 'One or more conditional statements have not been satisfied'
module.fail_json(msg=msg, failed_conditions=failed_conditions)
result = {
'changed': False,
'warnings': warnings,
'stdout': responses,
'stdout_lines': list(to_lines(responses)),
}
if output:
result['output'] = output
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,483 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_config
version_added: "2.1"
author: "Peter Sprygada (@privateip)"
short_description: Manage configuration on devices running Juniper JUNOS
description:
- This module provides an implementation for working with the active
configuration running on Juniper JUNOS devices. It provides a set
of arguments for loading configuration, performing rollback operations
and zeroing the active configuration on the device.
extends_documentation_fragment: junos
options:
lines:
description:
- This argument takes a list of C(set) or C(delete) configuration
lines to push into the remote device. Each line must start with
either C(set) or C(delete). This argument is mutually exclusive
with the I(src) argument.
src:
description:
- The I(src) argument provides a path to the configuration file
to load into the remote system. The path can either be a full
system path to the configuration file if the value starts with /
or relative to the root of the implemented role or playbook.
This argument is mutually exclusive with the I(lines) argument.
version_added: "2.2"
src_format:
description:
- The I(src_format) argument specifies the format of the configuration
found int I(src). If the I(src_format) argument is not provided,
the module will attempt to determine the format of the configuration
file specified in I(src).
choices: ['xml', 'set', 'text', 'json']
version_added: "2.2"
rollback:
description:
- The C(rollback) argument instructs the module to rollback the
current configuration to the identifier specified in the
argument. If the specified rollback identifier does not
exist on the remote device, the module will fail. To rollback
to the most recent commit, set the C(rollback) argument to 0.
zeroize:
description:
- The C(zeroize) argument is used to completely sanitize the
remote device configuration back to initial defaults. This
argument will effectively remove all current configuration
statements on the remote device.
type: bool
confirm:
description:
- The C(confirm) argument will configure a time out value in minutes
for the commit to be confirmed before it is automatically
rolled back. If the C(confirm) argument is set to False, this
argument is silently ignored. If the value for this argument
is set to 0, the commit is confirmed immediately.
default: 0
comment:
description:
- The C(comment) argument specifies a text string to be used
when committing the configuration. If the C(confirm) argument
is set to False, this argument is silently ignored.
default: configured by junos_config
replace:
description:
- The C(replace) argument will instruct the remote device to
replace the current configuration hierarchy with the one specified
in the corresponding hierarchy of the source configuration loaded
from this module.
- Note this argument should be considered deprecated. To achieve
the equivalent, set the I(update) argument to C(replace). This argument
will be removed in a future release. The C(replace) and C(update) argument
is mutually exclusive.
type: bool
default: 'no'
backup:
description:
- This argument will cause the module to create a full backup of
the current C(running-config) from the remote device before any
changes are made. If the C(backup_options) value is not given,
the backup file is written to the C(backup) folder in the playbook
root directory or role root directory, if playbook is part of an
ansible role. If the directory does not exist, it is created.
type: bool
default: 'no'
version_added: "2.2"
update:
description:
- This argument will decide how to load the configuration
data particularly when the candidate configuration and loaded
configuration contain conflicting statements. Following are
accepted values.
C(merge) combines the data in the loaded configuration with the
candidate configuration. If statements in the loaded configuration
conflict with statements in the candidate configuration, the loaded
statements replace the candidate ones.
C(override) discards the entire candidate configuration and replaces
it with the loaded configuration.
C(replace) substitutes each hierarchy level in the loaded configuration
for the corresponding level.
C(update) is similar to the override option. The new configuration completely
replaces the existing configuration. The difference comes when the configuration
is later committed. This option performs a 'diff' between the new candidate
configuration and the existing committed configuration. It then only notifies
system processes responsible for the changed portions of the configuration, and
only marks the actual configuration changes as 'changed'.
default: merge
choices: ['merge', 'override', 'replace', 'update']
version_added: "2.3"
confirm_commit:
description:
- This argument will execute commit operation on remote device.
It can be used to confirm a previous commit.
type: bool
default: 'no'
version_added: "2.4"
check_commit:
description:
- This argument will check correctness of syntax; do not apply changes.
- Note that this argument can be used to confirm verified configuration done via commit confirmed operation
type: bool
default: 'no'
version_added: "2.8"
backup_options:
description:
- This is a dict object containing configurable options related to backup file path.
The value of this option is read only when C(backup) is set to I(yes), if C(backup) is set
to I(no) this option will be silently ignored.
suboptions:
filename:
description:
- The filename to be used to store the backup configuration. If the filename
is not given it will be generated based on the hostname, current time and date
in format defined by <hostname>_config.<current-date>@<current-time>
dir_path:
description:
- This option provides the path ending with directory name in which the backup
configuration file will be stored. If the directory does not exist it will be first
created and the filename is either the value of C(filename) or default filename
as described in C(filename) options description. If the path value is not given
in that case a I(backup) directory will be created in the current working directory
and backup configuration will be copied in C(filename) within I(backup) directory.
type: path
type: dict
version_added: "2.8"
requirements:
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Abbreviated commands are NOT idempotent, see
L(Network FAQ,../network/user_guide/faq.html#why-do-the-config-modules-always-return-changed-true-with-abbreviated-commands).
- Loading JSON-formatted configuration I(json) is supported
starting in Junos OS Release 16.1 onwards.
- Update C(override) not currently compatible with C(set) notation.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
"""
EXAMPLES = """
- name: load configure file into device
junos_config:
src: srx.cfg
comment: update config
- name: load configure lines into device
junos_config:
lines:
- set interfaces ge-0/0/1 unit 0 description "Test interface"
- set vlans vlan01 description "Test vlan"
comment: update config
- name: Set routed VLAN interface (RVI) IPv4 address
junos_config:
lines:
- set vlans vlan01 vlan-id 1
- set interfaces irb unit 10 family inet address 10.0.0.1/24
- set vlans vlan01 l3-interface irb.10
- name: Check correctness of commit configuration
junos_config:
check_commit: yes
- name: rollback the configuration to id 10
junos_config:
rollback: 10
- name: zero out the current configuration
junos_config:
zeroize: yes
- name: Set VLAN access and trunking
junos_config:
lines:
- set vlans vlan02 vlan-id 6
- set interfaces ge-0/0/6.0 family ethernet-switching interface-mode access vlan members vlan02
- set interfaces ge-0/0/6.0 family ethernet-switching interface-mode trunk vlan members vlan02
- name: confirm a previous commit
junos_config:
confirm_commit: yes
- name: for idempotency, use full-form commands
junos_config:
lines:
# - set int ge-0/0/1 unit 0 desc "Test interface"
- set interfaces ge-0/0/1 unit 0 description "Test interface"
- name: configurable backup path
junos_config:
src: srx.cfg
backup: yes
backup_options:
filename: backup.cfg
dir_path: /home/user
"""
RETURN = """
backup_path:
description: The full path to the backup file
returned: when backup is yes
type: str
sample: /playbooks/ansible/backup/config.2016-07-16@22:28:34
filename:
description: The name of the backup file
returned: when backup is yes and filename is not specified in backup options
type: str
sample: junos01_config.2016-07-16@22:28:34
shortname:
description: The full path to the backup file excluding the timestamp
returned: when backup is yes and filename is not specified in backup options
type: str
sample: /playbooks/ansible/backup/junos01_config
date:
description: The date extracted from the backup file name
returned: when backup is yes
type: str
sample: "2016-07-16"
time:
description: The time extracted from the backup file name
returned: when backup is yes
type: str
sample: "22:28:34"
"""
import re
import json
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.common.netconf import exec_rpc
from ansible.module_utils.network.junos.junos import get_diff, load_config, get_configuration
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes, locked_config
from ansible.module_utils.network.junos.junos import junos_argument_spec, load_configuration, tostring
from ansible.module_utils.six import string_types
from ansible.module_utils._text import to_native, to_text
try:
from lxml.etree import Element, fromstring
except ImportError:
from xml.etree.ElementTree import Element, fromstring
try:
from lxml.etree import ParseError
except ImportError:
try:
from xml.etree.ElementTree import ParseError
except ImportError:
# for Python < 2.7
from xml.parsers.expat import ExpatError
ParseError = ExpatError
USE_PERSISTENT_CONNECTION = True
DEFAULT_COMMENT = 'configured by junos_config'
def check_args(module, warnings):
if module.params['replace'] is not None:
module.fail_json(msg='argument replace is deprecated, use update')
def zeroize(module):
return exec_rpc(module, tostring(Element('request-system-zeroize')), ignore_warning=False)
def rollback(ele, id='0'):
return get_diff(ele, id)
def guess_format(config):
try:
json.loads(config)
return 'json'
except ValueError:
pass
try:
fromstring(config)
return 'xml'
except ParseError:
pass
if config.startswith('set') or config.startswith('delete'):
return 'set'
return 'text'
def filter_delete_statements(module, candidate):
reply = get_configuration(module, format='set')
match = reply.find('.//configuration-set')
if match is None:
# Could not find configuration-set in reply, perhaps device does not support it?
return candidate
config = to_native(match.text, encoding='latin-1')
modified_candidate = candidate[:]
for index, line in reversed(list(enumerate(candidate))):
if line.startswith('delete'):
newline = re.sub('^delete', 'set', line)
if newline not in config:
del modified_candidate[index]
return modified_candidate
def configure_device(module, warnings, candidate):
kwargs = {}
config_format = None
if module.params['src']:
config_format = module.params['src_format'] or guess_format(str(candidate))
if config_format == 'set':
kwargs.update({'format': 'text', 'action': 'set'})
else:
kwargs.update({'format': config_format, 'action': module.params['update']})
if isinstance(candidate, string_types):
candidate = candidate.split('\n')
# this is done to filter out `delete ...` statements which map to
# nothing in the config as that will cause an exception to be raised
if any((module.params['lines'], config_format == 'set')):
candidate = filter_delete_statements(module, candidate)
kwargs['format'] = 'text'
kwargs['action'] = 'set'
return load_config(module, candidate, warnings, **kwargs)
def main():
""" main entry point for module execution
"""
backup_spec = dict(
filename=dict(),
dir_path=dict(type='path')
)
argument_spec = dict(
lines=dict(aliases=['commands'], type='list'),
src=dict(type='path'),
src_format=dict(choices=['xml', 'text', 'set', 'json']),
# update operations
update=dict(default='merge', choices=['merge', 'override', 'replace', 'update']),
# deprecated replace in Ansible 2.3
replace=dict(type='bool'),
confirm=dict(default=0, type='int'),
comment=dict(default=DEFAULT_COMMENT),
confirm_commit=dict(type='bool', default=False),
check_commit=dict(type='bool', default=False),
# config operations
backup=dict(type='bool', default=False),
backup_options=dict(type='dict', options=backup_spec),
rollback=dict(type='int'),
zeroize=dict(default=False, type='bool'),
)
argument_spec.update(junos_argument_spec)
mutually_exclusive = [('lines', 'src', 'rollback', 'zeroize')]
module = AnsibleModule(argument_spec=argument_spec,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True)
warnings = list()
check_args(module, warnings)
candidate = module.params['lines'] or module.params['src']
commit = not module.check_mode
result = {'changed': False, 'warnings': warnings}
if module.params['backup']:
for conf_format in ['set', 'text']:
reply = get_configuration(module, format=conf_format)
match = reply.find('.//configuration-%s' % conf_format)
if match is not None:
break
else:
module.fail_json(msg='unable to retrieve device configuration')
result['__backup__'] = match.text.strip()
rollback_id = module.params['rollback']
if rollback_id:
diff = rollback(module, rollback_id)
if commit:
kwargs = {
'comment': module.params['comment']
}
with locked_config(module):
load_configuration(module, rollback=rollback_id)
commit_configuration(module, **kwargs)
if module._diff:
result['diff'] = {'prepared': diff}
result['changed'] = True
elif module.params['zeroize']:
if commit:
zeroize(module)
result['changed'] = True
else:
if candidate:
with locked_config(module):
diff = configure_device(module, warnings, candidate)
if diff:
if commit:
kwargs = {
'comment': module.params['comment'],
'check': module.params['check_commit']
}
confirm = module.params['confirm']
if confirm > 0:
kwargs.update({
'confirm': True,
'confirm_timeout': to_text(confirm, errors='surrogate_then_replace')
})
commit_configuration(module, **kwargs)
else:
discard_changes(module)
result['changed'] = True
if module._diff:
result['diff'] = {'prepared': diff}
elif module.params['check_commit']:
commit_configuration(module, check=True)
elif module.params['confirm_commit']:
with locked_config(module):
# confirm a previous commit
commit_configuration(module)
result['changed'] = True
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,139 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_facts
version_added: "2.1"
author: "Nathaniel Case (@Qalthos)"
short_description: Collect facts from remote devices running Juniper Junos
description:
- Collects fact information from a remote device running the Junos
operating system. By default, the module will collect basic fact
information from the device to be included with the hostvars.
Additional fact information can be collected based on the
configured set of arguments.
extends_documentation_fragment: junos
options:
gather_subset:
description:
- When supplied, this argument will restrict the facts collected
to a given subset. Possible values for this argument include
all, hardware, config, and interfaces. Can specify a list of
values to include a larger subset. Values can also be used
with an initial C(M(!)) to specify that a specific subset should
not be collected. To maintain backward compatibility old style facts
can be retrieved by explicitly adding C(ofacts) to value, this requires
junos-eznc to be installed as a prerequisite. Valid value of gather_subset
are default, hardware, config, interfaces, ofacts. If C(ofacts) is present in the
list it fetches the old style facts (fact keys without 'ansible_' prefix) and it requires
junos-eznc library to be installed on control node and the device login credentials
must be given in C(provider) option.
required: false
default: ['!config']
version_added: "2.3"
config_format:
description:
- The I(config_format) argument specifies the format of the configuration
when serializing output from the device. This argument is applicable
only when C(config) value is present in I(gather_subset).
The I(config_format) should be supported by the junos version running on
device. This value is not applicable while fetching old style facts that is
when C(ofacts) value is present in value if I(gather_subset) value. This option
is valid only for C(gather_subset) values.
required: false
default: 'text'
choices: ['xml', 'text', 'set', 'json']
version_added: "2.3"
gather_network_resources:
description:
- When supplied, this argument will restrict the facts collected
to a given subset. Possible values for this argument include
all and the resources like interfaces, vlans etc.
Can specify a list of values to include a larger subset.
Values can also be used with an initial C(M(!)) to specify that
a specific subset should not be collected.
Valid subsets are 'all', 'interfaces', 'lacp', 'lacp_interfaces',
'lag_interfaces', 'l2_interfaces', 'l3_interfaces', 'lldp_global',
'lldp_interfaces', 'vlans'.
required: false
version_added: "2.9"
requirements:
- ncclient (>=v0.5.2)
notes:
- Ensure I(config_format) used to retrieve configuration from device
is supported by junos version running on device.
- With I(config_format = json), configuration in the results will be a dictionary(and not a JSON string)
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
- Fetching old style facts requires junos-eznc library to be installed on control node and the device login credentials
must be given in provider option.
"""
EXAMPLES = """
- name: collect default set of facts
junos_facts:
- name: collect default set of facts and configuration
junos_facts:
gather_subset: config
- name: Gather legacy and resource facts
junos_facts:
gather_subset: all
gather_network_resources: all
"""
RETURN = """
ansible_facts:
description: Returns the facts collect from the device
returned: always
type: dict
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.argspec.facts.facts import FactsArgs
from ansible.module_utils.network.junos.facts.facts import Facts
from ansible.module_utils.network.junos.junos import junos_argument_spec
def main():
"""
Main entry point for module execution
:returns: ansible_facts
"""
argument_spec = FactsArgs.argument_spec
argument_spec.update(junos_argument_spec)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
warnings = []
if module.params["gather_subset"] == "!config":
warnings.append('default value for `gather_subset` will be changed to `min` from `!config` v2.11 onwards')
result = Facts(module).get_facts()
ansible_facts, additional_warnings = result
warnings.extend(additional_warnings)
module.exit_json(ansible_facts=ansible_facts, warnings=warnings)
if __name__ == '__main__':
main()

@ -1,332 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The module file for junos_interfaces
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_interfaces
version_added: 2.9
short_description: Manages interface attributes of Juniper Junos OS network devices.
description: This module manages the interfaces on Juniper Junos OS network devices.
author: Ganesh Nalawade (@ganeshrn)
options:
config:
description: The provided configuration
type: list
suboptions:
name:
description:
- Full name of interface, e.g. ge-0/0/0.
type: str
required: True
description:
description:
- Interface description.
type: str
duplex:
description:
- Interface link status. Applicable for Ethernet interfaces only, either in half duplex,
full duplex or in automatic state which negotiates the duplex automatically.
type: str
choices: ['automatic', 'full-duplex', 'half-duplex']
enabled:
default: True
description:
- Administrative state of the interface.
- Set the value to C(true) to administratively enabled the interface or C(false) to disable it.
type: bool
hold_time:
description:
- The hold time for given interface name.
type: dict
suboptions:
down:
description:
- The link down hold time in milliseconds.
type: int
up:
description:
- The link up hold time in milliseconds.
type: int
mtu:
description:
- MTU for a specific interface.
- Applicable for Ethernet interfaces only.
type: int
speed:
description:
- Interface link speed. Applicable for Ethernet interfaces only.
type: int
state:
choices:
- merged
- replaced
- overridden
- deleted
default: merged
description:
- The state of the configuration after module completion
type: str
requirements:
- ncclient (>=v0.6.4)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 18.4R1.
- This module works with connection C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
"""
EXAMPLES = """
# Using deleted
# Before state:
# -------------
# user@junos01# show interfaces
# ge-0/0/1 {
# description "Configured by Ansible-1";
# speed 1g;
# mtu 1800
# }
# ge-0/0/2 {
# description "Configured by Ansible-2";
# ether-options {
# auto-negotiation;
# }
# }
- name: "Delete given options for the interface (Note: This won't delete the interface itself if any other values are configured for interface)"
junos_interfaces:
config:
- name: ge-0/0/1
description: 'Configured by Ansible-1'
speed: 1g
mtu: 1800
- name: ge-0/0/2
description: 'Configured by Ansible -2'
state: deleted
# After state:
# ------------
# user@junos01# show interfaces
# ge-0/0/2 {
# ether-options {
# auto-negotiation;
# }
# }
# Using merged
# Before state:
# -------------
# user@junos01# show interfaces
# ge-0/0/1 {
# description "test interface";
# speed 1g;
# }
- name: "Merge provided configuration with device configuration (default operation is merge)"
junos_interfaces:
config:
- name: ge-0/0/1
description: 'Configured by Ansible-1'
enabled: True
mtu: 1800
- name: ge-0/0/2
description: 'Configured by Ansible-2'
enabled: False
state: merged
# After state:
# ------------
# user@junos01# show interfaces
# ge-0/0/1 {
# description "Configured by Ansible-1";
# speed 1g;
# mtu 1800
# }
# ge-0/0/2 {
# disable;
# description "Configured by Ansible-2";
# }
# Using overridden
# Before state:
# -------------
# user@junos01# show interfaces
# ge-0/0/1 {
# description "Configured by Ansible-1";
# speed 1g;
# mtu 1800
# }
# ge-0/0/2 {
# disable;
# description "Configured by Ansible-2";
# ether-options {
# auto-negotiation;
# }
# }
# ge-0/0/11 {
# description "Configured by Ansible-11";
# }
- name: "Override device configuration of all interfaces with provided configuration"
junos_interfaces:
config:
- name: ge-0/0/2
description: 'Configured by Ansible-2'
enabled: False
mtu: 2800
- name: ge-0/0/3
description: 'Configured by Ansible-3'
state: overridden
# After state:
# ------------
# user@junos01# show interfaces
# ge-0/0/2 {
# disable;
# description "Configured by Ansible-2";
# mtu 2800
# }
# ge-0/0/3 {
# description "Configured by Ansible-3";
# }
# Using replaced
# Before state:
# -------------
# user@junos01# show interfaces
# ge-0/0/1 {
# description "Configured by Ansible-1";
# speed 1g;
# mtu 1800
# }
# ge-0/0/2 {
# disable;
# mtu 1800;
# speed 1g;
# description "Configured by Ansible-2";
# ether-options {
# auto-negotiation;
# }
# }
# ge-0/0/11 {
# description "Configured by Ansible-11";
# }
- name: "Replaces device configuration of listed interfaces with provided configuration"
junos_interfaces:
config:
- name: ge-0/0/2
description: 'Configured by Ansible-2'
enabled: False
mtu: 2800
- name: ge-0/0/3
description: 'Configured by Ansible-3'
state: replaced
# After state:
# ------------
# user@junos01# show interfaces
# ge-0/0/1 {
# description "Configured by Ansible-1";
# speed 1g;
# mtu 1800
# }
# ge-0/0/2 {
# disable;
# description "Configured by Ansible-2";
# mtu 2800
# }
# ge-0/0/3 {
# description "Configured by Ansible-3";
# }
# ge-0/0/11 {
# description "Configured by Ansible-11";
# }
"""
RETURN = """
before:
description: The configuration as structured data prior to module invocation.
returned: always
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
after:
description: The configuration as structured data after module completion.
returned: when changed
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
xml:
description: The set of xml rpc payload pushed to the remote device.
returned: always
type: list
sample: ['xml 1', 'xml 2', 'xml 3']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.argspec.interfaces.interfaces import InterfacesArgs
from ansible.module_utils.network.junos.config.interfaces.interfaces import Interfaces
def main():
"""
Main entry point for module execution
:returns: the result form module invocation
"""
required_if = [('state', 'merged', ('config',)),
('state', 'replaced', ('config',)),
('state', 'overridden', ('config',))]
module = AnsibleModule(argument_spec=InterfacesArgs.argument_spec,
required_if=required_if,
supports_check_mode=True)
result = Interfaces(module).execute_module()
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,407 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The module file for junos_l2_interfaces
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'
}
DOCUMENTATION = """
---
module: junos_l2_interfaces
version_added: 2.9
short_description: Manage Layer-2 interface on Juniper JUNOS devices
description: This module provides declarative management of a Layer-2 interface on Juniper JUNOS devices.
author: Ganesh Nalawade (@ganeshrn)
options:
config:
description: A dictionary of Layer-2 interface options
type: list
elements: dict
suboptions:
name:
description:
- Full name of interface, e.g. ge-0/0/1.
type: str
required: True
unit:
description:
- Logical interface number. Value of C(unit) should be of type
integer.
type: int
access:
description:
- Configure the interface as a Layer 2 access mode.
type: dict
suboptions:
vlan:
description:
- Configure the access VLAN ID.
type: str
trunk:
description:
- Configure the interface as a Layer 2 trunk mode.
type: dict
suboptions:
allowed_vlans:
description:
- List of VLANs to be configured in trunk port. It's used as the VLAN range to ADD or
REMOVE from the trunk.
type: list
native_vlan:
description:
- Native VLAN to be configured in trunk port. It is used as the trunk native VLAN ID.
type: str
enhanced_layer:
description:
- True if your device has Enhanced Layer 2 Software (ELS). If the l2 configuration is under
C(interface-mode) the value is True else if the l2 configuration is under C(port-mode) value
is False
type: bool
state:
choices:
- merged
- replaced
- overridden
- deleted
default: merged
description:
- The state of the configuration after module completion
type: str
requirements:
- ncclient (>=v0.6.4)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 18.4R1.
- This module works with connection C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
"""
EXAMPLES = """
# Using deleted
# Before state:
# -------------
#
# ansible@junos01# show interfaces
# ge-0/0/1 {
# description "L2 interface";
# speed 1g;
# unit 0 {
# family ethernet-switching {
# interface-mode access;
# vlan {
# members vlan30;
# }
# }
# }
#}
#ge-0/0/2 {
# description "non L2 interface";
# unit 0 {
# family inet {
# address 192.168.56.14/24;
# }
# }
- name: "Delete L2 attributes of given interfaces (Note: This won't delete the interface itself)."
junos_l2_interfaces:
config:
- name: ge-0/0/1
- name: ge-0/0/2
state: deleted
# After state:
# ------------
#
# ansible@junos01# show interfaces
# ge-0/0/1 {
# description "L2 interface";
# speed 1g;
# }
#ge-0/0/2 {
# description "non L2 interface";
# unit 0 {
# family inet {
# address 192.168.56.14/24;
# }
# }
# Using merged
# Before state:
# -------------
# ansible@junos01# show interfaces
# ge-0/0/3 {
# description "test interface";
# speed 1g;
#}
# ge-0/0/4 {
# description interface-trunk;
# native-vlan-id 100;
# unit 0 {
# family ethernet-switching {
# interface-mode trunk;
# vlan {
# members [ vlan40 ];
# }
# }
# }
# }
- name: "Merge provided configuration with device configuration (default operation is merge)"
junos_l2_interfaces:
config:
- name: ge-0/0/3
access:
vlan: v101
- name: ge-0/0/4
trunk:
allowed_vlans:
- vlan30
native_vlan: 50
state: merged
# After state:
# ------------
# user@junos01# show interfaces
# ge-0/0/3 {
# description "test interface";
# speed 1g;
# unit 0 {
# family ethernet-switching {
# interface-mode access;
# vlan {
# members v101;
# }
# }
# }
# }
# ge-0/0/4 {
# description interface-trunk;
# native-vlan-id 50;
# unit 0 {
# family ethernet-switching {
# interface-mode trunk;
# vlan {
# members [ vlan40 vlan30 ];
# }
# }
# }
# }
# Using overridden
# Before state:
# -------------
# ansible@junos01# show interfaces
# ge-0/0/3 {
# description "test interface";
# speed 1g;
#}
# ge-0/0/4 {
# description interface-trunk;
# native-vlan-id 100;
# unit 0 {
# family ethernet-switching {
# interface-mode trunk;
# vlan {
# members [ vlan40 ];
# }
# }
# }
# }
# ge-0/0/5 {
# description "Configured by Ansible-11";
# unit 0 {
# family ethernet-switching {
# interface-mode access;
# vlan {
# members v101;
# }
# }
# }
# }
- name: "Override provided configuration with device configuration"
junos_l2_interfaces:
config:
- name: ge-0/0/3
access:
vlan: v101
- name: ge-0/0/4
trunk:
allowed_vlans:
- vlan30
native_vlan: 50
state: overridden
# After state:
# ------------
# user@junos01# show interfaces
# ge-0/0/3 {
# unit 0 {
# family ethernet-switching {
# interface-mode access;
# vlan {
# members v101;
# }
# }
# }
# }
# ge-0/0/4 {
# description interface-trunk;
# native-vlan-id 50;
# unit 0 {
# family ethernet-switching {
# interface-mode trunk;
# vlan {
# members [ vlan30 ];
# }
# }
# }
# }
# Using replaced
# Before state:
# -------------
# ansible@junos01# show interfaces
# ge-0/0/3 {
# description "test interface";
# speed 1g;
#}
# ge-0/0/4 {
# description interface-trunk;
# native-vlan-id 100;
# unit 0 {
# family ethernet-switching {
# interface-mode trunk;
# vlan {
# members [ vlan40 ];
# }
# }
# }
# }
- name: "Replace provided configuration with device configuration"
junos_l2_interfaces:
config:
- name: ge-0/0/3
access:
vlan: v101
- name: ge-0/0/4
trunk:
allowed_vlans:
- vlan30
native_vlan: 50
state: replaced
# After state:
# ------------
# user@junos01# show interfaces
# ge-0/0/3 {
# unit 0 {
# family ethernet-switching {
# interface-mode access;
# vlan {
# members v101;
# }
# }
# }
# }
# ge-0/0/4 {
# description interface-trunk;
# native-vlan-id 50;
# unit 0 {
# family ethernet-switching {
# interface-mode trunk;
# vlan {
# members [ vlan30 ];
# }
# }
# }
# }
"""
RETURN = """
before:
description: The configuration as structured data prior to module invocation.
returned: always
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
after:
description: The configuration as structured data after module completion.
returned: when changed
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
commands:
description: The set of commands pushed to the remote device.
returned: always
type: list
sample: ['command 1', 'command 2', 'command 3']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.argspec.l2_interfaces.l2_interfaces import L2_interfacesArgs
from ansible.module_utils.network.junos.config.l2_interfaces.l2_interfaces import L2_interfaces
def main():
"""
Main entry point for module execution
:returns: the result form module invocation
"""
required_if = [('state', 'merged', ('config',)),
('state', 'replaced', ('config',)),
('state', 'overridden', ('config',))]
module = AnsibleModule(argument_spec=L2_interfacesArgs.argument_spec,
required_if=required_if,
supports_check_mode=True)
result = L2_interfaces(module).execute_module()
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,408 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The module file for junos_l3_interfaces
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'
}
DOCUMENTATION = """
---
module: junos_l3_interfaces
version_added: 2.9
short_description: Manage Layer 3 interface on Juniper JUNOS devices
description: This module provides declarative management of a Layer 3 interface on Juniper JUNOS devices
author: Daniel Mellado (@dmellado)
requirements:
- ncclient (>=v0.6.4)
notes:
- This module requires the netconf system service be enabled on the device being managed.
- This module works with connection C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- Tested against JunOS v18.4R1
options:
config:
description: A dictionary of Layer 3 interface options
type: list
elements: dict
suboptions:
name:
description:
- Full name of interface, e.g. ge-0/0/1
type: str
required: True
unit:
description:
- Logical interface number. Value of C(unit) should be of type integer
default: 0
type: int
ipv4:
description:
- IPv4 addresses to be set for the Layer 3 logical interface mentioned in I(name) option.
The address format is <ipv4 address>/<mask>. The mask is number in range 0-32
for example, 192.0.2.1/24, or C(dhcp) to query DHCP for an IP address
type: list
elements: dict
suboptions:
address:
description:
- IPv4 address to be set for the specific interface
type: str
ipv6:
description:
- IPv6 addresses to be set for the Layer 3 logical interface mentioned in I(name) option.
The address format is <ipv6 address>/<mask>, the mask is number in range 0-128
for example, 2001:db8:2201:1::1/64 or C(auto-config) to use SLAAC
type: list
elements: dict
suboptions:
address:
description:
- IPv6 address to be set for the specific interface
type: str
state:
description:
- The state of the configuration after module completion
type: str
choices:
- merged
- replaced
- overridden
- deleted
default: merged
"""
EXAMPLES = """
# Using deleted
# Before state:
# -------------
#
# admin# show interfaces
# ge-0/0/1 {
# description "L3 interface";
# unit 0 {
# family inet {
# address 10.200.16.10/24;
# }
# }
# }
# ge-0/0/2 {
# description "non L3 interface";
# unit 0 {
# family ethernet-switching {
# interface-mode access;
# vlan {
# members 2;
# }
# }
# }
# }
- name: Delete JUNOS L3 logical interface
junos_l3_interfaces:
config:
- name: ge-0/0/1
- name: ge-0/0/2
state: deleted
# After state:
# ------------
#
# admin# show interfaces
# ge-0/0/1 {
# description "deleted L3 interface";
# }
# ge-0/0/2 {
# description "non L3 interface";
# unit 0 {
# family ethernet-switching {
# interface-mode access;
# vlan {
# members 2;
# }
# }
# }
# }
# Using merged
# Before state
# ------------
#
# admin# show interfaces
# ge-0/0/1 {
# description "L3 interface";
# unit 0 {
# family inet {
# address 10.200.16.10/24;
# }
# }
# }
# ge-0/0/2 {
# description "non configured interface";
# unit 0;
# }
- name: Merge provided configuration with device configuration (default operation is merge)
junos_l3_interfaces:
config:
- name: ge-0/0/1
ipv4:
- address: 192.168.1.10/24
ipv6:
- address: 8d8d:8d01::1/64
- name: ge-0/0/2
ipv4:
- address: dhcp
state: merged
# After state:
# ------------
#
# admin# show interfaces
# ge-0/0/1 {
# description "L3 interface";
# unit 0 {
# family inet {
# address 10.200.16.10/24;
# address 192.168.1.10/24;
# }
# family inet6 {
# address 8d8d:8d01::1/64;
# }
# }
# }
# ge-0/0/2 {
# description "L3 interface with dhcp";
# unit 0 {
# family inet {
# dhcp;
# }
# }
# }
# Using overridden
# Before state
# ------------
#
# admin# show interfaces
# ge-0/0/1 {
# description "L3 interface";
# unit 0 {
# family inet {
# address 10.200.16.10/24;
# }
# }
# }
# ge-0/0/2 {
# description "L3 interface with dhcp";
# unit 0 {
# family inet {
# dhcp;
# }
# }
# }
# ge-0/0/3 {
# description "another L3 interface";
# unit 0 {
# family inet {
# address 192.168.1.10/24;
# }
# }
# }
- name: Override provided configuration with device configuration
junos_l3_interfaces:
config:
- name: ge-0/0/1
ipv4:
- address: 192.168.1.10/24
ipv6:
- address: 8d8d:8d01::1/64
- name: ge-0/0/2
ipv6:
- address: 2001:db8:3000::/64
state: overridden
# After state:
# ------------
#
# admin# show interfaces
# ge-0/0/1 {
# description "L3 interface";
# unit 0 {
# family inet {
# address 192.168.1.10/24;
# }
# family inet6 {
# address 8d8d:8d01::1/64;
# }
# }
# }
# ge-0/0/2 {
# description "L3 interface with ipv6";
# unit 0 {
# family inet6 {
# address 2001:db8:3000::/64;
# }
# }
# }
# ge-0/0/3 {
# description "overridden L3 interface";
# unit 0;
# }
# Using replaced
# Before state
# ------------
#
# admin# show interfaces
# ge-0/0/1 {
# description "L3 interface";
# unit 0 {
# family inet {
# address 10.200.16.10/24;
# }
# }
# }
# ge-0/0/2 {
# description "non configured interface";
# unit 0;
# }
# ge-0/0/3 {
# description "another L3 interface";
# unit 0 {
# family inet {
# address 192.168.1.10/24;
# }
# }
# }
- name: Replace provided configuration with device configuration
junos_l3_interfaces:
config:
- name: ge-0/0/1
ipv4:
- address: 192.168.1.10/24
ipv6:
- address: 8d8d:8d01::1/64
- name: ge-0/0/2
ipv4:
- address: dhcp
state: replaced
# After state:
# ------------
#
# admin# show interfaces
# ge-0/0/1 {
# description "L3 interface";
# unit 0 {
# family inet {
# address 192.168.1.10/24;
# }
# family inet6 {
# address 8d8d:8d01::1/64;
# }
# }
# }
# ge-0/0/2 {
# description "L3 interface with dhcp";
# unit 0 {
# family inet {
# dhcp;
# }
# }
# }
# ge-0/0/3 {
# description "another L3 interface";
# unit 0 {
# family inet {
# address 192.168.1.10/24;
# }
# }
# }
"""
RETURN = """
before:
description: The configuration as structured data prior to module invocation.
returned: always
sample: >
The configuration returned will always be in the same format
of the parameters above.
type: list
after:
description: The configuration as structured data after module completion.
returned: when changed
sample: >
The configuration returned will always be in the same format
of the parameters above.
type: list
commands:
description: The set of commands pushed to the remote device.
returned: always
type: list
sample: ['command 1', 'command 2', 'command 3']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.argspec.l3_interfaces.l3_interfaces import L3_interfacesArgs
from ansible.module_utils.network.junos.config.l3_interfaces.l3_interfaces import L3_interfaces
def main():
"""
Main entry point for module execution
:returns: the result form module invocation
"""
required_if = [('state', 'merged', ('config',)),
('state', 'replaced', ('config',)),
('state', 'overridden', ('config',))]
module = AnsibleModule(argument_spec=L3_interfacesArgs.argument_spec,
required_if=required_if,
supports_check_mode=True)
result = L3_interfaces(module).execute_module()
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,193 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The module file for junos_lacp
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'
}
DOCUMENTATION = """
---
module: junos_lacp
version_added: 2.9
short_description: Manage Global Link Aggregation Control Protocol (LACP) on Juniper Junos devices
description: This module provides declarative management of global LACP on Juniper Junos network devices.
author: Ganesh Nalawade (@ganeshrn)
options:
config:
description: A dictionary of LACP global options
type: dict
suboptions:
system_priority:
description:
- LACP priority for the system.
type: int
link_protection:
description:
- Enable LACP link-protection for the system. If the value is set to C(non-revertive)
it will not revert links when a better priority link comes up. By default the link will
be reverted.
type: str
choices: ['revertive', 'non-revertive']
state:
description:
- The state of the configuration after module completion
type: str
choices:
- merged
- replaced
- deleted
default: merged
requirements:
- ncclient (>=v0.6.4)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 18.1R1.
- This module works with connection C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
"""
EXAMPLES = """
# Using deleted
# Before state:
# -------------
# user@junos01# show chassis aggregated-devices ethernet lacp
# system-priority 63;
# link-protection {
# non-revertive;
# }
- name: Delete global LACP attributes
junos_lacp:
state: deleted
# After state:
# ------------
# user@junos01# show chassis aggregated-devices ethernet lacp
#
# Using merged
# Before state:
# -------------
# user@junos01# show chassis aggregated-devices ethernet lacp
#
- name: Merge global LACP attributes
junos_lacp:
config:
system_priority: 63
link_protection: revertive
state: merged
# After state:
# ------------
# user@junos01# show chassis aggregated-devices ethernet lacp
# system-priority 63;
# link-protection {
# non-revertive;
# }
# Using replaced
# Before state:
# -------------
# user@junos01# show chassis aggregated-devices ethernet lacp
# system-priority 63;
# link-protection {
# non-revertive;
# }
- name: Replace global LACP attributes
junos_lacp:
config:
system_priority: 30
link_protection: non-revertive
state: replaced
# After state:
# ------------
# user@junos01# show chassis aggregated-devices ethernet lacp
# system-priority 30;
# link-protection;
"""
RETURN = """
before:
description: The configuration as structured data prior to module invocation.
returned: always
type: dict
sample: >
The configuration returned will always be in the same format
of the parameters above.
after:
description: The configuration as structured data after module completion.
returned: when changed
type: dict
sample: >
The configuration returned will always be in the same format
of the parameters above.
xml:
description: The set of xml rpc payload pushed to the remote device.
returned: always
type: list
sample: ['xml 1', 'xml 2', 'xml 3']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.argspec.lacp.lacp import LacpArgs
from ansible.module_utils.network.junos.config.lacp.lacp import Lacp
def main():
"""
Main entry point for module execution
:returns: the result form module invocation
"""
required_if = [('state', 'merged', ('config',)),
('state', 'replaced', ('config',))]
module = AnsibleModule(argument_spec=LacpArgs.argument_spec,
required_if=required_if,
supports_check_mode=True)
result = Lacp(module).execute_module()
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,520 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The module file for junos_lacp_interfaces
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'
}
DOCUMENTATION = """
---
module: junos_lacp_interfaces
version_added: 2.9
short_description: Manage Link Aggregation Control Protocol (LACP) attributes of interfaces on Juniper JUNOS devices.
description:
- This module manages Link Aggregation Control Protocol (LACP) attributes of interfaces on Juniper JUNOS devices.
author: Ganesh Nalawade (@ganeshrn)
options:
config:
description: The list of dictionaries of LACP interfaces options.
type: list
elements: dict
suboptions:
name:
description:
- Name Identifier of the interface or link aggregation group.
type: str
period:
description:
- Timer interval for periodic transmission of LACP packets. If the value is
set to C(fast) the packets are received every second and if the value is
C(slow) the packets are received every 30 seconds. This value is applicable
for aggregate interface only.
type: str
choices: ['fast', 'slow']
sync_reset:
description:
- The argument notifies minimum-link failure out of sync to peer. If the value
is C(disable) it disables minimum-link failure handling at LACP level and if
value is C(enable) it enables minimum-link failure handling at LACP level.
This value is applicable for aggregate interface only.
type: str
choices: ['disable', 'enable']
force_up:
description:
- This is a boolean argument to control if the port should be up in absence
of received link Aggregation Control Protocol Data Unit (LACPDUS).
This value is applicable for member interfaces only.
type: bool
port_priority:
description:
- Priority of the member port. This value is applicable for member interfaces only.
- Refer to vendor documentation for valid values.
type: int
system:
description:
- This dict object contains configurable options related to LACP
system parameters for the link aggregation group.
This value is applicable for aggregate interface only.
type: dict
suboptions:
priority:
description:
- Specifies the system priority to use in LACP negotiations for
the bundle.
- Refer to vendor documentation for valid values.
type: int
mac:
description:
- Specifies the system ID to use in LACP negotiations for
the bundle, encoded as a MAC address.
type: dict
suboptions:
address:
description:
- The system ID to use in LACP negotiations.
type: str
state:
description:
- The state of the configuration after module completion.
type: str
choices:
- merged
- replaced
- overridden
- deleted
default: merged
"""
EXAMPLES = """
# Using merged
# Before state:
# -------------
# user@junos01# show interfaces
# ge-0/0/2 {
# ether-options {
# 802.3ad ae4;
# }
# }
# ge-0/0/3 {
# ether-options {
# 802.3ad ae0;
# }
# }
# ae0 {
# description "lag interface merged";
# aggregated-ether-options {
# lacp {
# passive;
# }
# }
# }
# ae4 {
# description "test aggregate interface";
# aggregated-ether-options {
# lacp {
# passive;
# link-protection;
# }
# }
# }
- name: Merge provided configuration with device configuration
junos_lacp_interfaces:
config:
- name: ae0
period: fast
sync_reset: enable
system:
priority: 100
mac:
address: 00:00:00:00:00:02
- name: ge-0/0/3
port_priority: 100
force_up: True
state: merged
# After state:
# -------------
# user@junos01# show interfaces
# ge-0/0/2 {
# ether-options {
# 802.3ad ae4;
# }
# }
# ge-0/0/3 {
# ether-options {
# 802.3ad {
# lacp {
# force-up;
# port-priority 100;
# }
# ae0;
# }
# }
# }
# ae0 {
# description "lag interface merged";
# aggregated-ether-options {
# lacp {
# passive;
# periodic fast;
# sync-reset enable;
# system-priority 100;
# system-id 00:00:00:00:00:02;
# }
# }
# }
# ae4 {
# description "test aggregate interface";
# aggregated-ether-options {
# lacp {
# passive;
# link-protection;
# }
# }
# }
# Using replaced
# Before state:
# -------------
# user@junos01# show interfaces
# ge-0/0/2 {
# ether-options {
# 802.3ad ae4;
# }
# }
# ge-0/0/3 {
# ether-options {
# 802.3ad {
# lacp {
# force-up;
# port-priority 100;
# }
# ae0;
# }
# }
# }
# ae0 {
# description "lag interface merged";
# aggregated-ether-options {
# lacp {
# passive;
# periodic fast;
# sync-reset enable;
# system-priority 100;
# system-id 00:00:00:00:00:02;
# }
# }
# }
# ae4 {
# description "test aggregate interface";
# aggregated-ether-options {
# lacp {
# passive;
# link-protection;
# }
# }
# }
- name: Replace device LACP interfaces configuration with provided configuration
junos_lacp_interfaces:
config:
- name: ae0
period: slow
state: replaced
# After state:
# -------------
# user@junos01# show interfaces
# ge-0/0/2 {
# ether-options {
# 802.3ad ae4;
# }
# }
# ge-0/0/3 {
# ether-options {
# 802.3ad {
# lacp {
# force-up;
# port-priority 100;
# }
# ae0;
# }
# }
# }
# ae0 {
# description "lag interface merged";
# aggregated-ether-options {
# lacp {
# passive;
# periodic slow;
# }
# }
# }
# ae4 {
# description "test aggregate interface";
# aggregated-ether-options {
# lacp {
# passive;
# link-protection;
# }
# }
# }
# Using overridden
# Before state:
# -------------
# user@junos01# show interfaces
# ge-0/0/2 {
# ether-options {
# 802.3ad ae4;
# }
# }
# ge-0/0/3 {
# ether-options {
# 802.3ad {
# lacp {
# force-up;
# port-priority 100;
# }
# ae0;
# }
# }
# }
# ae0 {
# description "lag interface merged";
# aggregated-ether-options {
# lacp {
# passive;
# periodic slow;
# }
# }
# }
# ae4 {
# description "test aggregate interface";
# aggregated-ether-options {
# lacp {
# passive;
# link-protection;
# }
# }
# }
- name: Overrides all device LACP interfaces configuration with provided configuration
junos_lacp_interfaces:
config:
- name: ae0
system:
priority: 300
mac:
address: 00:00:00:00:00:03
- name: ge-0/0/2
port_priority: 200
force_up: False
state: overridden
# After state:
# -------------
# user@junos01# show interfaces
# ge-0/0/2 {
# ether-options {
# 802.3ad {
# lacp {
# port-priority 200;
# }
# ae4;
# }
# }
# }
# ge-0/0/3 {
# ether-options {
# 802.3ad {
# lacp {
# force-up;
# port-priority 100;
# }
# ae0;
# }
# }
# }
# ae0 {
# description "lag interface merged";
# aggregated-ether-options {
# lacp {
# passive;
# system-priority 300;
# system-id 00:00:00:00:00:03;
# }
# }
# }
# ae4 {
# description "test aggregate interface";
# aggregated-ether-options {
# lacp {
# passive;
# link-protection;
# }
# }
# }
# Using deleted
# Before state:
# -------------
# user@junos01# show interfaces
# ge-0/0/2 {
# ether-options {
# 802.3ad {
# lacp {
# port-priority 200;
# }
# ae4;
# }
# }
# }
# ge-0/0/3 {
# ether-options {
# 802.3ad {
# lacp {
# force-up;
# port-priority 100;
# }
# ae0;
# }
# }
# }
# ae0 {
# description "lag interface merged";
# aggregated-ether-options {
# lacp {
# passive;
# system-priority 300;
# system-id 00:00:00:00:00:03;
# }
# }
# }
# ae4 {
# description "test aggregate interface";
# aggregated-ether-options {
# lacp {
# passive;
# link-protection;
# }
# }
# }
- name: "Delete LACP interfaces attributes of given interfaces (Note: This won't delete the interface itself)"
junos_lacp_interfaces:
config:
- name: ae0
- name: ge-0/0/3
- name: ge-0/0/2
state: deleted
# After state:
# -------------
# user@junos01# show interfaces
# ge-0/0/2 {
# ether-options {
# 802.3ad ae4;
# }
# }
# ge-0/0/3 {
# ether-options {
# 802.3ad ae0;
# }
# }
# ae0 {
# description "lag interface merged";
# aggregated-ether-options {
# lacp {
# passive;
# }
# }
# }
# ae4 {
# description "test aggregate interface";
# aggregated-ether-options {
# lacp {
# passive;
# link-protection;
# }
# }
# }
"""
RETURN = """
before:
description: The configuration as structured data prior to module invocation.
returned: always
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
after:
description: The configuration as structured data after module completion.
returned: when changed
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
commands:
description: The set of commands pushed to the remote device.
returned: always
type: list
sample: ['command 1', 'command 2', 'command 3']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.argspec.lacp_interfaces.lacp_interfaces import Lacp_interfacesArgs
from ansible.module_utils.network.junos.config.lacp_interfaces.lacp_interfaces import Lacp_interfaces
def main():
"""
Main entry point for module execution
:returns: the result form module invocation
"""
required_if = [('state', 'merged', ('config',)),
('state', 'replaced', ('config',)),
('state', 'overridden', ('config',))]
module = AnsibleModule(argument_spec=Lacp_interfacesArgs.argument_spec,
required_if=required_if,
supports_check_mode=True)
result = Lacp_interfaces(module).execute_module()
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,349 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The module file for junos_lag_interfaces
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'
}
DOCUMENTATION = """
---
module: junos_lag_interfaces
version_added: 2.9
short_description: Manage Link Aggregation on Juniper JUNOS devices.
description: This module manages properties of Link Aggregation Group on Juniper JUNOS devices.
author: Ganesh Nalawade (@ganeshrn)
options:
config:
description: A list of link aggregation group configurations.
type: list
suboptions:
name:
description:
- Name of the link aggregation group (LAG).
type: str
required: True
mode:
description:
- LAG mode. A value of C(passive) will enable LACP in C(passive) mode that is it
will respond to LACP packets and C(active) configures the link to initiate
transmission of LACP packets.
choices: ['active', 'passive']
link_protection:
description:
- This boolean option indicates if link protection should be enabled for the LAG interface.
If value is C(True) link protection is enabled on LAG and if value is C(False) link protection
is disabled.
type: bool
members:
description:
- List of member interfaces of the link aggregation group. The value can be
single interface or list of interfaces.
type: list
suboptions:
member:
description:
- Name of the member interface.
type: str
link_type:
description:
- The value of this options configures the member link as either C(primary)
or C(backup). Value C(primary) configures primary interface for link-protection mode
and C(backup) configures backup interface for link-protection mode.
choices: ['primary', 'backup']
state:
description:
- The state of the configuration after module completion
type: str
choices:
- merged
- replaced
- overridden
- deleted
default: merged
requirements:
- ncclient (>=v0.6.4)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 18.4R1.
- This module works with connection C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
"""
EXAMPLES = """
# Using merged
# Before state:
# -------------
# user@junos01# show interfaces
# ge-0/0/1 {
# description "Ansible configured interface 1";
# ether-options {
# 802.3ad ae0;
# }
# }
# ge-0/0/2 {
# description "Ansible configured interface 2";
# ether-options {
# 802.3ad ae0;
# }
# }
# ae0 {
# description "lag interface";
# }
# ae1 {
# description "lag interface 1";
# }
- name: "Delete LAG attributes of given interfaces (Note: This won't delete the interface itself)"
junos_lag_interfaces:
config:
- name: ae0
- name: ae1
state: deleted
# After state:
# -------------
# user@junos01# show interfaces
# ge-0/0/1 {
# description "Ansible configured interface 1";
# }
# ge-0/0/2 {
# description "Ansible configured interface 2";
# }
# Using merged
# Before state:
# -------------
# user@junos01# show interfaces
# ge-0/0/1 {
# description "Ansible configured interface 1";
# }
# ge-0/0/2 {
# description "Ansible configured interface 2";
# }
- name: Merge provided configuration with device configuration
junos_lag_interfaces:
config:
- name: ae0
members:
- member: ge-0/0/1
link_type: primary
- member: ge-0/0/2
link_type: backup
state: merged
# After state:
# -------------
# user@junos01# show interfaces
# ge-0/0/1 {
# description "Ansible configured interface 1";
# ether-options {
# 802.3ad {
# ae0;
# primary;
# }
# }
# }
# ge-0/0/2 {
# description "Ansible configured interface 2";
# ether-options {
# 802.3ad {
# ae0;
# backup;
# }
# }
# }
# Using merged
# Before state:
# -------------
# user@junos01# show interfaces
# ge-0/0/1 {
# description "Ansible configured interface 1";
# ether-options {
# 802.3ad ae0;
# }
# }
# ge-0/0/2 {
# description "Ansible configured interface 2";
# ether-options {
# 802.3ad ae0;
# }
# }
# ae0 {
# description "lag interface";
# }
# ae3 {
# description "lag interface 3";
# }
- name: Overrides all device LAG configuration with provided configuration
junos_lag_interfaces:
config:
- name: ae0
members:
- member: ge-0/0/2
- name: ae1
members:
- member: ge-0/0/1
mode: passive
state: overridden
# After state:
# -------------
# user@junos01# show interfaces
# ge-0/0/1 {
# description "Ansible configured interface 1";
# ether-options {
# 802.3ad ae1;
# }
# }
# ge-0/0/2 {
# description "Ansible configured interface 2";
# ether-options {
# 802.3ad ae0;
# }
# }
# ae0 {
# description "lag interface";
# }
# ae1 {
# aggregated-ether-options {
# lacp {
# active;
# }
# }
# }
# Using merged
# Before state:
# -------------
# user@junos01# show interfaces
# ge-0/0/1 {
# description "Ansible configured interface 1";
# }
# ge-0/0/2 {
# description "Ansible configured interface 2";
# }
# ge-0/0/3 {
# description "Ansible configured interface 3";
# }
- name: Replace device LAG configuration with provided configuration
junos_lag_interfaces:
config:
- name: ae0
members:
- member: ge-0/0/1
mode: active
state: replaced
# After state:
# -------------
# user@junos01# show interfaces
# ge-0/0/1 {
# description "Ansible configured interface 1";
# ether-options {
# 802.3ad ae0;
# }
# }
# ge-0/0/2 {
# description "Ansible configured interface 2";
# }
# ae0 {
# aggregated-ether-options {
# lacp {
# active;
# }
# }
# }
# ge-0/0/3 {
# description "Ansible configured interface 3";
# }
"""
RETURN = """
before:
description: The configuration as structured data prior to module invocation.
returned: always
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
after:
description: The configuration as structured data after module completion.
returned: when changed
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
xml:
description: The set of xml rpc payload pushed to the remote device.
returned: always
type: list
sample: ['xml 1', 'xml 2', 'xml 3']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.argspec.lag_interfaces.lag_interfaces import Lag_interfacesArgs
from ansible.module_utils.network.junos.config.lag_interfaces.lag_interfaces import Lag_interfaces
def main():
"""
Main entry point for module execution
:returns: the result form module invocation
"""
required_if = [('state', 'merged', ('config',)),
('state', 'replaced', ('config',)),
('state', 'overridden', ('config',))]
module = AnsibleModule(argument_spec=Lag_interfacesArgs.argument_spec,
required_if=required_if,
supports_check_mode=True)
result = Lag_interfaces(module).execute_module()
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,200 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The module file for junos_lldp_global
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'
}
DOCUMENTATION = """
---
module: junos_lldp_global
version_added: 2.9
short_description: Manage link layer discovery protocol (LLDP) attributes on Juniper JUNOS devices.
description:
- This module manages link layer discovery protocol (LLDP) attributes on Juniper JUNOS devices.
author: Ganesh Nalawade (@ganeshrn)
options:
config:
description: The list of link layer discovery protocol attribute configurations
type: dict
suboptions:
enabled:
description:
- This argument is a boolean value to enabled or disable LLDP.
type: bool
interval:
description:
- Frequency at which LLDP advertisements are sent (in seconds).
type: int
address:
description:
- This argument sets the management address from LLDP.
type: str
transmit_delay:
description:
- Specify the number of seconds the device waits before sending
advertisements to neighbors after a change is made in local system.
type: int
hold_multiplier:
description:
- Specify the number of seconds that LLDP information is held before it is
discarded. The multiplier value is used in combination with the
C(interval) value.
type: int
state:
description:
- The state of the configuration after module completion.
type: str
choices:
- merged
- replaced
- deleted
default: merged
requirements:
- ncclient (>=v0.6.4)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 18.4R1.
- This module works with connection C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
"""
EXAMPLES = """
# Using merged
# Before state:
# -------------
# user@junos01# # show protocols lldp
#
- name: Merge provided configuration with device configuration
junos_lldp_global:
config:
interval: 10000
address: 10.1.1.1
transmit_delay: 400
hold_multiplier: 10
state: merged
# After state:
# -------------
# user@junos01# show protocols lldp
# management-address 10.1.1.1;
# advertisement-interval 10000;
# transmit-delay 400;
# hold-multiplier 10;
# Using replaced
# Before state:
# -------------
# user@junos01# show protocols lldp
# management-address 10.1.1.1;
# advertisement-interval 10000;
# transmit-delay 400;
# hold-multiplier 10;
- name: Replace provided configuration with device configuration
junos_lldp_global:
config:
address: 20.2.2.2
hold_multiplier: 30
enabled: False
state: replaced
# After state:
# -------------
# user@junos01# show protocols lldp
# disable;
# management-address 20.2.2.2;
# hold-multiplier 30;
# Using deleted
# Before state:
# -------------
# user@junos01# show protocols lldp
# management-address 20.2.2.2;
# hold-multiplier 30;
- name: Delete lldp configuration (this will by default remove all lldp configuration)
junos_lldp_global:
state: deleted
# After state:
# -------------
# user@junos01# # show protocols lldp
#
"""
RETURN = """
before:
description: The configuration as structured data prior to module invocation.
returned: always
type: dict
sample: >
The configuration returned will always be in the same format
of the parameters above.
after:
description: The configuration as structured data after module completion.
returned: when changed
type: dict
sample: >
The configuration returned will always be in the same format
of the parameters above.
commands:
description: The set of commands pushed to the remote device.
returned: always
type: list
sample: ['xml 1', 'xml 2', 'xml 3']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.argspec.lldp_global.lldp_global import Lldp_globalArgs
from ansible.module_utils.network.junos.config.lldp_global.lldp_global import Lldp_global
def main():
"""
Main entry point for module execution
:returns: the result form module invocation
"""
required_if = [('state', 'merged', ('config',)),
('state', 'replaced', ('config',))]
module = AnsibleModule(argument_spec=Lldp_globalArgs.argument_spec,
required_if=required_if,
supports_check_mode=True)
result = Lldp_global(module).execute_module()
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,229 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The module file for junos_lldp_interfaces
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'
}
DOCUMENTATION = """
---
module: junos_lldp_interfaces
version_added: 2.9
short_description: Manage link layer discovery protocol (LLDP) attributes of interfaces on Juniper JUNOS devices
description:
- This module manages link layer discovery protocol (LLDP) attributes of interfaces on Juniper JUNOS devices.
author: Ganesh Nalawade (@ganeshrn)
options:
config:
description: The list of link layer discovery protocol interface attribute configurations
type: list
elements: dict
suboptions:
name:
description:
- Name of the interface LLDP needs to be configured on.
type: str
required: True
enabled:
description:
- This is a boolean value to control disabling of LLDP on the interface C(name)
type: bool
state:
description:
- The state of the configuration after module completion.
type: str
choices:
- merged
- replaced
- overridden
- deleted
default: merged
"""
EXAMPLES = """
# Using merged
# Before state:
# -------------
# user@junos01# # show protocols lldp
# management-address 10.1.1.1;
# advertisement-interval 10000;
- name: Merge provided configuration with device configuration
junos_lldp_interfaces:
config:
- name: ge-0/0/1
- name: ge-0/0/2
enabled: False
state: merged
# After state:
# -------------
# user@junos01# show protocols lldp
# management-address 10.1.1.1;
# advertisement-interval 10000;
# interface ge-0/0/1;
# interface ge-0/0/2 {
# disable;
# }
# Using replaced
# Before state:
# -------------
# user@junos01# show protocols lldp
# management-address 10.1.1.1;
# advertisement-interval 10000;
# interface ge-0/0/1;
# interface ge-0/0/2 {
# disable;
# }
- name: Replace provided configuration with device configuration
junos_lldp_interfaces:
config:
- name: ge-0/0/2
disable: False
- name: ge-0/0/3
enabled: False
state: replaced
# After state:
# -------------
# user@junos01# show protocols lldp
# management-address 10.1.1.1;
# advertisement-interval 10000;
# interface ge-0/0/1;
# interface ge-0/0/2;
# interface ge-0/0/3 {
# disable;
# }
# Using overridden
# Before state:
# -------------
# user@junos01# show protocols lldp
# management-address 10.1.1.1;
# advertisement-interval 10000;
# interface ge-0/0/1;
# interface ge-0/0/2 {
# disable;
# }
- name: Override provided configuration with device configuration
junos_lldp_interfaces:
config:
- name: ge-0/0/2
enabled: False
state: overridden
# After state:
# -------------
# user@junos01# show protocols lldp
# management-address 10.1.1.1;
# advertisement-interval 10000;
# interface ge-0/0/2 {
# disable;
# }
# Using deleted
# Before state:
# -------------
# user@junos01# show protocols lldp
# management-address 10.1.1.1;
# advertisement-interval 10000;
# interface ge-0/0/1;
# interface ge-0/0/2;
# interface ge-0/0/3 {
# disable;
# }
- name: Delete lldp interface configuration (this will not delete other lldp configuration)
junos_lldp_interfaces:
config:
- name: ge-0/0/1
- name: ge-0/0/3
state: deleted
# After state:
# -------------
# user@junos01# show protocols lldp
# management-address 10.1.1.1;
# advertisement-interval 10000;
# interface ge-0/0/2;
# interface ge-0/0/1;
"""
RETURN = """
before:
description: The configuration as structured data prior to module invocation.
returned: always
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
after:
description: The configuration as structured data after module completion.
returned: when changed
type: list
sample: >
The configuration returned will always be in the same format
of the parameters above.
commands:
description: The set of commands pushed to the remote device.
returned: always
type: list
sample: ['xml 1', 'xml 2', 'xml 3']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.argspec.lldp_interfaces.lldp_interfaces import Lldp_interfacesArgs
from ansible.module_utils.network.junos.config.lldp_interfaces.lldp_interfaces import Lldp_interfaces
def main():
"""
Main entry point for module execution
:returns: the result form module invocation
"""
required_if = [('state', 'merged', ('config',)),
('state', 'replaced', ('config',)),
('state', 'overridden', ('config',))]
module = AnsibleModule(argument_spec=Lldp_interfacesArgs.argument_spec,
required_if=required_if,
supports_check_mode=True)
result = Lldp_interfaces(module).execute_module()
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,284 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_logging
version_added: "2.4"
author: "Ganesh Nalawade (@ganeshrn)"
short_description: Manage logging on network devices
description:
- This module provides declarative management of logging
on Juniper JUNOS devices.
options:
dest:
description:
- Destination of the logs.
choices: ['console', 'host', 'file', 'user']
name:
description:
- If value of C(dest) is I(file) it indicates file-name,
for I(user) it indicates username and for I(host) indicates
the host name to be notified.
facility:
description:
- Set logging facility.
level:
description:
- Set logging severity levels.
aggregate:
description: List of logging definitions.
state:
description:
- State of the logging configuration.
default: present
choices: ['present', 'absent']
active:
description:
- Specifies whether or not the configuration is active or deactivated
default: True
type: bool
rotate_frequency:
description:
- Rotate log frequency in minutes, this is applicable if value
of I(dest) is C(file). The acceptable value is in range of 1 to 59.
This controls the frequency after which log file is rotated.
required: false
size:
description:
- Size of the file in archive, this is applicable if value
of I(dest) is C(file). The acceptable value is in range from 65536 to
1073741824 bytes.
required: false
files:
description:
- Number of files to be archived, this is applicable if value
of I(dest) is C(file). The acceptable value is in range from 1 to 1000.
required: false
requirements:
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
extends_documentation_fragment: junos
"""
EXAMPLES = """
- name: configure console logging
junos_logging:
dest: console
facility: any
level: critical
- name: remove console logging configuration
junos_logging:
dest: console
state: absent
- name: configure file logging
junos_logging:
dest: file
name: test
facility: pfe
level: error
- name: configure logging parameter
junos_logging:
files: 30
size: 65536
rotate_frequency: 10
- name: Configure file logging using aggregate
junos_logging:
dest: file
aggregate:
- name: test-1
facility: pfe
level: critical
- 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 }
- { dest: file, name: test-2, facility: kernel, level: emergency }
state: absent
"""
RETURN = """
diff.prepared:
description: Configuration difference before and after applying change.
returned: when configuration is changed and diff option is enabled.
type: str
sample: >
[edit system syslog]
+ [edit system syslog]
file interactive-commands { ... }
+ file test {
+ pfe critical;
+ }
"""
import collections
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.common.utils import remove_default_spec
from ansible.module_utils.network.junos.junos import junos_argument_spec, tostring
from ansible.module_utils.network.junos.junos import load_config, map_params_to_obj, map_obj_to_ele, to_param_list
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes, locked_config
USE_PERSISTENT_CONNECTION = True
def validate_files(value, module):
if value and not 1 <= value <= 1000:
module.fail_json(msg='files must be between 1 and 1000')
def validate_size(value, module):
if value and not 65536 <= value <= 1073741824:
module.fail_json(msg='size must be between 65536 and 1073741824')
def validate_rotate_frequency(value, module):
if value and not 1 <= value <= 59:
module.fail_json(msg='rotate_frequency must be between 1 and 59')
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(param.get(key), module)
def main():
""" main entry point for module execution
"""
element_spec = dict(
dest=dict(choices=['console', 'host', 'file', 'user']),
name=dict(),
facility=dict(),
level=dict(),
rotate_frequency=dict(type='int'),
size=dict(type='int'),
files=dict(type='int'),
src_addr=dict(),
state=dict(default='present', choices=['present', 'absent']),
active=dict(default=True, type='bool')
)
aggregate_spec = deepcopy(element_spec)
# remove default in aggregate spec, to handle common arguments
remove_default_spec(aggregate_spec)
argument_spec = dict(
aggregate=dict(type='list', elements='dict', options=aggregate_spec),
)
argument_spec.update(element_spec)
argument_spec.update(junos_argument_spec)
required_if = [('dest', 'host', ['name', 'facility', 'level']),
('dest', 'file', ['name', 'facility', 'level']),
('dest', 'user', ['name', 'facility', 'level']),
('dest', 'console', ['facility', 'level'])]
module = AnsibleModule(argument_spec=argument_spec,
required_if=required_if,
supports_check_mode=True)
warnings = list()
result = {'changed': False}
if warnings:
result['warnings'] = warnings
params = to_param_list(module)
requests = list()
for param in params:
# if key doesn't exist in the item, get it from module.params
for key in param:
if param.get(key) is None:
param[key] = module.params[key]
module._check_required_if(required_if, param)
item = param.copy()
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):
for req in requests:
diff = load_config(module, tostring(req), warnings, action='merge')
commit = not module.check_mode
if diff:
if commit:
commit_configuration(module)
else:
discard_changes(module)
result['changed'] = True
if module._diff:
result['diff'] = {'prepared': diff}
module.exit_json(**result)
if __name__ == "__main__":
main()

@ -1,193 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_netconf
version_added: "2.1"
author: "Peter Sprygada (@privateip)"
short_description: Configures the Junos Netconf system service
description:
- This module provides an abstraction that enables and configures
the netconf system service running on Junos devices. This module
can be used to easily enable the Netconf API. Netconf provides
a programmatic interface for working with configuration and state
resources as defined in RFC 6242. If the C(netconf_port) is not
mentioned in the task by default netconf will be enabled on port 830
only.
extends_documentation_fragment: junos
options:
netconf_port:
description:
- This argument specifies the port the netconf service should
listen on for SSH connections. The default port as defined
in RFC 6242 is 830.
required: false
default: 830
aliases: ['listens_on']
version_added: "2.2"
state:
description:
- Specifies the state of the C(junos_netconf) resource on
the remote device. If the I(state) argument is set to
I(present) the netconf service will be configured. If the
I(state) argument is set to I(absent) the netconf service
will be removed from the configuration.
required: false
default: present
choices: ['present', 'absent']
notes:
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(network_cli). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
- If C(netconf_port) value is not mentioned in task by default it will be enabled on port 830 only.
Although C(netconf_port) value can be from 1 through 65535, avoid configuring access on a port
that is normally assigned for another service. This practice avoids potential resource conflicts.
"""
EXAMPLES = """
- name: enable netconf service on port 830
junos_netconf:
listens_on: 830
state: present
- name: disable netconf service
junos_netconf:
state: absent
"""
RETURN = """
commands:
description: Returns the command sent to the remote device
returned: when changed is True
type: str
sample: 'set system services netconf ssh port 830'
"""
import re
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import ConnectionError
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.junos import junos_argument_spec, get_connection
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.six import iteritems
USE_PERSISTENT_CONNECTION = True
def map_obj_to_commands(updates, module):
want, have = updates
commands = list()
if want['state'] == 'absent':
if have['state'] == 'present':
commands.append('delete system services netconf')
else:
if have['state'] == 'absent' or want['netconf_port'] != have.get('netconf_port'):
commands.append(
'set system services netconf ssh port %s' % want['netconf_port']
)
return commands
def parse_port(config):
match = re.search(r'port (\d+)', config)
if match:
return int(match.group(1))
def map_config_to_obj(module):
conn = get_connection(module)
out = conn.get(command='show configuration system services netconf')
if out is None:
module.fail_json(msg='unable to retrieve current config')
config = str(out).strip()
obj = {'state': 'absent'}
if 'ssh' in config:
obj.update({
'state': 'present',
'netconf_port': parse_port(config)
})
return obj
def validate_netconf_port(value, module):
if not 1 <= value <= 65535:
module.fail_json(msg='netconf_port must be between 1 and 65535')
def map_params_to_obj(module):
obj = {
'netconf_port': module.params['netconf_port'],
'state': module.params['state']
}
for key, value in iteritems(obj):
# validate the param value (if validator func exists)
validator = globals().get('validate_%s' % key)
if callable(validator):
validator(value, module)
return obj
def load_config(module, config, commit=False):
conn = get_connection(module)
try:
resp = conn.edit_config(to_list(config) + ['top'], commit)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
diff = resp.get('diff', '')
return to_text(diff, errors='surrogate_then_replace').strip()
def main():
"""main entry point for module execution
"""
argument_spec = dict(
netconf_port=dict(type='int', default=830, aliases=['listens_on']),
state=dict(default='present', choices=['present', 'absent']),
)
argument_spec.update(junos_argument_spec)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
warnings = list()
result = {'changed': False, 'warnings': warnings}
want = map_params_to_obj(module)
have = map_config_to_obj(module)
commands = map_obj_to_commands((want, have), module)
result['commands'] = commands
if commands:
commit = not module.check_mode
diff = load_config(module, commands, commit=commit)
if diff:
if module._diff:
result['diff'] = {'prepared': diff}
result['changed'] = True
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,224 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_package
version_added: "2.1"
author: "Peter Sprygada (@privateip)"
short_description: Installs packages on remote devices running Junos
description:
- This module can install new and updated packages on remote
devices running Junos. The module will compare the specified
package with the one running on the remote device and install
the specified version if there is a mismatch
extends_documentation_fragment: junos
options:
src:
description:
- The I(src) argument specifies the path to the source package to be
installed on the remote device in the advent of a version mismatch.
The I(src) argument can be either a localized path or a full
path to the package file to install.
required: true
aliases: ['package']
version:
description:
- The I(version) argument can be used to explicitly specify the
version of the package that should be installed on the remote
device. If the I(version) argument is not specified, then
the version is extracts from the I(src) filename.
reboot:
description:
- In order for a package to take effect, the remote device must be
restarted. When enabled, this argument will instruct the module
to reboot the device once the updated package has been installed.
If disabled or the remote package does not need to be changed,
the device will not be started.
type: bool
default: 'yes'
no_copy:
description:
- The I(no_copy) argument is responsible for instructing the remote
device on where to install the package from. When enabled, the
package is transferred to the remote device prior to installing.
type: bool
default: 'no'
validate:
description:
- The I(validate) argument is responsible for instructing the remote
device to skip checking the current device configuration
compatibility with the package being installed. When set to false
validation is not performed.
version_added: 2.5
type: bool
default: 'yes'
force:
description:
- The I(force) argument instructs the module to bypass the package
version check and install the packaged identified in I(src) on
the remote device.
type: bool
default: 'no'
force_host:
description:
- The I(force_host) argument controls the way software package or
bundle is added on remote JUNOS host and is applicable
for JUNOS QFX5100 device. If the value is set to C(True) it
will ignore any warnings while adding the host software package or bundle.
type: bool
default: False
version_added: 2.8
issu:
description:
- The I(issu) argument is a boolean flag when set to C(True) allows
unified in-service software upgrade (ISSU) feature which enables
you to upgrade between two different Junos OS releases with no
disruption on the control plane and with minimal disruption of traffic.
type: bool
default: False
version_added: 2.8
ssh_private_key_file:
description:
- The C(ssh_private_key_file) argument is path to the SSH private key file.
This can be used if you need to provide a private key rather than loading
the key into the ssh-key-ring/environment
type: path
version_added: '2.10'
ssh_config:
description:
- The C(ssh_config) argument is path to the SSH configuration file.
This can be used to load SSH information from a configuration file.
If this option is not given by default ~/.ssh/config is queried.
type: path
version_added: '2.10'
requirements:
- junos-eznc
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Works with C(local) connections only.
- Since this module uses junos-eznc to establish connection with junos
device the netconf configuration parameters needs to be passed
using module options for example C(ssh_config) unlike other junos
modules that uses C(netconf) connection type.
"""
EXAMPLES = """
# the required set of connection arguments have been purposely left off
# the examples for brevity
- name: install local package on remote device
junos_package:
src: junos-vsrx-12.1X46-D10.2-domestic.tgz
- name: install local package on remote device without rebooting
junos_package:
src: junos-vsrx-12.1X46-D10.2-domestic.tgz
reboot: no
- name: install local package on remote device with jumpost
junos_package:
src: junos-vsrx-12.1X46-D10.2-domestic.tgz
ssh_config: /home/user/customsshconfig
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.junos import junos_argument_spec, get_device
try:
from jnpr.junos.utils.sw import SW
HAS_PYEZ = True
except ImportError:
HAS_PYEZ = False
def install_package(module, device):
junos = SW(device)
package = module.params['src']
no_copy = module.params['no_copy']
validate = module.params['validate']
force_host = module.params['force_host']
issu = module.params['issu']
def progress_log(dev, report):
module.log(report)
module.log('installing package')
result = junos.install(package, progress=progress_log, no_copy=no_copy,
validate=validate, force_host=force_host, issu=issu)
if not result:
module.fail_json(msg='Unable to install package on device')
if module.params['reboot']:
module.log('rebooting system')
junos.reboot()
def main():
""" Main entry point for Ansible module execution
"""
argument_spec = dict(
src=dict(type='path', required=True, aliases=['package']),
version=dict(),
reboot=dict(type='bool', default=True),
no_copy=dict(default=False, type='bool'),
validate=dict(default=True, type='bool'),
force=dict(type='bool', default=False),
transport=dict(default='netconf', choices=['netconf']),
force_host=dict(type='bool', default=False),
issu=dict(type='bool', default=False),
ssh_private_key_file=dict(type='path'),
ssh_config=dict(type='path')
)
argument_spec.update(junos_argument_spec)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
if module.params['provider'] is None:
module.params['provider'] = {}
if not HAS_PYEZ:
module.fail_json(
msg='junos-eznc is required but does not appear to be installed. '
'It can be installed using `pip install junos-eznc`'
)
result = dict(changed=False)
do_upgrade = module.params['force'] or False
device = get_device(module)
if not module.params['force']:
device.facts_refresh()
has_ver = device.facts.get('version')
wants_ver = module.params['version']
do_upgrade = has_ver != wants_ver
if do_upgrade:
if not module.check_mode:
install_package(module, device)
result['changed'] = True
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,232 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2019, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_ping
short_description: Tests reachability using ping from devices running Juniper JUNOS
description:
- Tests reachability using ping from devices running Juniper JUNOS to a remote destination.
- Tested against Junos (17.3R1.10)
- For a general purpose network module, see the M(net_ping) module.
- For Windows targets, use the M(win_ping) module instead.
- For targets running Python, use the M(ping) module instead.
author:
- Nilashish Chakraborty (@NilashishC)
version_added: '2.8'
options:
dest:
description:
- The IP Address or hostname (resolvable by the device) of the remote node.
required: true
count:
description:
- Number of packets to send to check reachability.
type: int
default: 5
source:
description:
- The IP Address to use while sending the ping packet(s).
interface:
description:
- The source interface to use while sending the ping packet(s).
ttl:
description:
- The time-to-live value for the ICMP packet(s).
type: int
size:
description:
- Determines the size (in bytes) of the ping packet(s).
type: int
interval:
description:
- Determines the interval (in seconds) between consecutive pings.
type: int
state:
description:
- Determines if the expected result is success or fail.
choices: [ absent, present ]
default: present
notes:
- For a general purpose network module, see the M(net_ping) module.
- For Windows targets, use the M(win_ping) module instead.
- For targets running Python, use the M(ping) module instead.
- This module works only with connection C(network_cli).
extends_documentation_fragment: junos
"""
EXAMPLES = """
- name: Test reachability to 10.10.10.10
junos_ping:
dest: 10.10.10.10
- name: Test reachability to 10.20.20.20 using source and size set
junos_ping:
dest: 10.20.20.20
size: 1024
ttl: 128
- name: Test unreachability to 10.30.30.30 using interval
junos_ping:
dest: 10.30.30.30
interval: 3
state: absent
- name: Test reachability to 10.40.40.40 setting count and interface
junos_ping:
dest: 10.40.40.40
interface: fxp0
count: 20
size: 512
"""
RETURN = """
commands:
description: List of commands sent.
returned: always
type: list
sample: ["ping 10.8.38.44 count 10 source 10.8.38.38 ttl 128"]
packet_loss:
description: Percentage of packets lost.
returned: always
type: str
sample: "0%"
packets_rx:
description: Packets successfully received.
returned: always
type: int
sample: 20
packets_tx:
description: Packets successfully transmitted.
returned: always
type: int
sample: 20
rtt:
description: The round trip time (RTT) stats.
returned: when ping succeeds
type: dict
sample: {"avg": 2, "max": 8, "min": 1, "stddev": 24}
"""
import re
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.junos import junos_argument_spec, get_connection
def main():
""" main entry point for module execution
"""
argument_spec = dict(
count=dict(type="int", default=5),
dest=dict(type="str", required=True),
source=dict(),
interface=dict(),
ttl=dict(type='int'),
size=dict(type='int'),
interval=dict(type='int'),
state=dict(type="str", choices=["absent", "present"], default="present"),
)
argument_spec.update(junos_argument_spec)
module = AnsibleModule(argument_spec=argument_spec)
count = module.params["count"]
dest = module.params["dest"]
source = module.params["source"]
size = module.params["size"]
ttl = module.params["ttl"]
interval = module.params["interval"]
interface = module.params['interface']
warnings = list()
results = {'changed': False}
if warnings:
results["warnings"] = warnings
results["commands"] = build_ping(dest, count, size, interval, source, ttl, interface)
conn = get_connection(module)
ping_results = conn.get(results["commands"])
rtt_info, rate_info = None, None
for line in ping_results.split("\n"):
if line.startswith('round-trip'):
rtt_info = line
if line.startswith('%s packets transmitted' % count):
rate_info = line
if rtt_info:
rtt = parse_rtt(rtt_info)
for k, v in rtt.items():
if rtt[k] is not None:
rtt[k] = float(v)
results["rtt"] = rtt
pkt_loss, rx, tx = parse_rate(rate_info)
results["packet_loss"] = str(pkt_loss) + "%"
results["packets_rx"] = int(rx)
results["packets_tx"] = int(tx)
validate_results(module, pkt_loss, results)
module.exit_json(**results)
def build_ping(dest, count, size=None, interval=None, source=None, ttl=None, interface=None):
cmd = "ping {0} count {1}".format(dest, str(count))
if source:
cmd += " source {0}".format(source)
if interface:
cmd += " interface {0}".format(interface)
if ttl:
cmd += " ttl {0}".format(str(ttl))
if size:
cmd += " size {0}".format(str(size))
if interval:
cmd += " interval {0}".format(str(interval))
return cmd
def parse_rate(rate_info):
rate_re = re.compile(
r"(?P<tx>\d*) packets transmitted,(?:\s*)(?P<rx>\d*) packets received,(?:\s*)(?P<pkt_loss>\d*)% packet loss")
rate = rate_re.match(rate_info)
return rate.group("pkt_loss"), rate.group("rx"), rate.group("tx")
def parse_rtt(rtt_info):
rtt_re = re.compile(
r"round-trip (?:.*)=(?:\s*)(?P<min>\d+\.\d+).(?:\d*)/(?P<avg>\d+\.\d+).(?:\d*)/(?P<max>\d*\.\d*).(?:\d*)/(?P<stddev>\d*\.\d*)")
rtt = rtt_re.match(rtt_info)
return rtt.groupdict()
def validate_results(module, loss, results):
state = module.params["state"]
if state == "present" and int(loss) == 100:
module.fail_json(msg="Ping failed unexpectedly", **results)
elif state == "absent" and int(loss) < 100:
module.fail_json(msg="Ping succeeded unexpectedly", **results)
if __name__ == "__main__":
main()

@ -1,173 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_rpc
version_added: "2.3"
author: "Peter Sprygada (@privateip)"
short_description: Runs an arbitrary RPC over NetConf on an Juniper JUNOS device
description:
- Sends a request to the remote device running JUNOS to execute the
specified RPC using the NetConf transport. The reply is then
returned to the playbook in the C(xml) key. If an alternate output
format is requested, the reply is transformed to the requested output.
extends_documentation_fragment: junos
options:
rpc:
description:
- The C(rpc) argument specifies the RPC call to send to the
remote devices to be executed. The RPC Reply message is parsed
and the contents are returned to the playbook.
required: true
args:
description:
- The C(args) argument provides a set of arguments for the RPC
call and are encoded in the request message. This argument
accepts a set of key=value arguments.
attrs:
description:
- The C(attrs) arguments defines a list of attributes and their values
to set for the RPC call. This accepts a dictionary of key-values.
version_added: "2.5"
output:
description:
- The C(output) argument specifies the desired output of the
return data. This argument accepts one of C(xml), C(text),
or C(json). For C(json), the JUNOS device must be running a
version of software that supports native JSON output.
default: xml
requirements:
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
"""
EXAMPLES = """
- name: collect interface information using rpc
junos_rpc:
rpc: get-interface-information
args:
interface-name: em0
media: True
- name: get system information
junos_rpc:
rpc: get-system-information
- name: load configuration
junos_rpc:
rpc: load-configuration
attrs:
action: override
url: /tmp/config.conf
"""
RETURN = """
xml:
description: The xml return string from the rpc request.
returned: always
type: str
output:
description: The rpc rely converted to the output format.
returned: always
type: str
output_lines:
description: The text output split into lines for readability.
returned: always
type: list
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.common.netconf import exec_rpc
from ansible.module_utils.network.junos.junos import junos_argument_spec, tostring
from ansible.module_utils.six import iteritems
USE_PERSISTENT_CONNECTION = True
try:
from lxml.etree import Element, SubElement
except ImportError:
from xml.etree.ElementTree import Element, SubElement
def main():
"""main entry point for Ansible module
"""
argument_spec = dict(
rpc=dict(required=True),
args=dict(type='dict'),
attrs=dict(type='dict'),
output=dict(default='xml', choices=['xml', 'json', 'text']),
)
argument_spec.update(junos_argument_spec)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=False)
warnings = list()
result = {'changed': False, 'warnings': warnings}
rpc = str(module.params['rpc']).replace('_', '-')
if all((module.check_mode, not rpc.startswith('get'))):
module.fail_json(msg='invalid rpc for running in check_mode')
args = module.params['args'] or {}
attrs = module.params['attrs'] or {}
xattrs = {'format': module.params['output']}
for key, value in iteritems(attrs):
xattrs.update({key: value})
element = Element(module.params['rpc'], xattrs)
for key, value in iteritems(args):
key = str(key).replace('_', '-')
if isinstance(value, list):
for item in value:
child = SubElement(element, key)
if item is not True:
child.text = item
else:
child = SubElement(element, key)
if value is not True:
child.text = value
reply = exec_rpc(module, tostring(element), ignore_warning=False)
result['xml'] = tostring(reply)
if module.params['output'] == 'text':
data = reply.find('.//output')
result['output'] = data.text.strip()
result['output_lines'] = result['output'].split('\n')
elif module.params['output'] == 'json':
result['output'] = module.from_json(reply.text.strip())
else:
result['output'] = tostring(reply).split('\n')
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,180 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2018, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_scp
version_added: "2.5"
author: "Christian Giese (@GIC-de)"
short_description: Transfer files from or to remote devices running Junos
description:
- This module transfers files via SCP from or to remote devices
running Junos.
extends_documentation_fragment: junos
options:
src:
description:
- The C(src) argument takes a single path, or a list of paths to be
transferred. The argument C(recursive) must be C(true) to transfer
directories.
required: true
dest:
description:
- The C(dest) argument specifies the path in which to receive the files.
default: '.'
recursive:
description:
- The C(recursive) argument enables recursive transfer of files and
directories.
type: bool
default: 'no'
remote_src:
description:
- The C(remote_src) argument enables the download of files (I(scp get)) from
the remote device. The default behavior is to upload files (I(scp put))
to the remote device.
type: bool
default: 'no'
ssh_private_key_file:
description:
- The C(ssh_private_key_file) argument is path to the SSH private key file.
This can be used if you need to provide a private key rather than loading
the key into the ssh-key-ring/environment
type: path
version_added: '2.10'
ssh_config:
description:
- The C(ssh_config) argument is path to the SSH configuration file.
This can be used to load SSH information from a configuration file.
If this option is not given by default ~/.ssh/config is queried.
type: path
version_added: '2.10'
requirements:
- junos-eznc
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vMX JUNOS version 17.3R1.10.
- Works with C(local) connections only.
- Since this module uses junos-eznc to establish connection with junos
device the netconf configuration parameters needs to be passed
using module options for example C(ssh_config) unlike other junos
modules that uses C(netconf) connection type.
"""
EXAMPLES = """
# the required set of connection arguments have been purposely left off
# the examples for brevity
- name: upload local file to home directory on remote device
junos_scp:
src: test.tgz
- name: upload local file to tmp directory on remote device
junos_scp:
src: test.tgz
dest: /tmp/
- name: download file from remote device
junos_scp:
src: test.tgz
remote_src: true
- name: ssh config file path for jumphost config
junos_scp:
src: test.tgz
remote_src: true
ssh_config: /home/user/customsshconfig
"""
RETURN = """
changed:
description: always true
returned: always
type: bool
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.junos import junos_argument_spec, get_device
from ansible.module_utils._text import to_native
try:
from jnpr.junos.utils.scp import SCP
HAS_PYEZ = True
except ImportError:
HAS_PYEZ = False
def transfer_files(module, device):
dest = module.params['dest']
recursive = module.params['recursive']
with SCP(device) as scp:
for src in module.params['src']:
if module.params['remote_src']:
scp.get(src.strip(), local_path=dest, recursive=recursive)
else:
scp.put(src.strip(), remote_path=dest, recursive=recursive)
def main():
""" Main entry point for Ansible module execution
"""
argument_spec = dict(
src=dict(type='list', required=True),
dest=dict(type='path', required=False, default="."),
recursive=dict(type='bool', default=False),
remote_src=dict(type='bool', default=False),
ssh_private_key_file=dict(type='path'),
ssh_config=dict(type='path'),
transport=dict(default='netconf', choices=['netconf'])
)
argument_spec.update(junos_argument_spec)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
if module.params['provider'] is None:
module.params['provider'] = {}
if not HAS_PYEZ:
module.fail_json(
msg='junos-eznc is required but does not appear to be installed. '
'It can be installed using `pip install junos-eznc`'
)
result = dict(changed=True)
if not module.check_mode:
# open pyez connection and transfer files via SCP
try:
device = get_device(module)
transfer_files(module, device)
except Exception as ex:
module.fail_json(
msg=to_native(ex)
)
finally:
try:
# close pyez connection and ignore exceptions
device.close()
except Exception:
pass
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,282 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The module file for junos_static_routes
"""
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'
}
DOCUMENTATION = """
---
module: junos_static_routes
version_added: '2.10'
short_description: Manage static routes on Juniper JUNOS devices
description: This module provides declarative management of static routes on Juniper JUNOS devices
author: Daniel Mellado (@dmellado)
requirements:
- ncclient (>=v0.6.4)
- xmltodict (>=0.12)
notes:
- This module requires the netconf system service be enabled on the device being managed.
- This module works with connection C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- Tested against JunOS v18.4R1
options:
config:
description: A dictionary of static routes options
type: list
elements: dict
suboptions:
vrf:
description:
- Virtual Routing and Forwarding (VRF) name
type: str
address_families:
description:
- Address family to use for the static routes
elements: dict
type: list
suboptions:
afi:
description:
- afi to use for the static routes
type: str
required: true
choices:
- ipv4
- ipv6
routes:
description:
- Static route configuration
elements: dict
type: list
suboptions:
dest:
description:
- Static route destination including prefix
type: str
next_hop:
elements: dict
type: list
description:
- Next hop to destination
suboptions:
forward_router_address:
description:
- List of next hops
type: str
metric:
description:
- Metric value for the static route
type: int
state:
description:
- The state the configuration should be left in
type: str
choices:
- merged
- replaced
- overridden
- deleted
default: merged
"""
EXAMPLES = """
---
# Using deleted
# Before state
# ------------
#
# admin# show routing-options
# static {
# route 192.168.47.0/24 next-hop 172.16.1.2;
# route 192.168.16.0/24 next-hop 172.16.1.2;
# route 10.200.16.75/24 next-hop 10.200.16.2;
# }
- name: Delete provided configuration (default operation is merge)
junos_static_routes:
config:
- address_families:
- afi: 'ipv4'
routes:
- dest: 10.200.16.75/24
next_hop:
- forward_router_address: 10.200.16.2
state: deleted
# After state:
# ------------
#
# admin# show routing-options
# static {
# route 192.168.47.0/24 next-hop 172.16.1.2;
# route 192.168.16.0/24 next-hop 172.16.1.2;
# }
# Using merged
# Before state
# ------------
#
# admin# show routing-options
# static {
# route 192.168.47.0/24 next-hop 172.16.1.2;
# route 192.168.16.0/24 next-hop 172.16.1.2;
# }
- name: Merge provided configuration with device configuration (default operation is merge)
junos_static_routes:
config:
- address_families:
- afi: 'ipv4'
routes:
- dest: 10.200.16.75/24
next_hop:
- forward_router_address: 10.200.16.2
state: merged
# After state:
# ------------
#
# admin# show routing-options
# static {
# route 192.168.47.0/24 next-hop 172.16.1.2;
# route 192.168.16.0/24 next-hop 172.16.1.2;
# route 10.200.16.75/24 next-hop 10.200.16.2;
# }
# Using overridden
# Before state
# ------------
#
# admin# show routing-options
# static {
# route 192.168.47.0/24 next-hop 172.16.1.2;
# route 192.168.16.0/24 next-hop 172.16.0.1;
# }
- name: Override provided configuration with device configuration (default operation is merge)
junos_static_routes:
config:
- address_families:
- afi: 'ipv4'
routes:
- dest: 10.200.16.75/24
next_hop:
- forward_router_address: 10.200.16.2
state: overridden
# After state:
# ------------
#
# admin# show routing-options
# static {
# route 10.200.16.75/24 next-hop 10.200.16.2;
# }
# Using replaced
# Before state
# ------------
#
# admin# show routing-options
# static {
# route 192.168.47.0/24 next-hop 172.16.1.2;
# route 192.168.16.0/24 next-hop 172.16.1.2;
# }
- name: Replace provided configuration with device configuration (default operation is merge)
junos_static_routes:
config:
- address_families:
- afi: 'ipv4'
routes:
- dest: 192.168.47.0/24
next_hop:
- forward_router_address: 10.200.16.2
state: replaced
# After state:
# ------------
#
# admin# show routing-options
# static {
# route 192.168.47.0/24 next-hop 10.200.16.2;
# route 192.168.16.0/24 next-hop 172.16.1.2;
# }
"""
RETURN = """
before:
description: The configuration prior to the model invocation.
returned: always
type: str
sample: >
The configuration returned will always be in the same format
of the parameters above.
after:
description: The resulting configuration model invocation.
returned: when changed
type: str
sample: >
The configuration returned will always be in the same format
of the parameters above.
commands:
description: The set of commands pushed to the remote device.
returned: always
type: list
sample: ['command 1', 'command 2', 'command 3']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.argspec.static_routes.static_routes import Static_routesArgs
from ansible.module_utils.network.junos.config.static_routes.static_routes import Static_routes
def main():
"""
Main entry point for module execution
:returns: the result form module invocation
"""
module = AnsibleModule(argument_spec=Static_routesArgs.argument_spec,
supports_check_mode=True)
result = Static_routes(module).execute_module()
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,190 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_system
version_added: "2.4"
author: "Ganesh Nalawade (@ganeshrn)"
short_description: Manage the system attributes on Juniper JUNOS devices
description:
- This module provides declarative management of node system attributes
on Juniper JUNOS devices. It provides an option to configure host system
parameters or remove those parameters from the device active
configuration.
options:
hostname:
description:
- Configure the device hostname parameter. This option takes an ASCII string value.
domain_name:
description:
- Configure the IP domain name
on the remote device to the provided value. Value
should be in the dotted name form and will be
appended to the C(hostname) to create a fully-qualified
domain name.
domain_search:
description:
- Provides the list of domain suffixes to
append to the hostname for the purpose of doing name resolution.
This argument accepts a list of names and will be reconciled
with the current active configuration on the running node.
name_servers:
description:
- List of DNS name servers by IP address to use to perform name resolution
lookups. This argument accepts either a list of DNS servers See
examples.
state:
description:
- State of the configuration
values in the device's current active configuration. When set
to I(present), the values should be configured in the device active
configuration and when set to I(absent) the values should not be
in the device active configuration
default: present
choices: ['present', 'absent']
active:
description:
- Specifies whether or not the configuration is active or deactivated
default: True
type: bool
requirements:
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
extends_documentation_fragment: junos
"""
EXAMPLES = """
- name: configure hostname and domain name
junos_system:
hostname: junos01
domain_name: test.example.com
domain-search:
- ansible.com
- redhat.com
- juniper.com
- name: remove configuration
junos_system:
state: absent
- name: configure name servers
junos_system:
name_servers:
- 8.8.8.8
- 8.8.4.4
"""
RETURN = """
diff.prepared:
description: Configuration difference before and after applying change.
returned: when configuration is changed and diff option is enabled.
type: str
sample: >
[edit system]
+ host-name test;
+ domain-name ansible.com;
+ domain-search redhat.com;
[edit system name-server]
172.26.1.1 { ... }
+ 8.8.8.8;
"""
import collections
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.junos import junos_argument_spec, tostring
from ansible.module_utils.network.junos.junos import load_config, map_params_to_obj, map_obj_to_ele
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes, locked_config
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(
hostname=dict(),
domain_name=dict(),
domain_search=dict(type='list'),
name_servers=dict(type='list'),
state=dict(choices=['present', 'absent'], default='present'),
active=dict(default=True, type='bool')
)
argument_spec.update(junos_argument_spec)
params = ['hostname', 'domain_name', 'domain_search', 'name_servers']
required_if = [('state', 'present', params, True),
('state', 'absent', params, True),
('state', 'active', params, True),
('state', 'suspend', params, True)]
module = AnsibleModule(argument_spec=argument_spec,
required_if=required_if,
supports_check_mode=True)
warnings = list()
result = {'changed': False}
if warnings:
result['warnings'] = warnings
top = 'system'
param_to_xpath_map = collections.OrderedDict()
param_to_xpath_map.update([
('hostname', {'xpath': 'host-name', 'leaf_only': True}),
('domain_name', {'xpath': 'domain-name', 'leaf_only': True}),
('domain_search', {'xpath': 'domain-search', 'leaf_only': True, 'value_req': True}),
('name_servers', {'xpath': 'name-server/name', 'is_key': True})
])
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)
with locked_config(module):
diff = load_config(module, tostring(ele), warnings, action='merge')
commit = not module.check_mode
if diff:
if commit:
commit_configuration(module)
else:
discard_changes(module)
result['changed'] = True
if module._diff:
result['diff'] = {'prepared': diff}
module.exit_json(**result)
if __name__ == "__main__":
main()

@ -1,371 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_user
version_added: "2.3"
author: "Peter Sprygada (@privateip)"
short_description: Manage local user accounts on Juniper JUNOS devices
description:
- This module manages locally configured user accounts on remote
network devices running the JUNOS operating system. It provides
a set of arguments for creating, removing and updating locally
defined accounts
extends_documentation_fragment: junos
options:
aggregate:
description:
- The C(aggregate) argument defines a list of users to be configured
on the remote device. The list of users will be compared against
the current users and only changes will be added or removed from
the device configuration. This argument is mutually exclusive with
the name argument.
version_added: "2.4"
aliases: ['users', 'collection']
name:
description:
- The C(name) argument defines the username of the user to be created
on the system. This argument must follow appropriate usernaming
conventions for the target device running JUNOS. This argument is
mutually exclusive with the C(aggregate) argument.
full_name:
description:
- The C(full_name) argument provides the full name of the user
account to be created on the remote device. This argument accepts
any text string value.
role:
description:
- The C(role) argument defines the role of the user account on the
remote system. User accounts can have more than one role
configured.
choices: ['operator', 'read-only', 'super-user', 'unauthorized']
sshkey:
description:
- The C(sshkey) argument defines the public SSH key to be configured
for the user account on the remote system. This argument must
be a valid SSH key
encrypted_password:
description:
- The C(encrypted_password) argument set already hashed password
for the user account on the remote system.
version_added: "2.8"
purge:
description:
- The C(purge) argument instructs the module to consider the
users definition absolute. It will remove any previously configured
users on the device with the exception of the current defined
set of aggregate.
type: bool
default: 'no'
state:
description:
- The C(state) argument configures the state of the user definitions
as it relates to the device operational configuration. When set
to I(present), the user should be configured in the device active
configuration and when set to I(absent) the user should not be
in the device active configuration
default: present
choices: ['present', 'absent']
active:
description:
- Specifies whether or not the configuration is active or deactivated
type: bool
default: 'yes'
version_added: "2.4"
requirements:
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
"""
EXAMPLES = """
- name: create new user account
junos_user:
name: ansible
role: super-user
sshkey: "{{ lookup('file', '~/.ssh/ansible.pub') }}"
state: present
- name: remove a user account
junos_user:
name: ansible
state: absent
- name: remove all user accounts except ansible
junos_user:
aggregate:
- name: ansible
purge: yes
- name: set user password
junos_user:
name: ansible
role: super-user
encrypted_password: "{{ 'my-password' | password_hash('sha512') }}"
state: present
- 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 = """
diff.prepared:
description: Configuration difference before and after applying change.
returned: when configuration is changed and diff option is enabled.
type: str
sample: >
[edit system login]
+ user test-user {
+ uid 2005;
+ class read-only;
+ }
"""
from functools import partial
from copy import deepcopy
from ansible.module_utils._text import to_text
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import ConnectionError
from ansible.module_utils.network.common.utils import remove_default_spec
from ansible.module_utils.network.junos.junos import junos_argument_spec, get_connection, tostring
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes
from ansible.module_utils.network.junos.junos import load_config, locked_config
from ansible.module_utils.six import iteritems
try:
from lxml.etree import Element, SubElement
except ImportError:
from xml.etree.ElementTree import Element, SubElement
ROLES = ['operator', 'read-only', 'super-user', 'unauthorized']
USE_PERSISTENT_CONNECTION = True
def handle_purge(module, want):
want_users = [item['name'] for item in want]
element = Element('system')
login = SubElement(element, 'login')
conn = get_connection(module)
try:
reply = conn.execute_rpc(tostring(Element('get-configuration')), ignore_warning=False)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
users = reply.xpath('configuration/system/login/user/name')
if users:
for item in users:
name = item.text
if name not in want_users and name != 'root':
user = SubElement(login, 'user', {'operation': 'delete'})
SubElement(user, 'name').text = name
if element.xpath('/system/login/user/name'):
return element
def map_obj_to_ele(module, want):
element = Element('system')
login = SubElement(element, 'login')
for item in want:
if item['state'] != 'present':
if item['name'] == 'root':
module.fail_json(msg="cannot delete the 'root' account.")
operation = 'delete'
else:
operation = 'merge'
if item['name'] != 'root':
user = SubElement(login, 'user', {'operation': operation})
SubElement(user, 'name').text = item['name']
else:
user = auth = SubElement(element, 'root-authentication', {'operation': operation})
if operation == 'merge':
if item['name'] == 'root' and (not item['active'] or item['role'] or item['full_name']):
module.fail_json(msg="'root' account cannot be deactivated or be assigned a role and a full name")
if item['active']:
user.set('active', 'active')
else:
user.set('inactive', 'inactive')
if item['role']:
SubElement(user, 'class').text = item['role']
if item.get('full_name'):
SubElement(user, 'full-name').text = item['full_name']
if item.get('sshkey'):
auth = SubElement(user, 'authentication')
if 'ssh-rsa' in item['sshkey']:
ssh_rsa = SubElement(auth, 'ssh-rsa')
elif 'ssh-dss' in item['sshkey']:
ssh_rsa = SubElement(auth, 'ssh-dsa')
elif 'ecdsa-sha2' in item['sshkey']:
ssh_rsa = SubElement(auth, 'ssh-ecdsa')
elif 'ssh-ed25519' in item['sshkey']:
ssh_rsa = SubElement(auth, 'ssh-ed25519')
SubElement(ssh_rsa, 'name').text = item['sshkey']
if item.get('encrypted_password'):
auth = SubElement(user, 'authentication')
SubElement(auth, 'encrypted-password').text = item['encrypted_password']
return element
def get_param_value(key, item, module):
# if key doesn't exist in the item, get it from module.params
if not item.get(key):
value = module.params[key]
# if key does exist, do a type check on it to validate it
else:
value_type = module.argument_spec[key].get('type', 'str')
type_checker = module._CHECK_ARGUMENT_TYPES_DISPATCHER[value_type]
type_checker(item[key])
value = item[key]
# validate the param value (if validator func exists)
validator = globals().get('validate_%s' % key)
if all((value, validator)):
validator(value, module)
return value
def map_params_to_obj(module):
aggregate = module.params['aggregate']
if not aggregate:
if not module.params['name'] and module.params['purge']:
return list()
elif not module.params['name']:
module.fail_json(msg='missing required argument: name')
else:
collection = [{'name': module.params['name']}]
else:
collection = list()
for item in aggregate:
if not isinstance(item, dict):
collection.append({'username': item})
elif 'name' not in item:
module.fail_json(msg='missing required argument: name')
else:
collection.append(item)
objects = list()
for item in collection:
get_value = partial(get_param_value, item=item, module=module)
item.update({
'full_name': get_value('full_name'),
'role': get_value('role'),
'encrypted_password': get_value('encrypted_password'),
'sshkey': get_value('sshkey'),
'state': get_value('state'),
'active': get_value('active')
})
for key, value in iteritems(item):
# validate the param value (if validator func exists)
validator = globals().get('validate_%s' % key)
if all((value, validator)):
validator(value, module)
objects.append(item)
return objects
def main():
""" main entry point for module execution
"""
element_spec = dict(
name=dict(),
full_name=dict(),
role=dict(choices=ROLES),
encrypted_password=dict(no_log=True),
sshkey=dict(),
state=dict(choices=['present', 'absent'], default='present'),
active=dict(type='bool', default=True)
)
aggregate_spec = deepcopy(element_spec)
aggregate_spec['name'] = dict(required=True)
# remove default in aggregate spec, to handle common arguments
remove_default_spec(aggregate_spec)
argument_spec = dict(
aggregate=dict(type='list', elements='dict', options=aggregate_spec, aliases=['collection', 'users']),
purge=dict(default=False, type='bool')
)
argument_spec.update(element_spec)
argument_spec.update(junos_argument_spec)
mutually_exclusive = [['aggregate', 'name']]
module = AnsibleModule(argument_spec=argument_spec,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True)
warnings = list()
result = {'changed': False, 'warnings': warnings}
want = map_params_to_obj(module)
ele = map_obj_to_ele(module, want)
purge_request = None
if module.params['purge']:
purge_request = handle_purge(module, want)
with locked_config(module):
if purge_request:
load_config(module, tostring(purge_request), warnings, action='replace')
diff = load_config(module, tostring(ele), warnings, action='merge')
commit = not module.check_mode
if diff:
if commit:
commit_configuration(module)
else:
discard_changes(module)
result['changed'] = True
if module._diff:
result['diff'] = {'prepared': diff}
module.exit_json(**result)
if __name__ == "__main__":
main()

@ -1,283 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#############################################
# WARNING #
#############################################
#
# This file is auto generated by the resource
# module builder playbook.
#
# Do not edit this file manually.
#
# Changes to this file will be over written
# by the resource module builder.
#
# Changes should be made in the model used to
# generate this file or in the resource module
# builder template.
#
#############################################
"""
The module file for junos_vlans
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'
}
DOCUMENTATION = """
---
module: junos_vlans
version_added: 2.9
short_description: Create and manage VLAN configurations on Junos OS
description: This module creates and manages VLAN configurations on Junos OS.
author: Daniel Mellado (@danielmellado)
requirements:
- ncclient (>=v0.6.4)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed
- Tested against Junos OS 18.4R1
- This module works with connection C(netconf). See L(the Junos OS
Platform Options,../network/user_guide/platform_junos.html).
options:
config:
description: A dictionary of Vlan options
type: list
elements: dict
suboptions:
vlan_id:
description:
- IEEE 802.1q VLAN identifier for VLAN (1..4094).
type: int
required: true
name:
description:
- Name of VLAN.
type: str
required: true
description:
description:
- Text description of VLANs
type: str
state:
description:
- The state of the configuration after module completion.
type: str
choices:
- merged
- replaced
- overridden
- deleted
default: merged
"""
EXAMPLES = """
# Using merged
#############
# Before State
# ------------
#
# admin# show vlans
# vlan-2 {
# vlan-id 2;
# }
# vlan-3 {
# vlan-id 3;
# }
- name: Merge JUNOS vlan
junos_vlans:
config:
- name: vlan-1
vlan-id: 1
state: merged
# After State
# -----------
#
# admin# show vlans
# vlan-1 {
# vlan-id 1;
# }
# vlan-2 {
# vlan-id 2;
# }
# vlan-3 {
# vlan-id 3;
# }
# Using replaced
################
# Before State
# ------------
#
# admin# show vlans
# vlan-1 {
# vlan-id 1;
# }
# vlan-2 {
# vlan-id 2;
# }
# vlan-3 {
# vlan-id 3;
# }
- name: Replace JUNOS vlan
junos_vlans:
config:
- name: vlan-1
vlan-id: 10
- name: vlan-3
vlan-id: 30
state: replaced
# After State
# -----------
#
# admin# show vlans
# vlan-1 {
# vlan-id 10;
# }
# vlan-2 {
# vlan-id 2;
# }
# vlan-3 {
# vlan-id 30;
# }
# Using overridden
##################
# Before State
# ------------
#
# admin# show vlans
# vlan-1 {
# vlan-id 1;
# }
# vlan-2 {
# vlan-id 2;
# }
# vlan-3 {
# vlan-id 3;
# }
- name: Override JUNOS vlan
junos_vlans:
config:
- name: vlan-4
vlan-id: 100
- name: vlan-2
vlan-id: 200
state: overridden
# After State
# -----------
#
# admin# show vlans
# vlan-2 {
# vlan-id 200;
# }
# vlan-4 {
# vlan-id 100;
# }
#Using deleted
##############
# Before State
# ------------
#
# admin# show vlans
# vlan-1 {
# vlan-id 1;
# }
# vlan-2 {
# vlan-id 2;
# }
# vlan-3 {
# vlan-id 3;
# }
- name: Delete JUNOS vlan
junos_vlans:
config:
- name: vlan-1
state: deleted
# After State
# -----------
#
# admin# show vlans
# vlan-2 {
# vlan-id 2;
# }
# vlan-3 {
# vlan-id 3;
# }
"""
RETURN = """
before:
description: The configuration as structured data prior to module invocation.
returned: always
type: str
sample: >
The configuration returned will always be in the same format
of the parameters above.
after:
description: The configuration as structured data after module completion.
returned: when changed
type: str
sample: >
The configuration returned will always be in the same format
of the parameters above.
commands:
description: The set of commands pushed to the remote device.
returned: always
type: list
sample: ['xml 1', 'xml 2', 'xml 3']
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.argspec.vlans.vlans import VlansArgs
from ansible.module_utils.network.junos.config.vlans.vlans import Vlans
def main():
"""
Main entry point for module execution
:returns: the result form module invocation
"""
required_if = [('state', 'merged', ('config',)),
('state', 'replaced', ('config',)),
('state', 'overridden', ('config',))]
module = AnsibleModule(argument_spec=VlansArgs.argument_spec,
required_if=required_if,
supports_check_mode=True)
result = Vlans(module).execute_module()
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -1,271 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'network'}
DOCUMENTATION = """
---
module: junos_vrf
version_added: "2.4"
author: "Ganesh Nalawade (@ganeshrn)"
short_description: Manage the VRF definitions on Juniper JUNOS devices
description:
- This module provides declarative management of VRF definitions on
Juniper JUNOS devices. It allows playbooks to manage individual or
the entire VRF collection.
options:
name:
description:
- The name of the VRF definition to be managed on the remote IOS
device. The VRF definition name is an ASCII string name used
to uniquely identify the VRF. This argument is mutually exclusive
with the C(aggregate) argument
description:
description:
- Provides a short description of the VRF definition in the
current active configuration. The VRF definition value accepts
alphanumeric characters used to provide additional information
about the VRF.
rd:
description:
- The router-distinguisher value uniquely identifies the VRF to
routing processes on the remote IOS system. The RD value takes
the form of C(A:B) where C(A) and C(B) are both numeric values.
interfaces:
description:
- Identifies the set of interfaces that
should be configured in the VRF. Interfaces must be routed
interfaces in order to be placed into a VRF.
target:
description:
- It configures VRF target community configuration. The target value takes
the form of C(target:A:B) where C(A) and C(B) are both numeric values.
table_label:
description:
- Causes JUNOS to allocate a VPN label per VRF rather than per VPN FEC.
This allows for forwarding of traffic to directly connected subnets, COS
Egress filtering etc.
type: bool
aggregate:
description:
- The set of VRF definition objects to be configured on the remote
JUNOS device. Ths list entries can either be the VRF name or a hash
of VRF definitions and attributes. This argument is mutually
exclusive with the C(name) argument.
state:
description:
- Configures the state of the VRF definition
as it relates to the device operational configuration. When set
to I(present), the VRF should be configured in the device active
configuration and when set to I(absent) the VRF should not be
in the device active configuration
default: present
choices: ['present', 'absent']
active:
description:
- Specifies whether or not the configuration is active or deactivated
default: True
type: bool
requirements:
- ncclient (>=v0.5.2)
notes:
- This module requires the netconf system service be enabled on
the remote device being managed.
- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
- This module also works with C(local) connections for legacy playbooks.
extends_documentation_fragment: junos
"""
EXAMPLES = """
- name: Configure vrf configuration
junos_vrf:
name: test-1
description: test-vrf-1
interfaces:
- ge-0/0/3
- ge-0/0/2
rd: 192.0.2.1:10
target: target:65514:113
state: present
- name: Remove vrf configuration
junos_vrf:
name: test-1
description: test-vrf-1
interfaces:
- ge-0/0/3
- ge-0/0/2
rd: 192.0.2.1:10
target: target:65514:113
state: absent
- name: Deactivate vrf configuration
junos_vrf:
name: test-1
description: test-vrf-1
interfaces:
- ge-0/0/3
- ge-0/0/2
rd: 192.0.2.1:10
target: target:65514:113
active: False
- name: Activate vrf configuration
junos_vrf:
name: test-1
description: test-vrf-1
interfaces:
- ge-0/0/3
- ge-0/0/2
rd: 192.0.2.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: 192.0.2.1:10
target: target:65514:113
- name: test-2
description: test-vrf-2
interfaces:
- ge-0/0/4
- ge-0/0/5
rd: 192.0.2.2:10
target: target:65515:114
state: present
"""
RETURN = """
diff.prepared:
description: Configuration difference before and after applying change.
returned: when configuration is changed and diff option is enabled.
type: str
sample: >
[edit routing-instances]
+ test-1 {
+ description test-vrf-1;
+ instance-type vrf;
+ interface ge-0/0/2.0;
+ interface ge-0/0/3.0;
+ route-distinguisher 192.0.2.1:10;
+ vrf-target target:65514:113;
+ }
"""
import collections
from copy import deepcopy
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.common.utils import remove_default_spec
from ansible.module_utils.network.junos.junos import junos_argument_spec, tostring
from ansible.module_utils.network.junos.junos import load_config, map_params_to_obj, map_obj_to_ele, to_param_list
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes, locked_config
USE_PERSISTENT_CONNECTION = True
def main():
""" main entry point for module execution
"""
element_spec = dict(
name=dict(),
description=dict(),
rd=dict(type='list'),
interfaces=dict(type='list'),
target=dict(type='list'),
state=dict(default='present', choices=['present', 'absent']),
active=dict(default=True, type='bool'),
table_label=dict(default=True, type='bool')
)
aggregate_spec = deepcopy(element_spec)
aggregate_spec['name'] = dict(required=True)
# remove default in aggregate spec, to handle common arguments
remove_default_spec(aggregate_spec)
argument_spec = dict(
aggregate=dict(type='list', elements='dict', options=aggregate_spec),
)
argument_spec.update(element_spec)
argument_spec.update(junos_argument_spec)
required_one_of = [['aggregate', 'name']]
mutually_exclusive = [['aggregate', 'name']]
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True,
required_one_of=required_one_of,
mutually_exclusive=mutually_exclusive)
warnings = list()
result = {'changed': False}
if warnings:
result['warnings'] = warnings
top = 'routing-instances/instance'
param_to_xpath_map = collections.OrderedDict()
param_to_xpath_map.update([
('name', {'xpath': 'name', 'is_key': True}),
('description', 'description'),
('type', 'instance-type'),
('rd', 'route-distinguisher/rd-type'),
('interfaces', 'interface/name'),
('target', 'vrf-target/community'),
('table_label', {'xpath': 'vrf-table-label', 'tag_only': True}),
])
params = to_param_list(module)
requests = list()
for param in params:
# if key doesn't exist in the item, get it from module.params
for key in param:
if param.get(key) is None:
param[key] = module.params[key]
item = param.copy()
item['type'] = 'vrf'
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):
for req in requests:
diff = load_config(module, tostring(req), warnings, action='merge')
commit = not module.check_mode
if diff:
if commit:
commit_configuration(module)
else:
discard_changes(module)
result['changed'] = True
if module._diff:
result['diff'] = {'prepared': diff}
module.exit_json(**result)
if __name__ == "__main__":
main()

@ -1,115 +0,0 @@
#
# (c) 2016 Red Hat Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import sys
import copy
from ansible.module_utils.network.common.utils import load_provider
from ansible.module_utils.network.junos.junos import junos_provider_spec
from ansible.plugins.action.network import ActionModule as ActionNetworkModule
from ansible.utils.display import Display
display = Display()
CLI_SUPPORTED_MODULES = ['junos_netconf', 'junos_ping', 'junos_command']
class ActionModule(ActionNetworkModule):
def run(self, tmp=None, task_vars=None):
del tmp # tmp no longer has any effect
module_name = self._task.action.split('.')[-1]
self._config_module = True if module_name == 'junos_config' else False
persistent_connection = self._play_context.connection.split('.')[-1]
warnings = []
if self._play_context.connection == 'local':
provider = load_provider(junos_provider_spec, self._task.args)
pc = copy.deepcopy(self._play_context)
pc.network_os = 'junipernetworks.junos.junos'
pc.remote_addr = provider['host'] or self._play_context.remote_addr
if provider['transport'] == 'cli' and module_name not in CLI_SUPPORTED_MODULES:
return {'failed': True, 'msg': "Transport type '%s' is not valid for '%s' module. "
"Please see https://docs.ansible.com/ansible/latest/network/user_guide/platform_junos.html"
% (provider['transport'], module_name)}
if module_name == 'junos_netconf' or (provider['transport'] == 'cli' and module_name == 'junos_command'):
pc.connection = 'ansible.netcommon.network_cli'
pc.port = int(provider['port'] or self._play_context.port or 22)
else:
pc.connection = 'ansible.netcommon.netconf'
pc.port = int(provider['port'] or self._play_context.port or 830)
pc.remote_user = provider['username'] or self._play_context.connection_user
pc.password = provider['password'] or self._play_context.password
pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file
connection = self._shared_loader_obj.connection_loader.get('ansible.netcommon.persistent', pc, sys.stdin,
task_uuid=self._task._uuid)
# TODO: Remove below code after ansible minimal is cut out
if connection is None:
pc.network_os = 'junos'
if pc.connection.split('.')[-1] == 'netconf':
pc.connection = 'netconf'
else:
pc.connection = 'network_cli'
connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid)
display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr)
command_timeout = int(provider['timeout']) if provider['timeout'] else connection.get_option('persistent_command_timeout')
connection.set_options(direct={'persistent_command_timeout': command_timeout})
socket_path = connection.run()
display.vvvv('socket_path: %s' % socket_path, pc.remote_addr)
if not socket_path:
return {'failed': True,
'msg': 'unable to open shell. Please see: ' +
'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'}
task_vars['ansible_socket'] = socket_path
warnings.append(['connection local support for this module is deprecated and will be removed in version 2.14, use connection %s' % pc.connection])
elif persistent_connection in ('netconf', 'network_cli'):
provider = self._task.args.get('provider', {})
if any(provider.values()):
# for legacy reasons provider value is required for junos_facts(optional) and junos_package
# modules as it uses junos_eznc library to connect to remote host
if not (module_name == 'junos_facts' or module_name == 'junos_package' or module_name == 'junos_scp'):
display.warning('provider is unnecessary when using %s and will be ignored' % self._play_context.connection)
del self._task.args['provider']
if (persistent_connection == 'network_cli' and module_name not in CLI_SUPPORTED_MODULES) or \
(persistent_connection == 'netconf' and module_name in CLI_SUPPORTED_MODULES[0:2]):
return {'failed': True, 'msg': "Connection type '%s' is not valid for '%s' module. "
"Please see https://docs.ansible.com/ansible/latest/network/user_guide/platform_junos.html"
% (self._play_context.connection, module_name)}
result = super(ActionModule, self).run(task_vars=task_vars)
if warnings:
if 'warnings' in result:
result['warnings'].extend(warnings)
else:
result['warnings'] = warnings
return result

@ -1,270 +0,0 @@
#
# (c) 2017 Red Hat Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = """
---
author: Ansible Networking Team
cliconf: junos
short_description: Use junos cliconf to run command on Juniper Junos OS platform
description:
- This junos plugin provides low level abstraction apis for
sending and receiving CLI commands from Juniper Junos OS network devices.
version_added: "2.4"
"""
import json
import re
from itertools import chain
from functools import wraps
from ansible.errors import AnsibleConnectionFailure
from ansible.module_utils._text import to_text
from ansible.module_utils.common._collections_compat import Mapping
from ansible.module_utils.network.common.utils import to_list
from ansible.plugins.cliconf import CliconfBase
def configure(func):
@wraps(func)
def wrapped(self, *args, **kwargs):
prompt = self._connection.get_prompt()
if not to_text(prompt, errors='surrogate_or_strict').strip().endswith('#'):
self.send_command('configure')
return func(self, *args, **kwargs)
return wrapped
class Cliconf(CliconfBase):
def get_text(self, ele, tag):
try:
return to_text(ele.find(tag).text, errors='surrogate_then_replace').strip()
except AttributeError:
pass
def get_device_info(self):
device_info = dict()
device_info['network_os'] = 'junos'
reply = self.get(command='show version')
data = to_text(reply, errors='surrogate_or_strict').strip()
match = re.search(r'Junos: (\S+)', data)
if match:
device_info['network_os_version'] = match.group(1)
match = re.search(r'Model: (\S+)', data, re.M)
if match:
device_info['network_os_model'] = match.group(1)
match = re.search(r'Hostname: (\S+)', data, re.M)
if match:
device_info['network_os_hostname'] = match.group(1)
return device_info
def get_config(self, source='running', format='text', flags=None):
if source != 'running':
raise ValueError("fetching configuration from %s is not supported" % source)
options_values = self.get_option_values()
if format not in options_values['format']:
raise ValueError("'format' value %s is invalid. Valid values are %s" % (format, ','.join(options_values['format'])))
if format == 'text':
cmd = 'show configuration'
else:
cmd = 'show configuration | display %s' % format
cmd += ' '.join(to_list(flags))
cmd = cmd.strip()
return self.send_command(cmd)
@configure
def edit_config(self, candidate=None, commit=True, replace=None, comment=None):
operations = self.get_device_operations()
self.check_edit_config_capability(operations, candidate, commit, replace, comment)
resp = {}
results = []
requests = []
if replace:
candidate = 'load override {0}'.format(replace)
for line in to_list(candidate):
if not isinstance(line, Mapping):
line = {'command': line}
cmd = line['command']
try:
results.append(self.send_command(**line))
except AnsibleConnectionFailure as exc:
if "error: commit failed" in exc.message:
self.discard_changes()
raise
requests.append(cmd)
diff = self.compare_configuration()
if diff:
resp['diff'] = diff
if commit:
self.commit(comment=comment)
else:
self.discard_changes()
else:
self.send_command('top')
self.discard_changes()
resp['request'] = requests
resp['response'] = results
return resp
def get(self, command, prompt=None, answer=None, sendonly=False, output=None, newline=True, check_all=False):
if output:
command = self._get_command_with_output(command, output)
return self.send_command(command=command, prompt=prompt, answer=answer, sendonly=sendonly, newline=newline, check_all=check_all)
@configure
def commit(self, comment=None, confirmed=False, at_time=None, synchronize=False):
"""
Execute commit command on remote device.
:param comment: Comment to be associated with commit
:param confirmed: Boolean flag to indicate if the previous commit should confirmed
:param at_time: Time at which to activate configuration changes
:param synchronize: Boolean flag to indicate if commit should synchronize on remote peers
:return: Command response received from device
"""
command = 'commit'
if comment:
command += ' comment {0}'.format(comment)
if confirmed:
command += ' confirmed'
if at_time:
command += ' {0}'.format(at_time)
if synchronize:
command += ' peers-synchronize'
command += ' and-quit'
try:
response = self.send_command(command)
except AnsibleConnectionFailure:
self.discard_changes()
raise
return response
@configure
def discard_changes(self):
command = 'rollback 0'
for cmd in chain(to_list(command), ['exit']):
self.send_command(cmd)
@configure
def validate(self):
return self.send_command('commit check')
@configure
def compare_configuration(self, rollback_id=None):
command = 'show | compare'
if rollback_id is not None:
command += ' rollback %s' % int(rollback_id)
resp = self.send_command(command)
r = resp.splitlines()
if len(r) == 1 and '[edit]' in r[0] or len(r) == 4 and r[1].startswith('- version'):
resp = ''
return resp
@configure
def rollback(self, rollback_id, commit=True):
resp = {}
self.send_command('rollback %s' % int(rollback_id))
resp['diff'] = self.compare_configuration()
if commit:
self.commit()
else:
self.discard_changes()
return resp
def get_diff(self, rollback_id=None):
diff = {'config_diff': None}
response = self.compare_configuration(rollback_id=rollback_id)
if response:
diff['config_diff'] = response
return diff
def get_device_operations(self):
return {
'supports_diff_replace': False,
'supports_commit': True,
'supports_rollback': True,
'supports_defaults': False,
'supports_onbox_diff': True,
'supports_commit_comment': True,
'supports_multiline_delimiter': False,
'supports_diff_match': False,
'supports_diff_ignore_lines': False,
'supports_generate_diff': False,
'supports_replace': True
}
def get_option_values(self):
return {
'format': ['text', 'set', 'xml', 'json'],
'diff_match': [],
'diff_replace': [],
'output': ['text', 'set', 'xml', 'json']
}
def get_capabilities(self):
result = super(Cliconf, self).get_capabilities()
result['rpc'] += ['commit', 'discard_changes', 'run_commands', 'compare_configuration', 'validate', 'get_diff']
result['device_operations'] = self.get_device_operations()
result.update(self.get_option_values())
return json.dumps(result)
def set_cli_prompt_context(self):
"""
Make sure we are in the operational cli mode
:return: None
"""
if self._connection.connected:
self._update_cli_prompt_context(config_context='#')
def _get_command_with_output(self, command, output):
options_values = self.get_option_values()
if output not in options_values['output']:
raise ValueError("'output' value %s is invalid. Valid values are %s" % (output, ','.join(options_values['output'])))
if output == 'json' and not command.endswith('| display json'):
cmd = '%s | display json' % command
elif output == 'xml' and not command.endswith('| display xml'):
cmd = '%s | display xml' % command
elif output == 'text' and (command.endswith('| display json') or command.endswith('| display xml')):
cmd = command.rsplit('|', 1)[0]
else:
cmd = command
return cmd

@ -1,69 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2015, Peter Sprygada <psprygada@ansible.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
class ModuleDocFragment(object):
# Standard files documentation fragment
DOCUMENTATION = r'''
options:
provider:
description:
- B(Deprecated)
- "Starting with Ansible 2.5 we recommend using C(connection: network_cli) or C(connection: netconf)."
- For more information please see the L(Junos OS Platform Options guide, ../network/user_guide/platform_junos.html).
- HORIZONTALLINE
- A dict object containing connection details.
type: dict
suboptions:
host:
description:
- Specifies the DNS host name or address for connecting to the remote
device over the specified transport. The value of host is used as
the destination address for the transport.
type: str
required: true
port:
description:
- Specifies the port to use when building the connection to the remote
device. The port value will default to the well known SSH port
of 22 (for C(transport=cli)) or port 830 (for C(transport=netconf))
device.
type: int
default: 22
username:
description:
- Configures the username to use to authenticate the connection to
the remote device. This value is used to authenticate
the SSH session. If the value is not specified in the task, the
value of environment variable C(ANSIBLE_NET_USERNAME) will be used instead.
type: str
password:
description:
- Specifies the password to use to authenticate the connection to
the remote device. This value is used to authenticate
the SSH session. If the value is not specified in the task, the
value of environment variable C(ANSIBLE_NET_PASSWORD) will be used instead.
type: str
timeout:
description:
- Specifies the timeout in seconds for communicating with the network device
for either connecting or sending commands. If the timeout is
exceeded before the operation is completed, the module will error.
type: int
default: 10
ssh_keyfile:
description:
- Specifies the SSH key to use to authenticate the connection to
the remote device. This value is the path to the key
used to authenticate the SSH session. If the value is not specified in
the task, the value of environment variable C(ANSIBLE_NET_SSH_KEYFILE)
will be used instead.
type: path
notes:
- For information on using CLI and netconf see the :ref:`Junos OS Platform Options guide <junos_platform_options>`
- For more information on using Ansible to manage network devices see the :ref:`Ansible Network Guide <network_guide>`
- For more information on using Ansible to manage Juniper network devices see U(https://www.ansible.com/ansible-juniper).
'''

@ -1,226 +0,0 @@
#
# (c) 2017 Red Hat Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = """
---
author: Ansible Networking Team
netconf: junos
short_description: Use junos netconf plugin to run netconf commands on Juniper JUNOS platform
description:
- This junos plugin provides low level abstraction apis for
sending and receiving netconf commands from Juniper JUNOS network devices.
version_added: "2.9"
options:
ncclient_device_handler:
type: str
default: junos
description:
- Specifies the ncclient device handler name for Juniper junos network os. To
identify the ncclient device handler name refer ncclient library documentation.
"""
import json
import re
from ansible.module_utils._text import to_text, to_native
from ansible.module_utils.six import string_types
from ansible.errors import AnsibleConnectionFailure
from ansible.plugins.netconf import NetconfBase, ensure_ncclient
try:
from ncclient import manager
from ncclient.operations import RPCError
from ncclient.transport.errors import SSHUnknownHostError
from ncclient.xml_ import to_ele, to_xml, new_ele, sub_ele
HAS_NCCLIENT = True
except (ImportError, AttributeError): # paramiko and gssapi are incompatible and raise AttributeError not ImportError
HAS_NCCLIENT = False
class Netconf(NetconfBase):
def get_text(self, ele, tag):
try:
return to_text(ele.find(tag).text, errors='surrogate_then_replace').strip()
except AttributeError:
pass
@ensure_ncclient
def get_device_info(self):
device_info = dict()
device_info['network_os'] = 'junos'
ele = new_ele('get-software-information')
data = self.execute_rpc(to_xml(ele))
reply = to_ele(data)
sw_info = reply.find('.//software-information')
device_info['network_os_version'] = self.get_text(sw_info, 'junos-version')
device_info['network_os_hostname'] = self.get_text(sw_info, 'host-name')
device_info['network_os_model'] = self.get_text(sw_info, 'product-model')
return device_info
def execute_rpc(self, name):
"""
RPC to be execute on remote device
:param name: Name of rpc in string format
:return: Received rpc response from remote host
"""
return self.rpc(name)
@ensure_ncclient
def load_configuration(self, format='xml', action='merge', target='candidate', config=None):
"""
Load given configuration on device
:param format: Format of configuration (xml, text, set)
:param action: Action to be performed (merge, replace, override, update)
:param target: The name of the configuration datastore being edited
:param config: The configuration to be loaded on remote host in string format
:return: Received rpc response from remote host in string format
"""
if config:
if format == 'xml':
config = to_ele(config)
try:
return self.m.load_configuration(format=format, action=action, target=target, config=config).data_xml
except RPCError as exc:
raise Exception(to_xml(exc.xml))
def get_capabilities(self):
result = dict()
result['rpc'] = self.get_base_rpc() + ['commit', 'discard_changes', 'validate', 'lock', 'unlock', 'copy_copy',
'execute_rpc', 'load_configuration', 'get_configuration', 'command',
'reboot', 'halt']
result['network_api'] = 'netconf'
result['device_info'] = self.get_device_info()
result['server_capabilities'] = [c for c in self.m.server_capabilities]
result['client_capabilities'] = [c for c in self.m.client_capabilities]
result['session_id'] = self.m.session_id
result['device_operations'] = self.get_device_operations(result['server_capabilities'])
return json.dumps(result)
@staticmethod
@ensure_ncclient
def guess_network_os(obj):
"""
Guess the remote network os name
:param obj: Netconf connection class object
:return: Network OS name
"""
try:
m = manager.connect(
host=obj._play_context.remote_addr,
port=obj._play_context.port or 830,
username=obj._play_context.remote_user,
password=obj._play_context.password,
key_filename=obj.key_filename,
hostkey_verify=obj.get_option('host_key_checking'),
look_for_keys=obj.get_option('look_for_keys'),
allow_agent=obj._play_context.allow_agent,
timeout=obj.get_option('persistent_connect_timeout'),
# We need to pass in the path to the ssh_config file when guessing
# the network_os so that a jumphost is correctly used if defined
ssh_config=obj._ssh_config
)
except SSHUnknownHostError as exc:
raise AnsibleConnectionFailure(to_native(exc))
guessed_os = None
for c in m.server_capabilities:
if re.search('junos', c):
guessed_os = 'junos'
m.close_session()
return guessed_os
def get_configuration(self, format='xml', filter=None):
"""
Retrieve all or part of a specified configuration.
:param format: format in which configuration should be retrieved
:param filter: specifies the portion of the configuration to retrieve
as either xml string rooted in <configuration> element
:return: Received rpc response from remote host in string format
"""
if filter is not None:
if not isinstance(filter, string_types):
raise AnsibleConnectionFailure("get configuration filter should be of type string,"
" received value '%s' is of type '%s'" % (filter, type(filter)))
filter = to_ele(filter)
return self.m.get_configuration(format=format, filter=filter).data_xml
def compare_configuration(self, rollback=0):
"""
Compare the candidate configuration with running configuration
by default. The candidate configuration can be compared with older
committed configuration by providing rollback id.
:param rollback: Rollback id of previously commited configuration
:return: Received rpc response from remote host in string format
"""
return self.m.compare_configuration(rollback=rollback).data_xml
def halt(self):
"""reboot the device"""
return self.m.halt().data_xml
def reboot(self):
"""reboot the device"""
return self.m.reboot().data_xml
# Due to issue in ncclient commit() method for Juniper (https://github.com/ncclient/ncclient/issues/238)
# below commit() is a workaround which build's raw `commit-configuration` xml with required tags and uses
# ncclient generic rpc() method to execute rpc on remote host.
# Remove below method after the issue in ncclient is fixed.
@ensure_ncclient
def commit(self, confirmed=False, check=False, timeout=None, comment=None, synchronize=False, at_time=None):
"""
Commit the candidate configuration as the device's new current configuration.
Depends on the `:candidate` capability.
A confirmed commit (i.e. if *confirmed* is `True`) is reverted if there is no
followup commit within the *timeout* interval. If no timeout is specified the
confirm timeout defaults to 600 seconds (10 minutes).
A confirming commit may have the *confirmed* parameter but this is not required.
Depends on the `:confirmed-commit` capability.
:param confirmed: whether this is a confirmed commit
:param check: Check correctness of syntax
:param timeout: specifies the confirm timeout in seconds
:param comment: Message to write to commit log
:param synchronize: Synchronize commit on remote peers
:param at_time: Time at which to activate configuration changes
:return: Received rpc response from remote host
"""
obj = new_ele('commit-configuration')
if confirmed:
sub_ele(obj, 'confirmed')
if check:
sub_ele(obj, 'check')
if synchronize:
sub_ele(obj, 'synchronize')
if at_time:
subele = sub_ele(obj, 'at-time')
subele.text = str(at_time)
if comment:
subele = sub_ele(obj, 'log')
subele.text = str(comment)
if timeout:
subele = sub_ele(obj, 'confirm-timeout')
subele.text = str(timeout)
return self.rpc(obj)

@ -1,53 +0,0 @@
#
# (c) 2016 Red Hat Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import re
from ansible.plugins.terminal import TerminalBase
from ansible.errors import AnsibleConnectionFailure
from ansible.utils.display import Display
display = Display()
class TerminalModule(TerminalBase):
terminal_stdout_re = [
re.compile(br"({primary:node\d+})?[\r\n]?[\w@+\-\.:\/\[\]]+[>#%] ?$"),
]
terminal_stderr_re = [
re.compile(br"unknown command"),
re.compile(br"syntax error"),
re.compile(br"[\r\n]error:")
]
def on_open_shell(self):
try:
prompt = self._get_prompt()
if prompt.strip().endswith(b'%'):
display.vvv('starting cli', self._connection._play_context.remote_addr)
self._exec_cli_command(b'cli')
for c in (b'set cli timestamp disable', b'set cli screen-length 0', b'set cli screen-width 1024'):
self._exec_cli_command(c)
except AnsibleConnectionFailure:
raise AnsibleConnectionFailure('unable to set terminal parameters')

@ -1,3 +0,0 @@
---
testcase: "*"
test_items: []

@ -1,2 +0,0 @@
dependencies:
- prepare_junos_tests

@ -1,2 +0,0 @@
---
- { include: netconf.yaml, tags: ['netconf'] }

@ -1,21 +0,0 @@
- name: collect netconf test cases
find:
paths: "{{ role_path }}/tests/netconf"
patterns: "{{ testcase }}.yaml"
connection: local
register: test_cases
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=netconf)
include: "{{ test_case_to_run }} ansible_connection=netconf"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run
- name: run test case (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

@ -1,208 +0,0 @@
---
- debug: msg="START junos_banner netconf/basic.yaml on connection={{ ansible_connection }}"
- name: setup - remove login banner
junos_banner:
banner: login
state: absent
provider: "{{ netconf }}"
- name: Create login banner
junos_banner:
banner: login
text: this is my login banner
state: present
provider: "{{ netconf }}"
register: result
- name: Get running configuration
junos_rpc:
rpc: get-configuration
provider: "{{ netconf }}"
register: config
- assert:
that:
- "result.changed == true"
- "'<message>this is my login banner</message>' in config.xml"
- name: Create login banner (idempotent)
junos_banner:
banner: login
text: this is my login banner
state: present
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- name: Deactivate login banner
junos_banner:
banner: login
text: this is my login banner
state: present
active: False
provider: "{{ netconf }}"
register: result
- name: Get running configuration
junos_rpc:
rpc: get-configuration
provider: "{{ netconf }}"
register: config
- assert:
that:
- "result.changed == true"
- "'<message inactive=\"inactive\">this is my login banner</message>' in config.xml"
- name: Activate login banner
junos_banner:
banner: login
text: this is my login banner
state: present
active: True
provider: "{{ netconf }}"
register: result
- name: Get running configuration
junos_rpc:
rpc: get-configuration
provider: "{{ netconf }}"
register: config
- assert:
that:
- "result.changed == true"
- "'<message>this is my login banner</message>' in config.xml"
- name: check mode
junos_banner:
banner: login
text: this is not the login banner you're looking for
state: present
provider: "{{ netconf }}"
register: result
check_mode: yes
- assert:
that:
- "result.changed == true"
- "result.failed == false"
- name: delete login banner
junos_banner:
banner: login
state: absent
provider: "{{ netconf }}"
register: result
- name: Get running configuration
junos_rpc:
rpc: get-configuration
provider: "{{ netconf }}"
register: config
- assert:
that:
- "result.changed == true"
- "'<message>this is my login banner</message>' not in config.xml"
- name: setup - remove motd banner
junos_banner:
banner: motd
state: absent
provider: "{{ netconf }}"
- name: Create motd banner
junos_banner:
banner: motd
text: this is my motd banner
state: present
provider: "{{ netconf }}"
register: result
- name: Get running configuration
junos_rpc:
rpc: get-configuration
provider: "{{ netconf }}"
register: config
- assert:
that:
- "result.changed == true"
- "'<announcement>this is my motd banner</announcement>' in config.xml"
- name: Create motd banner (idempotent)
junos_banner:
banner: motd
text: this is my motd banner
state: present
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- name: Deactivate motd banner
junos_banner:
banner: motd
text: this is my motd banner
state: present
active: False
provider: "{{ netconf }}"
register: result
- name: Get running configuration
junos_rpc:
rpc: get-configuration
provider: "{{ netconf }}"
register: config
- assert:
that:
- "result.changed == true"
- "'<announcement inactive=\"inactive\">this is my motd banner</announcement>' in config.xml"
- name: Activate motd banner
junos_banner:
banner: motd
text: this is my motd banner
state: present
active: True
provider: "{{ netconf }}"
register: result
- name: Get running configuration
junos_rpc:
rpc: get-configuration
provider: "{{ netconf }}"
register: config
- assert:
that:
- "result.changed == true"
- "'<announcement>this is my motd banner</announcement>' in config.xml"
- name: delete motd banner
junos_banner:
banner: motd
state: absent
provider: "{{ netconf }}"
register: result
- name: Get running configuration
junos_rpc:
rpc: get-configuration
provider: "{{ netconf }}"
register: config
- assert:
that:
- "result.changed == true"
- "'<announcement>this is my motd banner</announcement>' not in config.xml"
- debug: msg="END junos_banner netconf/basic.yaml on connection={{ ansible_connection }}"

@ -1,35 +0,0 @@
---
- debug: msg="START junos net_banner netconf/net_banner.yaml on connection={{ ansible_connection }}"
- name: setup - remove login banner
net_banner:
banner: login
state: absent
provider: "{{ netconf }}"
- name: Create login banner
net_banner:
banner: login
text: this is my login banner configured by net_banner
state: present
provider: "{{ netconf }}"
register: result
- name: Get running configuration
junos_rpc:
rpc: get-configuration
provider: "{{ netconf }}"
register: config
- assert:
that:
- "result.changed == true"
- "'<message>this is my login banner configured by net_banner</message>' in config.xml"
- name: teardown - remove login banner
net_banner:
banner: login
state: absent
provider: "{{ netconf }}"
- debug: msg="END junos net_banner netconf/net_banner.yaml on connection={{ ansible_connection }}"

@ -1,3 +0,0 @@
---
testcase: "*"
test_items: []

@ -1,2 +0,0 @@
dependencies:
- prepare_junos_tests

@ -1,16 +0,0 @@
---
- name: collect all cli test cases
find:
paths: "{{ role_path }}/tests/cli"
patterns: "{{ testcase }}.yaml"
register: test_cases
delegate_to: localhost
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=network_cli)
include: "{{ test_case_to_run }} ansible_connection=network_cli"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

@ -1,5 +0,0 @@
---
- { include: netconf_xml.yaml, tags: ['netconf', 'xml'] }
- { include: netconf_text.yaml, tags: ['netconf', 'text'] }
- { include: netconf_json.yaml, tags: ['netconf', 'json'] }
- { include: cli.yaml, tags: ['cli'] }

@ -1,22 +0,0 @@
---
- name: collect netconf_json test cases with json encoding
find:
paths: "{{ role_path }}/tests/netconf_json"
patterns: "{{ testcase }}.yaml"
connection: local
register: test_cases
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=netconf)
include: "{{ test_case_to_run }} ansible_connection=netconf"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run
- name: run test case (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

@ -1,22 +0,0 @@
---
- name: collect netconf_text test cases with text encoding
find:
paths: "{{ role_path }}/tests/netconf_text"
patterns: "{{ testcase }}.yaml"
connection: local
register: test_cases
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=netconf)
include: "{{ test_case_to_run }} ansible_connection=netconf"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run
- name: run test case (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

@ -1,22 +0,0 @@
---
- name: collect netconf_xml test cases with xml encoding
find:
paths: "{{ role_path }}/tests/netconf_xml"
patterns: "{{ testcase }}.yaml"
connection: local
register: test_cases
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=netconf)
include: "{{ test_case_to_run }} ansible_connection=netconf"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run
- name: run test case (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

@ -1,64 +0,0 @@
---
- debug:
msg: "START cli/cli_command.yaml on connection={{ ansible_connection }}"
- block:
- name: get output for single command
cli_command:
command: show version
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- name: test with prompt and answer
cli_command:
command: "{{ item }}"
prompt:
- "Exit with uncommitted changes"
answer: yes
loop:
- configure
- set system syslog file test any any
- rollback
- exit
register: result
- assert:
that:
- "result.changed == false"
- cli_command:
command: "{{item}}"
prompt:
- "New password"
- "Retype new password"
answer:
- "Test1234"
- "Test1234"
check_all: True
loop:
- "configure"
- "rollback"
- "set system login user ansible_test class operator authentication plain-text-password"
- "commit"
register: result
ignore_errors: True
- assert:
that:
- "'failed' not in result"
- junos_netconf:
register: result
ignore_errors: True
- assert:
that:
- "result.failed == false"
when: ansible_connection == 'network_cli'
- debug: msg="END cli/cli_command.yaml on connection={{ ansible_connection }}"

@ -1,21 +0,0 @@
---
- debug: msg="START netconf_json/bad_operator.yaml on connection={{ ansible_connection }}"
- name: test bad operator with json encoding
junos_command:
commands:
- show version
- show interfaces lo0
wait_for:
- "result[0]['software-information'][0]['host-name'][0]['data'] foo lo0"
format: json
provider: "{{ netconf }}"
register: result
ignore_errors: yes
- assert:
that:
- "result.failed == true"
- "result.msg is defined"
- debug: msg="END netconf_json/bad_operator.yaml on connection={{ ansible_connection }}"

@ -1,21 +0,0 @@
---
- debug: msg="START netconf_json/contains.yaml on connection={{ ansible_connection }}"
- name: test contains operator with json encoding
junos_command:
commands:
- show version
- show interfaces lo0
format: json
wait_for:
- "result[1]['interface-information'][0]['physical-interface'][0]['name'][0]['data'] contains lo0"
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- debug: msg="END netconf_json/contains.yaml on connection={{ ansible_connection }}"

@ -1,38 +0,0 @@
---
- debug: msg="START netconf_json/equal.yaml on connection={{ ansible_connection }}"
- name: test == operator with xml encoding
junos_command:
commands:
- show version
- show interfaces lo0
wait_for:
- "result[1]['interface-information'][0]['physical-interface'][0]['name'][0]['data'] == lo0"
format: json
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- name: test eq operator with json encoding
junos_command:
commands:
- show version
- show interfaces lo0
wait_for:
- "result[1]['interface-information'][0]['physical-interface'][0]['name'][0]['data'] eq lo0"
format: json
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- debug: msg="END netconf_json/equal.yaml on connection={{ ansible_connection }}"

@ -1,38 +0,0 @@
---
- debug: msg="START netconf_json/greaterthan.yaml on connection={{ ansible_connection }}"
- name: test gt operator
junos_command:
commands:
- show version
- show interfaces lo0
format: json
wait_for:
- "result[1]['interface-information'][0]['physical-interface'][0]['local-index'][0]['data'] gt 5"
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- name: test > operator
junos_command:
commands:
- show version
- show interfaces lo0
format: json
wait_for:
- "result[1]['interface-information'][0]['physical-interface'][0]['local-index'][0]['data'] > 5"
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- debug: msg="END netconf_json/greaterthan.yaml on connection={{ ansible_connection }}"

@ -1,38 +0,0 @@
---
- debug: msg="START netconf_json/greaterthanorequal.yaml on connection={{ ansible_connection }}"
- name: test ge operator
junos_command:
commands:
- show version
- show interfaces lo0
format: json
wait_for:
- "result[1]['interface-information'][0]['physical-interface'][0]['local-index'][0]['data'] ge 6"
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- name: test >= operator
junos_command:
commands:
- show version
- show interfaces lo0
format: json
wait_for:
- "result[1]['interface-information'][0]['physical-interface'][0]['local-index'][0]['data'] >= 6"
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- debug: msg="END netconf_json/greaterthanorequal.yaml on connection={{ ansible_connection }}"

@ -1,38 +0,0 @@
---
- debug: msg="START netconf_json/lessthan.yaml on connection={{ ansible_connection }}"
- name: test lt operator
junos_command:
commands:
- show version
- show interfaces lo0
format: json
wait_for:
- "result[1]['interface-information'][0]['physical-interface'][0]['local-index'][0]['data'] lt 7"
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- name: test < operator
junos_command:
commands:
- show version
- show interfaces lo0
format: json
wait_for:
- "result[1]['interface-information'][0]['physical-interface'][0]['local-index'][0]['data'] lt 7"
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- debug: msg="END netconf_json/lessthan.yaml on connection={{ ansible_connection }}"

@ -1,38 +0,0 @@
---
- debug: msg="START netconf_json/lessthanorequal.yaml on connection={{ ansible_connection }}"
- name: test le operator
junos_command:
commands:
- show version
- show interfaces lo0
format: json
wait_for:
- "result[1]['interface-information'][0]['physical-interface'][0]['local-index'][0][data] le 6"
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- name: test <= operator
junos_command:
commands:
- show version
- show interfaces lo0
format: json
wait_for:
- "result[1]['interface-information'][0]['physical-interface'][0]['local-index'][0][data] <= 6"
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- debug: msg="END netconf_json/lessthanorequal.yaml on connection={{ ansible_connection }}"

@ -1,38 +0,0 @@
---
- debug: msg="START netconf_json/notequal.yaml on connection={{ ansible_connection }}"
- name: test neq operator
junos_command:
commands:
- show version
- show interfaces lo0
format: json
wait_for:
- "result[1]['interface-information'][0]['physical-interface'][0]['name'][0]['data'] neq em0"
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- name: test != operator
junos_command:
commands:
- show version
- show interfaces lo0
format: json
wait_for:
- "result[1]['interface-information'][0]['physical-interface'][0]['name'][0]['data'] neq em0"
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- debug: msg="END netconf_json/notequal.yaml on connection={{ ansible_connection }}"

@ -1,63 +0,0 @@
---
- debug: msg="START netconf_json/output.yaml on connection={{ ansible_connection }}"
- name: get output for single command
junos_command:
commands: ['show version']
format: json
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- name: get output for multiple commands
junos_command:
commands:
- show version
- show route
format: json
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- name: get output for single command with cli transport
junos_command:
commands: ['show version | display json']
provider:
transport: cli
register: result
connection: network_cli
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- name: get output for multiple commands with cli transport
junos_command:
commands:
- show version
- show route
format: json
provider:
transport: cli
register: result
connection: network_cli
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- debug: msg="END netconf_json/output.yaml on connection={{ ansible_connection }}"

@ -1,21 +0,0 @@
---
- debug: msg="START netconf_text/bad_operator.yaml on connection={{ ansible_connection }}"
- name: test bad operator with text encoding
junos_command:
commands:
- show version
- show interfaces lo0
wait_for:
- "result[1].interface-information[0].physical-interface[0].name[0].data foo lo0"
encoding: text
provider: "{{ netconf }}"
register: result
ignore_errors: yes
- assert:
that:
- "result.failed == true"
- "result.msg is defined"
- debug: msg="END netconf_text/bad_operator.yaml on connection={{ ansible_connection }}"

@ -1,21 +0,0 @@
---
- debug: msg="START netconf_text/contains.yaml on connection={{ ansible_connection }}"
- name: test contains operator with text encoding
junos_command:
commands:
- show version
- show interfaces lo0
display: text
wait_for:
- "result[1] contains lo0"
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- debug: msg="END netconf_text/contains.yaml on connection={{ ansible_connection }}"

@ -1,34 +0,0 @@
---
- debug: msg="START netconf_text/invalid.yaml on connection={{ ansible_connection }}"
- name: run invalid command
junos_command:
commands: show foo
display: text
provider: "{{ netconf }}"
register: result
ignore_errors: yes
- debug: var=result
- assert:
that:
- "result.failed == true"
- "result.msg is defined"
- name: run commands that include invalid command
junos_command:
commands:
- show version
- show foo
display: text
provider: "{{ netconf }}"
register: result
ignore_errors: yes
- assert:
that:
- "result.failed == true"
- "result.msg is defined"
- debug: msg="END netconf_text/invalid.yaml on connection={{ ansible_connection }}"

@ -1,62 +0,0 @@
---
- debug: msg="START netconf_text/output.yaml on connection={{ ansible_connection }}"
- name: get output for single command
junos_command:
commands: show version
display: text
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- name: get output for multiple commands
junos_command:
commands:
- show version
- show route
display: text
provider: "{{ netconf }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- name: get output for single command with cli transport
junos_command:
commands: show version
display: text
provider:
transport: cli
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- name: get output for multiple commands with cli transport
junos_command:
commands:
- show version
- show route
display: text
provider:
transport: cli
register: result
- assert:
that:
- "result.changed == false"
- "result.stdout is defined"
- "result.stdout_lines is defined"
- debug: msg="END netconf_text/output.yaml on connection={{ ansible_connection }}"

@ -1,20 +0,0 @@
---
- debug: msg="START netconf_text/timeout.yaml on connection={{ ansible_connection }}"
- name: test bad condition
junos_command:
commands:
- show version
wait_for:
- "result[0] contains bad_value_string"
display: text
provider: "{{ netconf }}"
register: result
ignore_errors: yes
- assert:
that:
- "result.failed == true"
- "result.msg is defined"
- debug: msg="END netconf_text/timeout.yaml on connection={{ ansible_connection }}"

@ -1,21 +0,0 @@
---
- debug: msg="START netconf_xml/bad_operator.yaml on connection={{ ansible_connection }}"
- name: test bad operator with xml encoding
junos_command:
commands:
- show version
- show interfaces lo0
wait_for:
- "result[1].rpc-reply.interface-information[0].physical-interface[0].name[0].data foo lo0"
format: xml
provider: "{{ netconf }}"
register: result
ignore_errors: yes
- assert:
that:
- "result.failed == true"
- "result.msg is defined"
- debug: msg="END netconf_xml/bad_operator.yaml on connection={{ ansible_connection }}"

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save