summaryrefslogtreecommitdiffstats
path: root/ansible_collections/junipernetworks/junos/plugins
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:04:41 +0000
commit975f66f2eebe9dadba04f275774d4ab83f74cf25 (patch)
tree89bd26a93aaae6a25749145b7e4bca4a1e75b2be /ansible_collections/junipernetworks/junos/plugins
parentInitial commit. (diff)
downloadansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.tar.xz
ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.zip
Adding upstream version 7.7.0+dfsg.upstream/7.7.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/junipernetworks/junos/plugins')
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/action/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/action/junos.py58
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/cliconf/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/cliconf/junos.py346
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/doc_fragments/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/doc_fragments/junos.py21
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acl_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acl_interfaces/acl_interfaces.py80
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acls/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acls/acls.py211
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_address_family/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_address_family/bgp_address_family.py894
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_global/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_global/bgp_global.py1271
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/facts/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/facts/facts.py29
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/hostname/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/hostname/hostname.py56
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/interfaces/interfaces.py86
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l2_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l2_interfaces/l2_interfaces.py75
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l3_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l3_interfaces/l3_interfaces.py54
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp/lacp.py64
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp_interfaces/lacp_interfaces.py79
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lag_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lag_interfaces/lag_interfaces.py72
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_global/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_global/lldp_global.py64
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_interfaces/lldp_interfaces.py63
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/logging_global/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/logging_global/logging_global.py1380
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ntp_global/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ntp_global/ntp_global.py133
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospf_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospf_interfaces/ospf_interfaces.py141
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv2/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv2/ospfv2.py125
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv3/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv3/ospfv3.py125
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/prefix_lists/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/prefix_lists/prefix_lists.py63
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_instances/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_instances/routing_instances.py108
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_options/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_options/routing_options.py69
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies/security_policies.py822
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies_global/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies_global/security_policies_global.py129
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_zones/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_zones/security_zones.py192
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/snmp_server/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/snmp_server/snmp_server.py700
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/static_routes/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/static_routes/static_routes.py90
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/vlans/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/vlans/vlans.py65
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acl_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acl_interfaces/acl_interfaces.py260
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acls/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acls/acls.py441
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_address_family/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_address_family/bgp_address_family.py917
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_global/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_global/bgp_global.py792
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/hostname/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/hostname/hostname.py199
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/interfaces/interfaces.py358
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l2_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l2_interfaces/l2_interfaces.py340
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l3_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l3_interfaces/l3_interfaces.py288
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp/lacp.py255
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp_interfaces/lacp_interfaces.py345
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lag_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lag_interfaces/lag_interfaces.py365
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_global/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_global/lldp_global.py269
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_interfaces/lldp_interfaces.py264
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/logging_global/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/logging_global/logging_global.py528
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ntp_global/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ntp_global/ntp_global.py388
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospf_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospf_interfaces/ospf_interfaces.py362
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv2/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv2/ospfv2.py439
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv3/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv3/ospfv3.py454
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/prefix_lists/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/prefix_lists/prefix_lists.py280
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_instances/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_instances/routing_instances.py365
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_options/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_options/routing_options.py250
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies/security_policies.py796
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies_global/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies_global/security_policies_global.py394
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_zones/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_zones/security_zones.py515
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/snmp_server/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/snmp_server/snmp_server.py897
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/static_routes/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/static_routes/static_routes.py324
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/vlans/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/vlans/vlans.py254
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acl_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acl_interfaces/acl_interfaces.py160
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acls/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acls/acls.py246
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_address_family/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_address_family/bgp_address_family.py741
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_global/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_global/bgp_global.py1090
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/facts.py203
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/hostname/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/hostname/hostname.py137
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/interfaces/interfaces.py179
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l2_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l2_interfaces/l2_interfaces.py162
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l3_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l3_interfaces/l3_interfaces.py180
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp/lacp.py119
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp_interfaces/lacp_interfaces.py146
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lag_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lag_interfaces/lag_interfaces.py160
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/legacy/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/legacy/base.py232
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_global/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_global/lldp_global.py115
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_interfaces/lldp_interfaces.py115
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/logging_global/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/logging_global/logging_global.py428
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ntp_global/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ntp_global/ntp_global.py320
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospf_interfaces/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospf_interfaces/ospf_interfaces.py267
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv2/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv2/ospfv2.py286
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv3/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv3/ospfv3.py285
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/prefix_lists/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/prefix_lists/prefix_lists.py168
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_instances/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_instances/routing_instances.py248
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_options/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_options/routing_options.py150
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies/security_policies.py529
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies_global/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies_global/security_policies_global.py245
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_zones/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_zones/security_zones.py337
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/snmp_server/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/snmp_server/snmp_server.py851
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/static_routes/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/static_routes/static_routes.py180
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/vlans/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/vlans/vlans.py124
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/junos.py509
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/utils/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/utils/utils.py52
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_acl_interfaces.py366
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_acls.py364
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_banner.py194
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_bgp_address_family.py1651
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_bgp_global.py1763
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_command.py481
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_config.py531
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_facts.py146
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_hostname.py362
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_interfaces.py587
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_l2_interfaces.py697
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_l3_interfaces.py777
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_lacp.py305
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_lacp_interfaces.py967
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_lag_interfaces.py887
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_lldp_global.py331
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_lldp_interfaces.py359
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_logging.py403
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_logging_global.py1743
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_netconf.py193
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_ntp_global.py1019
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_ospf_interfaces.py611
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_ospfv2.py347
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_ospfv3.py693
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_package.py218
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_ping.py290
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_prefix_lists.py682
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_routing_instances.py766
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_routing_options.py402
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_rpc.py177
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_scp.py172
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_security_policies.py2707
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_security_policies_global.py994
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_security_zones.py2001
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_snmp_server.py1584
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_static_routes.py308
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_system.py207
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_user.py458
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_vlans.py467
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/modules/junos_vrf.py342
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/netconf/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/netconf/junos.py283
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/terminal/__init__.py0
-rw-r--r--ansible_collections/junipernetworks/junos/plugins/terminal/junos.py68
227 files changed, 55871 insertions, 0 deletions
diff --git a/ansible_collections/junipernetworks/junos/plugins/action/__init__.py b/ansible_collections/junipernetworks/junos/plugins/action/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/action/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/action/junos.py b/ansible_collections/junipernetworks/junos/plugins/action/junos.py
new file mode 100644
index 000000000..7c0389a8b
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/action/junos.py
@@ -0,0 +1,58 @@
+#
+# (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
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+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 in ["junos_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection not in ("netconf", "network_cli"):
+ 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
diff --git a/ansible_collections/junipernetworks/junos/plugins/cliconf/__init__.py b/ansible_collections/junipernetworks/junos/plugins/cliconf/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/cliconf/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/cliconf/junos.py b/ansible_collections/junipernetworks/junos/plugins/cliconf/junos.py
new file mode 100644
index 000000000..72ffec99e
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/cliconf/junos.py
@@ -0,0 +1,346 @@
+#
+# (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 (@ansible-network)
+name: 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: 1.0.0
+options:
+ config_commands:
+ description:
+ - Specifies a list of commands that can make configuration changes
+ to the target device.
+ - When `ansible_network_single_user_mode` is enabled, if a command sent
+ to the device is present in this list, the existing cache is invalidated.
+ version_added: 2.0.0
+ type: list
+ elements: str
+ default: []
+ vars:
+ - name: ansible_junos_config_commands
+"""
+
+import json
+import re
+
+from functools import wraps
+from itertools import chain
+
+from ansible.errors import AnsibleConnectionFailure
+from ansible.module_utils._text import to_text
+from ansible.module_utils.common._collections_compat import Mapping
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+from ansible_collections.ansible.netcommon.plugins.plugin_utils.cliconf_base 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 __init__(self, *args, **kwargs):
+ self._device_info = {}
+ super(Cliconf, self).__init__(*args, **kwargs)
+
+ 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):
+ if not self._device_info:
+ device_info = {}
+ 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)
+
+ self._device_info = device_info
+
+ return self._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
diff --git a/ansible_collections/junipernetworks/junos/plugins/doc_fragments/__init__.py b/ansible_collections/junipernetworks/junos/plugins/doc_fragments/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/doc_fragments/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/doc_fragments/junos.py b/ansible_collections/junipernetworks/junos/plugins/doc_fragments/junos.py
new file mode 100644
index 000000000..23bf60bb2
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/doc_fragments/junos.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+# 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: {}
+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).
+"""
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acl_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acl_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acl_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acl_interfaces/acl_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acl_interfaces/acl_interfaces.py
new file mode 100644
index 000000000..ae2303c00
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acl_interfaces/acl_interfaces.py
@@ -0,0 +1,80 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 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_acl_interfaces module
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Acl_interfacesArgs(object): # pylint: disable=R0903
+ """The arg spec for the junos_acl_interfaces module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "elements": "dict",
+ "options": {
+ "access_groups": {
+ "elements": "dict",
+ "options": {
+ "acls": {
+ "elements": "dict",
+ "options": {
+ "direction": {
+ "choices": ["in", "out"],
+ "type": "str",
+ },
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "afi": {"choices": ["ipv4", "ipv6"], "type": "str"},
+ },
+ "type": "list",
+ },
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acls/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acls/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acls/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acls/acls.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acls/acls.py
new file mode 100644
index 000000000..bf8633268
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/acls/acls.py
@@ -0,0 +1,211 @@
+#
+# _*_ coding: utf_8 _*_
+# Copyright 2020 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_acls module
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class AclsArgs(object): # pylint: disable=R0903
+ """The arg spec for the junos_acls module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "elements": "dict",
+ "type": "list",
+ "options": {
+ "afi": {
+ "required": True,
+ "choices": ["ipv4", "ipv6"],
+ "type": "str",
+ },
+ "acls": {
+ "elements": "dict",
+ "type": "list",
+ "options": {
+ "name": {"required": True, "type": "str"},
+ "aces": {
+ "elements": "dict",
+ "type": "list",
+ "options": {
+ "name": {"required": True, "type": "str"},
+ "source": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "raw"},
+ "prefix_list": {
+ "elements": "dict",
+ "type": "list",
+ "options": {
+ "name": {"type": "str"},
+ },
+ },
+ "port_protocol": {
+ "type": "dict",
+ "options": {
+ "eq": {"type": "str"},
+ "range": {
+ "type": "dict",
+ "options": {
+ "start": {
+ "type": "int",
+ },
+ "end": {"type": "int"},
+ },
+ },
+ },
+ },
+ },
+ },
+ "destination": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "raw"},
+ "prefix_list": {
+ "elements": "dict",
+ "type": "list",
+ "options": {
+ "name": {"type": "str"},
+ },
+ },
+ "port_protocol": {
+ "type": "dict",
+ "options": {
+ "eq": {"type": "str"},
+ "range": {
+ "type": "dict",
+ "options": {
+ "start": {
+ "type": "int",
+ },
+ "end": {"type": "int"},
+ },
+ },
+ },
+ },
+ },
+ },
+ "protocol": {"type": "str"},
+ "protocol_options": {
+ "type": "dict",
+ "options": {
+ "icmp": {
+ "type": "dict",
+ "options": {
+ "dod_host_prohibited": {
+ "type": "bool",
+ },
+ "dod_net_prohibited": {
+ "type": "bool",
+ },
+ "echo": {"type": "bool"},
+ "echo_reply": {"type": "bool"},
+ "host_tos_unreachable": {
+ "type": "bool",
+ },
+ "host_redirect": {
+ "type": "bool",
+ },
+ "host_tos_redirect": {
+ "type": "bool",
+ },
+ "host_unknown": {
+ "type": "bool",
+ },
+ "host_unreachable": {
+ "type": "bool",
+ },
+ "net_redirect": {
+ "type": "bool",
+ },
+ "net_tos_redirect": {
+ "type": "bool",
+ },
+ "network_unknown": {
+ "type": "bool",
+ },
+ "port_unreachable": {
+ "type": "bool",
+ },
+ "protocol_unreachable": {
+ "type": "bool",
+ },
+ "reassembly_timeout": {
+ "type": "bool",
+ },
+ "redirect": {"type": "bool"},
+ "router_advertisement": {
+ "type": "bool",
+ },
+ "router_solicitation": {
+ "type": "bool",
+ },
+ "source_route_failed": {
+ "type": "bool",
+ },
+ "time_exceeded": {
+ "type": "bool",
+ },
+ "ttl_exceeded": {
+ "type": "bool",
+ },
+ },
+ },
+ },
+ },
+ "grant": {
+ "type": "str",
+ "choices": ["permit", "deny"],
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "parsed",
+ "gathered",
+ "rendered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
+
+
+# pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_address_family/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_address_family/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_address_family/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_address_family/bgp_address_family.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_address_family/bgp_address_family.py
new file mode 100644
index 000000000..950c68629
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_address_family/bgp_address_family.py
@@ -0,0 +1,894 @@
+#
+# -*- 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_bgp_address_family module
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Bgp_address_familyArgs(object): # pylint: disable=R0903
+ """The arg spec for the junos_bgp_address_family module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "options": {
+ "address_family": {
+ "elements": "dict",
+ "options": {
+ "af_type": {
+ "elements": "dict",
+ "options": {
+ "accepted_prefix_limit": {
+ "options": {
+ "forever": {"type": "bool"},
+ "idle_timeout": {"type": "bool"},
+ "idle_timeout_value": {"type": "int"},
+ "limit_threshold": {"type": "int"},
+ "maximum": {"type": "int"},
+ "teardown": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "add_path": {
+ "options": {
+ "receive": {"type": "bool"},
+ "send": {
+ "options": {
+ "include_backup_path": {
+ "type": "int",
+ },
+ "multipath": {"type": "bool"},
+ "path_count": {
+ "required": True,
+ "type": "int",
+ },
+ "path_selection_mode": {
+ "options": {
+ "all_paths": {
+ "type": "bool",
+ },
+ "equal_cost_paths": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "prefix_policy": {
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "aggregate_label": {
+ "options": {
+ "community": {"type": "str"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "aigp": {
+ "options": {
+ "disable": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "damping": {"type": "bool"},
+ "defer_initial_multipath_build": {
+ "options": {
+ "maximum_delay": {"type": "int"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "delay_route_advertisements": {
+ "options": {
+ "max_delay_route_age": {"type": "int"},
+ "max_delay_routing_uptime": {
+ "type": "int",
+ },
+ "min_delay_inbound_convergence": {
+ "type": "int",
+ },
+ "min_delay_routing_uptime": {
+ "type": "int",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "entropy_label": {
+ "options": {
+ "import": {"type": "str"},
+ "no_next_hop_validation": {
+ "type": "bool",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "explicit_null": {
+ "options": {
+ "connected_only": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "extended_nexthop": {"type": "bool"},
+ "extended_nexthop_color": {"type": "bool"},
+ "graceful_restart_forwarding_state_bit": {
+ "choices": ["from-fib", "set"],
+ "type": "str",
+ },
+ "legacy_redirect_ip_action": {
+ "options": {
+ "receive": {"type": "bool"},
+ "send": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "local_ipv4_address": {"type": "str"},
+ "loops": {"type": "int"},
+ "no_install": {"type": "bool"},
+ "no_validate": {"type": "str"},
+ "output_queue_priority_expedited": {
+ "type": "bool",
+ },
+ "output_queue_priority_priority": {
+ "type": "int",
+ },
+ "per_group_label": {"type": "bool"},
+ "per_prefix_label": {"type": "bool"},
+ "prefix_limit": {
+ "options": {
+ "forever": {"type": "bool"},
+ "idle_timeout": {"type": "bool"},
+ "idle_timeout_value": {"type": "int"},
+ "limit_threshold": {"type": "int"},
+ "maximum": {"type": "int"},
+ "teardown": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "resolve_vpn": {"type": "bool"},
+ "rib": {"choices": ["inet.3"], "type": "str"},
+ "ribgroup_name": {"type": "str"},
+ "route_refresh_priority_expedited": {
+ "type": "bool",
+ },
+ "route_refresh_priority_priority": {
+ "type": "int",
+ },
+ "secondary_independent_resolution": {
+ "type": "bool",
+ },
+ "set": {"type": "bool"},
+ "strip_nexthop": {"type": "bool"},
+ "topology": {
+ "elements": "dict",
+ "options": {
+ "community": {
+ "elements": "str",
+ "type": "list",
+ },
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "traffic_statistics": {
+ "options": {
+ "file": {
+ "options": {
+ "filename": {"type": "str"},
+ "files": {"type": "int"},
+ "no_world_readable": {
+ "type": "bool",
+ },
+ "size": {"type": "int"},
+ "world_readable": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "interval": {"type": "int"},
+ "labeled_path": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "type": {
+ "choices": [
+ "any",
+ "flow",
+ "labeled-unicast",
+ "multicast",
+ "segment-routing-te",
+ "unicast",
+ "signaling",
+ "auto-discovery-mspw",
+ "auto-discovery-only",
+ ],
+ "type": "str",
+ },
+ "withdraw_priority_expedited": {
+ "type": "bool",
+ },
+ "withdraw_priority_priority": {"type": "int"},
+ },
+ "type": "list",
+ },
+ "afi": {
+ "choices": [
+ "evpn",
+ "inet",
+ "inet-mdt",
+ "inet-mvpn",
+ "inet-vpn",
+ "inet6",
+ "inet6-mvpn",
+ "inet6-vpn",
+ "iso-vpn",
+ "l2vpn",
+ "route-target",
+ "traffic-engineering",
+ ],
+ "type": "str",
+ },
+ },
+ "type": "list",
+ },
+ "groups": {
+ "elements": "dict",
+ "options": {
+ "address_family": {
+ "elements": "dict",
+ "options": {
+ "af_type": {
+ "elements": "dict",
+ "options": {
+ "accepted_prefix_limit": {
+ "options": {
+ "forever": {"type": "bool"},
+ "idle_timeout": {
+ "type": "bool",
+ },
+ "idle_timeout_value": {
+ "type": "int",
+ },
+ "limit_threshold": {
+ "type": "int",
+ },
+ "maximum": {"type": "int"},
+ "teardown": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "add_path": {
+ "options": {
+ "receive": {"type": "bool"},
+ "send": {
+ "options": {
+ "include_backup_path": {
+ "type": "int",
+ },
+ "multipath": {
+ "type": "bool",
+ },
+ "path_count": {
+ "required": True,
+ "type": "int",
+ },
+ "path_selection_mode": {
+ "options": {
+ "all_paths": {
+ "type": "bool",
+ },
+ "equal_cost_paths": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "prefix_policy": {
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "aggregate_label": {
+ "options": {
+ "community": {"type": "str"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "aigp": {
+ "options": {
+ "disable": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "damping": {"type": "bool"},
+ "defer_initial_multipath_build": {
+ "options": {
+ "maximum_delay": {
+ "type": "int",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "delay_route_advertisements": {
+ "options": {
+ "max_delay_route_age": {
+ "type": "int",
+ },
+ "max_delay_routing_uptime": {
+ "type": "int",
+ },
+ "min_delay_inbound_convergence": {
+ "type": "int",
+ },
+ "min_delay_routing_uptime": {
+ "type": "int",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "entropy_label": {
+ "options": {
+ "import": {"type": "str"},
+ "no_next_hop_validation": {
+ "type": "bool",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "explicit_null": {
+ "options": {
+ "connected_only": {
+ "type": "bool",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "extended_nexthop": {"type": "bool"},
+ "extended_nexthop_color": {
+ "type": "bool",
+ },
+ "graceful_restart_forwarding_state_bit": {
+ "choices": ["from-fib", "set"],
+ "type": "str",
+ },
+ "legacy_redirect_ip_action": {
+ "options": {
+ "receive": {"type": "bool"},
+ "send": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "local_ipv4_address": {"type": "str"},
+ "loops": {"type": "int"},
+ "no_install": {"type": "bool"},
+ "no_validate": {"type": "str"},
+ "output_queue_priority_expedited": {
+ "type": "bool",
+ },
+ "output_queue_priority_priority": {
+ "type": "int",
+ },
+ "per_group_label": {"type": "bool"},
+ "per_prefix_label": {"type": "bool"},
+ "prefix_limit": {
+ "options": {
+ "forever": {"type": "bool"},
+ "idle_timeout": {
+ "type": "bool",
+ },
+ "idle_timeout_value": {
+ "type": "int",
+ },
+ "limit_threshold": {
+ "type": "int",
+ },
+ "maximum": {"type": "int"},
+ "teardown": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "resolve_vpn": {"type": "bool"},
+ "rib": {
+ "choices": ["inet.3"],
+ "type": "str",
+ },
+ "ribgroup_name": {"type": "str"},
+ "route_refresh_priority_expedited": {
+ "type": "bool",
+ },
+ "route_refresh_priority_priority": {
+ "type": "int",
+ },
+ "secondary_independent_resolution": {
+ "type": "bool",
+ },
+ "set": {"type": "bool"},
+ "strip_nexthop": {"type": "bool"},
+ "topology": {
+ "elements": "dict",
+ "options": {
+ "community": {
+ "elements": "str",
+ "type": "list",
+ },
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "traffic_statistics": {
+ "options": {
+ "file": {
+ "options": {
+ "filename": {
+ "type": "str",
+ },
+ "files": {
+ "type": "int",
+ },
+ "no_world_readable": {
+ "type": "bool",
+ },
+ "size": {
+ "type": "int",
+ },
+ "world_readable": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "interval": {"type": "int"},
+ "labeled_path": {
+ "type": "bool",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "type": {
+ "choices": [
+ "any",
+ "flow",
+ "labeled-unicast",
+ "multicast",
+ "segment-routing-te",
+ "unicast",
+ "signaling",
+ "auto-discovery-mspw",
+ "auto-discovery-only",
+ ],
+ "type": "str",
+ },
+ "withdraw_priority_expedited": {
+ "type": "bool",
+ },
+ "withdraw_priority_priority": {
+ "type": "int",
+ },
+ },
+ "type": "list",
+ },
+ "afi": {
+ "choices": [
+ "evpn",
+ "inet",
+ "inet-mdt",
+ "inet-mvpn",
+ "inet-vpn",
+ "inet6",
+ "inet6-mvpn",
+ "inet6-vpn",
+ "iso-vpn",
+ "l2vpn",
+ "route-target",
+ "traffic-engineering",
+ ],
+ "type": "str",
+ },
+ },
+ "type": "list",
+ },
+ "name": {"type": "str"},
+ "neighbors": {
+ "elements": "dict",
+ "options": {
+ "address_family": {
+ "elements": "dict",
+ "options": {
+ "af_type": {
+ "elements": "dict",
+ "options": {
+ "accepted_prefix_limit": {
+ "options": {
+ "forever": {
+ "type": "bool",
+ },
+ "idle_timeout": {
+ "type": "bool",
+ },
+ "idle_timeout_value": {
+ "type": "int",
+ },
+ "limit_threshold": {
+ "type": "int",
+ },
+ "maximum": {
+ "type": "int",
+ },
+ "teardown": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "add_path": {
+ "options": {
+ "receive": {
+ "type": "bool",
+ },
+ "send": {
+ "options": {
+ "include_backup_path": {
+ "type": "int",
+ },
+ "multipath": {
+ "type": "bool",
+ },
+ "path_count": {
+ "required": True,
+ "type": "int",
+ },
+ "path_selection_mode": {
+ "options": {
+ "all_paths": {
+ "type": "bool",
+ },
+ "equal_cost_paths": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "prefix_policy": {
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "aggregate_label": {
+ "options": {
+ "community": {
+ "type": "str",
+ },
+ "set": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "aigp": {
+ "options": {
+ "disable": {
+ "type": "bool",
+ },
+ "set": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "damping": {"type": "bool"},
+ "defer_initial_multipath_build": {
+ "options": {
+ "maximum_delay": {
+ "type": "int",
+ },
+ "set": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "delay_route_advertisements": {
+ "options": {
+ "max_delay_route_age": {
+ "type": "int",
+ },
+ "max_delay_routing_uptime": {
+ "type": "int",
+ },
+ "min_delay_inbound_convergence": {
+ "type": "int",
+ },
+ "min_delay_routing_uptime": {
+ "type": "int",
+ },
+ "set": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "entropy_label": {
+ "options": {
+ "import": {
+ "type": "str",
+ },
+ "no_next_hop_validation": {
+ "type": "bool",
+ },
+ "set": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "explicit_null": {
+ "options": {
+ "connected_only": {
+ "type": "bool",
+ },
+ "set": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "extended_nexthop": {
+ "type": "bool",
+ },
+ "extended_nexthop_color": {
+ "type": "bool",
+ },
+ "graceful_restart_forwarding_state_bit": {
+ "choices": [
+ "from-fib",
+ "set",
+ ],
+ "type": "str",
+ },
+ "legacy_redirect_ip_action": {
+ "options": {
+ "receive": {
+ "type": "bool",
+ },
+ "send": {
+ "type": "bool",
+ },
+ "set": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "local_ipv4_address": {
+ "type": "str",
+ },
+ "loops": {"type": "int"},
+ "no_install": {"type": "bool"},
+ "no_validate": {"type": "str"},
+ "output_queue_priority_expedited": {
+ "type": "bool",
+ },
+ "output_queue_priority_priority": {
+ "type": "int",
+ },
+ "per_group_label": {
+ "type": "bool",
+ },
+ "per_prefix_label": {
+ "type": "bool",
+ },
+ "prefix_limit": {
+ "options": {
+ "forever": {
+ "type": "bool",
+ },
+ "idle_timeout": {
+ "type": "bool",
+ },
+ "idle_timeout_value": {
+ "type": "int",
+ },
+ "limit_threshold": {
+ "type": "int",
+ },
+ "maximum": {
+ "type": "int",
+ },
+ "teardown": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "resolve_vpn": {
+ "type": "bool",
+ },
+ "rib": {
+ "choices": ["inet.3"],
+ "type": "str",
+ },
+ "ribgroup_name": {
+ "type": "str",
+ },
+ "route_refresh_priority_expedited": {
+ "type": "bool",
+ },
+ "route_refresh_priority_priority": {
+ "type": "int",
+ },
+ "secondary_independent_resolution": {
+ "type": "bool",
+ },
+ "set": {"type": "bool"},
+ "strip_nexthop": {
+ "type": "bool",
+ },
+ "topology": {
+ "elements": "dict",
+ "options": {
+ "community": {
+ "elements": "str",
+ "type": "list",
+ },
+ "name": {
+ "type": "str",
+ },
+ },
+ "type": "list",
+ },
+ "traffic_statistics": {
+ "options": {
+ "file": {
+ "options": {
+ "filename": {
+ "type": "str",
+ },
+ "files": {
+ "type": "int",
+ },
+ "no_world_readable": {
+ "type": "bool",
+ },
+ "size": {
+ "type": "int",
+ },
+ "world_readable": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "interval": {
+ "type": "int",
+ },
+ "labeled_path": {
+ "type": "bool",
+ },
+ "set": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "type": {
+ "choices": [
+ "any",
+ "flow",
+ "labeled-unicast",
+ "multicast",
+ "segment-routing-te",
+ "unicast",
+ "signaling",
+ "auto-discovery-mspw",
+ "auto-discovery-only",
+ ],
+ "type": "str",
+ },
+ "withdraw_priority_expedited": {
+ "type": "bool",
+ },
+ "withdraw_priority_priority": {
+ "type": "int",
+ },
+ },
+ "type": "list",
+ },
+ "afi": {
+ "choices": [
+ "evpn",
+ "inet",
+ "inet-mdt",
+ "inet-mvpn",
+ "inet-vpn",
+ "inet6",
+ "inet6-mvpn",
+ "inet6-vpn",
+ "iso-vpn",
+ "l2vpn",
+ "route-target",
+ "traffic-engineering",
+ ],
+ "type": "str",
+ },
+ },
+ "type": "list",
+ },
+ "neighbor_address": {"type": "str"},
+ },
+ "type": "list",
+ },
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "gathered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_global/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_global/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_global/bgp_global.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_global/bgp_global.py
new file mode 100644
index 000000000..2cbbdf5e2
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/bgp_global/bgp_global.py
@@ -0,0 +1,1271 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 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_bgp_global module
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Bgp_globalArgs(object): # pylint: disable=R0903
+ """The arg spec for the junos_bgp_global module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "options": {
+ "accept_remote_nexthop": {"type": "bool"},
+ "add_path_display_ipv4_address": {"type": "bool"},
+ "advertise_bgp_static": {
+ "options": {
+ "policy": {"type": "str"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "advertise_external": {
+ "options": {
+ "conditional": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "advertise_from_main_vpn_tables": {"type": "bool"},
+ "advertise_inactive": {"type": "bool"},
+ "advertise_peer_as": {"type": "bool"},
+ "as_number": {"type": "str"},
+ "asdot_notation": {"type": "bool"},
+ "authentication_algorithm": {
+ "choices": ["aes-128-cmac-96", "hmac-sha-1-96", "md5"],
+ "type": "str",
+ },
+ "authentication_key": {"type": "str", "no_log": True},
+ "authentication_key_chain": {"type": "str", "no_log": False},
+ "bfd_liveness_detection": {
+ "options": {
+ "authentication": {
+ "options": {
+ "algorithm": {
+ "choices": [
+ "keyed-md5",
+ "keyed-sha-1",
+ "meticulous-keyed-md5",
+ "meticulous-keyed-sha-1",
+ "simple-password",
+ ],
+ "type": "str",
+ },
+ "key_chain": {"type": "str", "no_log": True},
+ "loose_check": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "detection_time": {
+ "options": {"threshold": {"type": "int"}},
+ "type": "dict",
+ },
+ "holddown_interval": {"type": "int"},
+ "minimum_interval": {"type": "int"},
+ "minimum_receive_interval": {"type": "int"},
+ "multiplier": {"type": "int"},
+ "no_adaptation": {"type": "bool"},
+ "session_mode": {
+ "choices": ["automatic", "multihop", "single-hop"],
+ "type": "str",
+ },
+ "transmit_interval": {
+ "options": {
+ "minimum_interval": {"type": "int"},
+ "threshold": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "version": {
+ "choices": ["0", "1", "automatic"],
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "bgp_error_tolerance": {
+ "options": {
+ "malformed_route_limit": {"type": "int"},
+ "malformed_update_log_interval": {"type": "int"},
+ "no_malformed_route_limit": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "bmp": {
+ "options": {
+ "monitor": {"type": "bool"},
+ "route_monitoring": {
+ "options": {
+ "none": {"type": "bool"},
+ "post_policy": {"type": "bool"},
+ "post_policy_exclude_non_eligible": {
+ "type": "bool",
+ },
+ "post_policy_exclude_non_feasible": {
+ "type": "bool",
+ },
+ "pre_policy": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "cluster_id": {"type": "str"},
+ "damping": {"type": "bool"},
+ "description": {"type": "str"},
+ "disable": {"type": "bool"},
+ "egress_te": {
+ "options": {
+ "backup_path": {"type": "str"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "egress_te_backup_paths": {
+ "options": {
+ "templates": {
+ "elements": "dict",
+ "options": {
+ "ip_forward": {
+ "options": {
+ "rti_name": {"type": "str"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "path_name": {"required": True, "type": "str"},
+ "peers": {"elements": "str", "type": "list"},
+ "remote_nexthop": {"type": "str"},
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "egress_te_set_segment": {
+ "elements": "dict",
+ "options": {
+ "egress_te_backup_segment_label": {"type": "int"},
+ "label": {"type": "int"},
+ "name": {"required": True, "type": "str"},
+ },
+ "type": "list",
+ },
+ "egress_te_sid_stats": {"type": "bool"},
+ "enforce_first_as": {"type": "bool"},
+ "export": {"type": "str"},
+ "forwarding_context": {"type": "str"},
+ "graceful_restart": {
+ "options": {
+ "disable": {"type": "bool"},
+ "dont_help_shared_fate_bfd_down": {"type": "bool"},
+ "forwarding_state_bit": {
+ "options": {
+ "as_rr_client": {"type": "bool"},
+ "from_fib": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "long_lived": {
+ "options": {
+ "advertise_to_non_llgr_neighbor": {
+ "options": {
+ "omit_no_export": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "receiver_disable": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "restart_time": {"type": "int"},
+ "set": {"type": "bool"},
+ "stale_routes_time": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "groups": {
+ "elements": "dict",
+ "options": {
+ "accept_remote_nexthop": {"type": "bool"},
+ "add_path_display_ipv4_address": {"type": "bool"},
+ "advertise_bgp_static": {
+ "options": {
+ "policy": {"type": "str"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "advertise_external": {
+ "options": {
+ "conditional": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "advertise_inactive": {"type": "bool"},
+ "advertise_peer_as": {"type": "bool"},
+ "allow": {"elements": "str", "type": "list"},
+ "as_override": {"type": "bool"},
+ "authentication_algorithm": {
+ "choices": [
+ "aes-128-cmac-96",
+ "hmac-sha-1-96",
+ "md5",
+ ],
+ "type": "str",
+ },
+ "authentication_key": {"type": "str", "no_log": True},
+ "authentication_key_chain": {
+ "type": "str",
+ "no_log": False,
+ },
+ "bfd_liveness_detection": {
+ "options": {
+ "authentication": {
+ "options": {
+ "algorithm": {
+ "choices": [
+ "keyed-md5",
+ "keyed-sha-1",
+ "meticulous-keyed-md5",
+ "meticulous-keyed-sha-1",
+ "simple-password",
+ ],
+ "type": "str",
+ },
+ "key_chain": {
+ "type": "str",
+ "no_log": True,
+ },
+ "loose_check": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "detection_time": {
+ "options": {"threshold": {"type": "int"}},
+ "type": "dict",
+ },
+ "holddown_interval": {"type": "int"},
+ "minimum_interval": {"type": "int"},
+ "minimum_receive_interval": {"type": "int"},
+ "multiplier": {"type": "int"},
+ "no_adaptation": {"type": "bool"},
+ "session_mode": {
+ "choices": [
+ "automatic",
+ "multihop",
+ "single-hop",
+ ],
+ "type": "str",
+ },
+ "transmit_interval": {
+ "options": {
+ "minimum_interval": {"type": "int"},
+ "threshold": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "version": {
+ "choices": ["0", "1", "automatic"],
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "bgp_error_tolerance": {
+ "options": {
+ "malformed_route_limit": {"type": "int"},
+ "malformed_update_log_interval": {
+ "type": "int",
+ },
+ "no_malformed_route_limit": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "bmp": {
+ "options": {
+ "monitor": {"type": "bool"},
+ "route_monitoring": {
+ "options": {
+ "none": {"type": "bool"},
+ "post_policy": {"type": "bool"},
+ "post_policy_exclude_non_eligible": {
+ "type": "bool",
+ },
+ "post_policy_exclude_non_feasible": {
+ "type": "bool",
+ },
+ "pre_policy": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "cluster_id": {"type": "str"},
+ "damping": {"type": "bool"},
+ "description": {"type": "str"},
+ "egress_te": {
+ "options": {
+ "backup_path": {"type": "str"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "enforce_first_as": {"type": "bool"},
+ "export": {"type": "str"},
+ "forwarding_context": {"type": "str"},
+ "graceful_restart": {
+ "options": {
+ "disable": {"type": "bool"},
+ "dont_help_shared_fate_bfd_down": {
+ "type": "bool",
+ },
+ "forwarding_state_bit": {
+ "options": {
+ "as_rr_client": {"type": "bool"},
+ "from_fib": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "long_lived": {
+ "options": {
+ "advertise_to_non_llgr_neighbor": {
+ "options": {
+ "omit_no_export": {
+ "type": "bool",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "receiver_disable": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "restart_time": {"type": "int"},
+ "set": {"type": "bool"},
+ "stale_routes_time": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "hold_time": {"type": "int"},
+ "idle_after_switch_over": {
+ "options": {
+ "forever": {"type": "bool"},
+ "timeout": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "import": {"elements": "str", "type": "list"},
+ "include_mp_next_hop": {"type": "bool"},
+ "ipsec_sa": {"type": "str"},
+ "keep": {"choices": ["all", "none"], "type": "str"},
+ "local_address": {"type": "str"},
+ "local_as": {
+ "options": {
+ "alias": {"type": "bool"},
+ "as_num": {"required": True, "type": "str"},
+ "loops": {"type": "int"},
+ "no_prepend_global_as": {"type": "bool"},
+ "private": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "local_interface": {"type": "str"},
+ "local_preference": {"type": "str"},
+ "log_updown": {"type": "bool"},
+ "metric_out": {
+ "options": {
+ "igp": {
+ "options": {
+ "delay_med_update": {"type": "bool"},
+ "metric_offset": {"type": "int"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "metric_value": {"type": "int"},
+ "minimum_igp": {
+ "options": {
+ "metric_offset": {"type": "int"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "mtu_discovery": {"type": "bool"},
+ "multihop": {
+ "options": {
+ "no_nexthop_change": {"type": "bool"},
+ "set": {"type": "bool"},
+ "ttl": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "multipath": {
+ "options": {
+ "disable": {"type": "bool"},
+ "multiple_as": {"type": "bool"},
+ "multiple_as_disable": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "name": {"type": "str"},
+ "neighbors": {
+ "elements": "dict",
+ "options": {
+ "accept_remote_nexthop": {"type": "bool"},
+ "add_path_display_ipv4_address": {
+ "type": "bool",
+ },
+ "advertise_bgp_static": {
+ "options": {
+ "policy": {"type": "str"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "advertise_external": {
+ "options": {
+ "conditional": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "advertise_inactive": {"type": "bool"},
+ "advertise_peer_as": {"type": "bool"},
+ "as_override": {"type": "bool"},
+ "authentication_algorithm": {
+ "choices": [
+ "aes-128-cmac-96",
+ "hmac-sha-1-96",
+ "md5",
+ ],
+ "type": "str",
+ },
+ "authentication_key": {
+ "type": "str",
+ "no_log": True,
+ },
+ "authentication_key_chain": {
+ "type": "str",
+ "no_log": False,
+ },
+ "bfd_liveness_detection": {
+ "options": {
+ "authentication": {
+ "options": {
+ "algorithm": {
+ "choices": [
+ "keyed-md5",
+ "keyed-sha-1",
+ "meticulous-keyed-md5",
+ "meticulous-keyed-sha-1",
+ "simple-password",
+ ],
+ "type": "str",
+ },
+ "key_chain": {
+ "type": "str",
+ "no_log": False,
+ },
+ "loose_check": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "detection_time": {
+ "options": {
+ "threshold": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "holddown_interval": {"type": "int"},
+ "minimum_interval": {"type": "int"},
+ "minimum_receive_interval": {
+ "type": "int",
+ },
+ "multiplier": {"type": "int"},
+ "no_adaptation": {"type": "bool"},
+ "session_mode": {
+ "choices": [
+ "automatic",
+ "multihop",
+ "single-hop",
+ ],
+ "type": "str",
+ },
+ "transmit_interval": {
+ "options": {
+ "minimum_interval": {
+ "type": "int",
+ },
+ "threshold": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "version": {
+ "choices": ["0", "1", "automatic"],
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "bgp_error_tolerance": {
+ "options": {
+ "malformed_route_limit": {
+ "type": "int",
+ },
+ "malformed_update_log_interval": {
+ "type": "int",
+ },
+ "no_malformed_route_limit": {
+ "type": "bool",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "bmp": {
+ "options": {
+ "monitor": {"type": "bool"},
+ "route_monitoring": {
+ "options": {
+ "none": {"type": "bool"},
+ "post_policy": {
+ "type": "bool",
+ },
+ "post_policy_exclude_non_eligible": {
+ "type": "bool",
+ },
+ "post_policy_exclude_non_feasible": {
+ "type": "bool",
+ },
+ "pre_policy": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "cluster_id": {"type": "str"},
+ "damping": {"type": "bool"},
+ "description": {"type": "str"},
+ "egress_te": {
+ "options": {
+ "backup_path": {"type": "str"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "enforce_first_as": {"type": "bool"},
+ "export": {"type": "str"},
+ "forwarding_context": {"type": "str"},
+ "graceful_restart": {
+ "options": {
+ "disable": {"type": "bool"},
+ "dont_help_shared_fate_bfd_down": {
+ "type": "bool",
+ },
+ "forwarding_state_bit": {
+ "options": {
+ "as_rr_client": {
+ "type": "bool",
+ },
+ "from_fib": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "long_lived": {
+ "options": {
+ "advertise_to_non_llgr_neighbor": {
+ "options": {
+ "omit_no_export": {
+ "type": "bool",
+ },
+ "set": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "receiver_disable": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "restart_time": {"type": "int"},
+ "set": {"type": "bool"},
+ "stale_routes_time": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "hold_time": {"type": "int"},
+ "idle_after_switch_over": {
+ "options": {
+ "forever": {"type": "bool"},
+ "timeout": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "import": {"elements": "str", "type": "list"},
+ "include_mp_next_hop": {"type": "bool"},
+ "ipsec_sa": {"type": "str"},
+ "keep": {
+ "choices": ["all", "none"],
+ "type": "str",
+ },
+ "local_address": {"type": "str"},
+ "local_as": {
+ "options": {
+ "alias": {"type": "bool"},
+ "as_num": {
+ "required": True,
+ "type": "str",
+ },
+ "loops": {"type": "int"},
+ "no_prepend_global_as": {
+ "type": "bool",
+ },
+ "private": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "local_interface": {"type": "str"},
+ "local_preference": {"type": "str"},
+ "log_updown": {"type": "bool"},
+ "metric_out": {
+ "options": {
+ "igp": {
+ "options": {
+ "delay_med_update": {
+ "type": "bool",
+ },
+ "metric_offset": {
+ "type": "int",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "metric_value": {"type": "int"},
+ "minimum_igp": {
+ "options": {
+ "metric_offset": {
+ "type": "int",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "mtu_discovery": {"type": "bool"},
+ "multihop": {
+ "options": {
+ "no_nexthop_change": {"type": "bool"},
+ "set": {"type": "bool"},
+ "ttl": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "multipath": {
+ "options": {
+ "disable": {"type": "bool"},
+ "multiple_as": {"type": "bool"},
+ "multiple_as_disable": {
+ "type": "bool",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "neighbor_address": {"type": "str"},
+ "no_advertise_peer_as": {"type": "bool"},
+ "no_aggregator_id": {"type": "bool"},
+ "no_client_reflect": {"type": "bool"},
+ "out_delay": {"type": "int"},
+ "outbound_route_filter": {
+ "options": {
+ "bgp_orf_cisco_mode": {"type": "bool"},
+ "prefix_based": {
+ "options": {
+ "accept": {
+ "options": {
+ "inet": {
+ "type": "bool",
+ },
+ "inet6": {
+ "type": "bool",
+ },
+ "set": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "passive": {"type": "bool"},
+ "peer_as": {"type": "str"},
+ "preference": {"type": "str"},
+ "remove_private": {
+ "options": {
+ "all": {"type": "bool"},
+ "all_replace": {"type": "bool"},
+ "all_replace_nearest": {
+ "type": "bool",
+ },
+ "no_peer_loop_check": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "rfc6514_compliant_safi129": {"type": "bool"},
+ "route_server_client": {"type": "bool"},
+ "tcp_aggressive_transmission": {
+ "type": "bool",
+ },
+ "tcp_mss": {"type": "int"},
+ "traceoptions": {
+ "options": {
+ "file": {
+ "options": {
+ "filename": {
+ "required": True,
+ "type": "str",
+ },
+ "files": {"type": "int"},
+ "no_world_readable": {
+ "type": "bool",
+ },
+ "size": {"type": "int"},
+ "world_readable": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "flag": {
+ "elements": "dict",
+ "options": {
+ "detail": {"type": "bool"},
+ "disable": {"type": "bool"},
+ "filter": {
+ "options": {
+ "match_on_prefix": {
+ "type": "bool",
+ },
+ "policy": {
+ "type": "str",
+ },
+ "set": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "name": {
+ "choices": [
+ "4byte-as",
+ "add-path",
+ "all",
+ "bfd",
+ "damping",
+ "egress-te",
+ "general",
+ "graceful-restart",
+ "keepalive",
+ "normal",
+ "nsr-synchronization",
+ "open",
+ "packets",
+ "policy",
+ "refresh",
+ "route",
+ "state",
+ "task",
+ "thread-io",
+ "thread-update-io",
+ "timer",
+ "update",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ "receive": {"type": "bool"},
+ "send": {"type": "bool"},
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "ttl": {"type": "int"},
+ "unconfigured_peer_graceful_restart": {
+ "type": "bool",
+ },
+ "vpn_apply_export": {"type": "bool"},
+ },
+ "type": "list",
+ },
+ "no_advertise_peer_as": {"type": "bool"},
+ "no_aggregator_id": {"type": "bool"},
+ "no_client_reflect": {"type": "bool"},
+ "optimal_route_reflection": {
+ "options": {
+ "igp_backup": {"type": "str"},
+ "igp_primary": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "out_delay": {"type": "int"},
+ "outbound_route_filter": {
+ "options": {
+ "bgp_orf_cisco_mode": {"type": "bool"},
+ "prefix_based": {
+ "options": {
+ "accept": {
+ "options": {
+ "inet": {"type": "bool"},
+ "inet6": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "passive": {"type": "bool"},
+ "peer_as": {"type": "str"},
+ "preference": {"type": "str"},
+ "remove_private": {
+ "options": {
+ "all": {"type": "bool"},
+ "all_replace": {"type": "bool"},
+ "all_replace_nearest": {"type": "bool"},
+ "no_peer_loop_check": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "rfc6514_compliant_safi129": {"type": "bool"},
+ "route_server_client": {"type": "bool"},
+ "tcp_aggressive_transmission": {"type": "bool"},
+ "tcp_mss": {"type": "int"},
+ "traceoptions": {
+ "options": {
+ "file": {
+ "options": {
+ "filename": {
+ "required": True,
+ "type": "str",
+ },
+ "files": {"type": "int"},
+ "no_world_readable": {"type": "bool"},
+ "size": {"type": "int"},
+ "world_readable": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "flag": {
+ "elements": "dict",
+ "options": {
+ "detail": {"type": "bool"},
+ "disable": {"type": "bool"},
+ "filter": {
+ "options": {
+ "match_on_prefix": {
+ "type": "bool",
+ },
+ "policy": {"type": "str"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "name": {
+ "choices": [
+ "4byte-as",
+ "add-path",
+ "all",
+ "bfd",
+ "damping",
+ "egress-te",
+ "general",
+ "graceful-restart",
+ "keepalive",
+ "normal",
+ "nsr-synchronization",
+ "open",
+ "packets",
+ "policy",
+ "refresh",
+ "route",
+ "state",
+ "task",
+ "thread-io",
+ "thread-update-io",
+ "timer",
+ "update",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ "receive": {"type": "bool"},
+ "send": {"type": "bool"},
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "ttl": {"type": "int"},
+ "type": {
+ "choices": ["external", "internal"],
+ "type": "str",
+ },
+ "unconfigured_peer_graceful_restart": {"type": "bool"},
+ "vpn_apply_export": {"type": "bool"},
+ },
+ "type": "list",
+ },
+ "hold_time": {"type": "int"},
+ "holddown_all_stale_labels": {"type": "bool"},
+ "idle_after_switch_over": {
+ "options": {
+ "forever": {"type": "bool"},
+ "timeout": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "import": {"elements": "str", "type": "list"},
+ "include_mp_next_hop": {"type": "bool"},
+ "ipsec_sa": {"type": "str"},
+ "keep": {"choices": ["all", "none"], "type": "str"},
+ "local_address": {"type": "str"},
+ "local_as": {
+ "options": {
+ "alias": {"type": "bool"},
+ "as_num": {"required": True, "type": "str"},
+ "loops": {"type": "int"},
+ "no_prepend_global_as": {"type": "bool"},
+ "private": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "local_interface": {"type": "str"},
+ "local_preference": {"type": "str"},
+ "log_updown": {"type": "bool"},
+ "loops": {"type": "int"},
+ "metric_out": {
+ "options": {
+ "igp": {
+ "options": {
+ "delay_med_update": {"type": "bool"},
+ "metric_offset": {"type": "int"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "metric_value": {"type": "int"},
+ "minimum_igp": {
+ "options": {
+ "metric_offset": {"type": "int"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "mtu_discovery": {"type": "bool"},
+ "multihop": {
+ "options": {
+ "no_nexthop_change": {"type": "bool"},
+ "set": {"type": "bool"},
+ "ttl": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "multipath": {
+ "options": {
+ "disable": {"type": "bool"},
+ "multiple_as": {"type": "bool"},
+ "multiple_as_disable": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "multipath_build_priority": {
+ "choices": ["low", "medium"],
+ "type": "str",
+ },
+ "no_advertise_peer_as": {"type": "bool"},
+ "no_aggregator_id": {"type": "bool"},
+ "no_client_reflect": {"type": "bool"},
+ "no_precision_timers": {"type": "bool"},
+ "out_delay": {"type": "int"},
+ "outbound_route_filter": {
+ "options": {
+ "bgp_orf_cisco_mode": {"type": "bool"},
+ "prefix_based": {
+ "options": {
+ "accept": {
+ "options": {
+ "inet": {"type": "bool"},
+ "inet6": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "output_queue_priority": {
+ "options": {
+ "defaults": {
+ "options": {
+ "high": {
+ "options": {
+ "expedited": {"type": "bool"},
+ "priority": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "low": {
+ "options": {
+ "expedited": {"type": "bool"},
+ "priority": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "medium": {
+ "options": {
+ "expedited": {"type": "bool"},
+ "priority": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "expedited_update_tokens": {
+ "type": "int",
+ "no_log": True,
+ },
+ "priority_update_tokens": {
+ "elements": "dict",
+ "no_log": True,
+ "options": {
+ "priority": {"required": True, "type": "int"},
+ "update_tokens": {
+ "required": True,
+ "type": "int",
+ "no_log": True,
+ },
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "passive": {"type": "bool"},
+ "path_selection": {
+ "options": {
+ "always_compare_med": {"type": "bool"},
+ "as_path_ignore": {"type": "bool"},
+ "cisco_non_deterministic": {"type": "bool"},
+ "external_router_id": {"type": "bool"},
+ "l2vpn_use_bgp_rules": {"type": "bool"},
+ "med_plus_igp": {
+ "options": {
+ "igp_multiplier": {"type": "int"},
+ "med_multiplier": {"type": "int"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "peer_as": {"type": "str"},
+ "precision_timers": {"type": "bool"},
+ "preference": {"type": "str"},
+ "remove_private": {
+ "options": {
+ "all": {"type": "bool"},
+ "all_replace": {"type": "bool"},
+ "all_replace_nearest": {"type": "bool"},
+ "no_peer_loop_check": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "rfc6514_compliant_safi129": {"type": "bool"},
+ "route_server_client": {"type": "bool"},
+ "send_addpath_optimization": {"type": "bool"},
+ "snmp_options": {
+ "options": {
+ "backward_traps_only_from_established": {
+ "type": "bool",
+ },
+ "emit_inet_address_length_in_oid": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "sr_preference_override": {"type": "str"},
+ "stale_labels_holddown_period": {"type": "int"},
+ "tcp_aggressive_transmission": {"type": "bool"},
+ "tcp_mss": {"type": "int"},
+ "traceoptions": {
+ "options": {
+ "file": {
+ "options": {
+ "filename": {"required": True, "type": "str"},
+ "files": {"type": "int"},
+ "no_world_readable": {"type": "bool"},
+ "size": {"type": "int"},
+ "world_readable": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "flag": {
+ "elements": "dict",
+ "options": {
+ "detail": {"type": "bool"},
+ "disable": {"type": "bool"},
+ "filter": {
+ "options": {
+ "match_on_prefix": {"type": "bool"},
+ "policy": {"type": "str"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "name": {
+ "choices": [
+ "4byte-as",
+ "add-path",
+ "all",
+ "bfd",
+ "damping",
+ "egress-te",
+ "general",
+ "graceful-restart",
+ "keepalive",
+ "normal",
+ "nsr-synchronization",
+ "open",
+ "packets",
+ "policy",
+ "refresh",
+ "route",
+ "state",
+ "task",
+ "thread-io",
+ "thread-update-io",
+ "timer",
+ "update",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ "receive": {"type": "bool"},
+ "send": {"type": "bool"},
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "traffic_statistics_labeled_path": {
+ "options": {
+ "file": {
+ "options": {
+ "filename": {"type": "str"},
+ "files": {"type": "int"},
+ "no_world_readable": {"type": "bool"},
+ "size": {"type": "int"},
+ "world_readable": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "interval": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "ttl": {"type": "int"},
+ "unconfigured_peer_graceful_restart": {"type": "bool"},
+ "vpn_apply_export": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "purged",
+ "merged",
+ "replaced",
+ "deleted",
+ "gathered",
+ "parsed",
+ "rendered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/facts/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/facts/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/facts/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/facts/facts.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/facts/facts.py
new file mode 100644
index 000000000..2ee80bd7a
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/facts/facts.py
@@ -0,0 +1,29 @@
+#
+# -*- 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.
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class FactsArgs(object):
+ """The arg spec for the junos facts module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "gather_subset": dict(default=["min"], type="list", elements="str"),
+ "config_format": dict(
+ default="text",
+ choices=["xml", "text", "set", "json"],
+ ),
+ "gather_network_resources": dict(type="list", elements="str"),
+ "available_network_resources": {"type": "bool", "default": False},
+ }
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/hostname/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/hostname/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/hostname/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/hostname/hostname.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/hostname/hostname.py
new file mode 100644
index 000000000..84e70cfd0
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/hostname/hostname.py
@@ -0,0 +1,56 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 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_hostname module
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class HostnameArgs(object): # pylint: disable=R0903
+ """The arg spec for the junos_hostname module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {"options": {"hostname": {"type": "str"}}, "type": "dict"},
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "deleted",
+ "overridden",
+ "parsed",
+ "gathered",
+ "rendered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/interfaces/interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/interfaces/interfaces.py
new file mode 100644
index 000000000..bc152bd38
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/interfaces/interfaces.py
@@ -0,0 +1,86 @@
+#
+# -*- 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"},
+ "units": {
+ "elements": "dict",
+ "options": {
+ "name": {"type": "int"},
+ "description": {"type": "str"},
+ },
+ "type": "list",
+ },
+ },
+ "type": "list",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l2_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l2_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l2_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l2_interfaces/l2_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l2_interfaces/l2_interfaces.py
new file mode 100644
index 000000000..e2495ff24
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l2_interfaces/l2_interfaces.py
@@ -0,0 +1,75 @@
+#
+# -*- 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": {"elements": "str", "type": "list"},
+ "native_vlan": {"type": "str"},
+ },
+ },
+ "unit": {"type": "int"},
+ "enhanced_layer": {"type": "bool"},
+ },
+ "type": "list",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l3_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l3_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l3_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l3_interfaces/l3_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l3_interfaces/l3_interfaces.py
new file mode 100644
index 000000000..ec89c3233
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/l3_interfaces/l3_interfaces.py
@@ -0,0 +1,54 @@
+# -*- 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",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "parsed",
+ "rendered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp/lacp.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp/lacp.py
new file mode 100644
index 000000000..e666d5f94
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp/lacp.py
@@ -0,0 +1,64 @@
+#
+# -*- 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"},
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp_interfaces/lacp_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp_interfaces/lacp_interfaces.py
new file mode 100644
index 000000000..052a54b06
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lacp_interfaces/lacp_interfaces.py
@@ -0,0 +1,79 @@
+#
+# -*- 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",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lag_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lag_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lag_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lag_interfaces/lag_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lag_interfaces/lag_interfaces.py
new file mode 100644
index 000000000..c0a56f0cd
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lag_interfaces/lag_interfaces.py
@@ -0,0 +1,72 @@
+#
+# -*- 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",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "parsed",
+ "rendered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_global/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_global/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_global/lldp_global.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_global/lldp_global.py
new file mode 100644
index 000000000..8f25d4e10
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_global/lldp_global.py
@@ -0,0 +1,64 @@
+#
+# -*- 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",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_interfaces/lldp_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_interfaces/lldp_interfaces.py
new file mode 100644
index 000000000..272302bf0
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/lldp_interfaces/lldp_interfaces.py
@@ -0,0 +1,63 @@
+#
+# -*- 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",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "deleted",
+ "overridden",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/logging_global/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/logging_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/logging_global/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/logging_global/logging_global.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/logging_global/logging_global.py
new file mode 100644
index 000000000..a00263a50
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/logging_global/logging_global.py
@@ -0,0 +1,1380 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 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_logging_global module
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Logging_globalArgs(object): # pylint: disable=R0903
+ """The arg spec for the junos_logging_global module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "options": {
+ "allow_duplicates": {"type": "bool"},
+ "archive": {
+ "options": {
+ "binary_data": {"type": "bool"},
+ "file_size": {"type": "str"},
+ "files": {"type": "int"},
+ "no_binary_data": {"type": "bool"},
+ "no_world_readable": {"type": "bool"},
+ "set": {"type": "bool"},
+ "world_readable": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "console": {
+ "options": {
+ "any": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "authorization": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "change_log": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "conflict_log": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "daemon": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "dfc": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "external": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "firewall": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "ftp": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "interactive_commands": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "kernel": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "ntp": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "pfe": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "security": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "user": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "files": {
+ "elements": "dict",
+ "options": {
+ "allow_duplicates": {"type": "bool"},
+ "any": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "archive": {
+ "options": {
+ "archive_sites": {
+ "elements": "str",
+ "type": "list",
+ },
+ "binary_data": {"type": "bool"},
+ "file_size": {"type": "str"},
+ "files": {"type": "int"},
+ "no_binary_data": {"type": "bool"},
+ "no_world_readable": {"type": "bool"},
+ "set": {"type": "bool"},
+ "start_time": {"type": "str"},
+ "transfer_interval": {"type": "int"},
+ "world_readable": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "authorization": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "change_log": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "conflict_log": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "daemon": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "dfc": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "explicit_priority": {"type": "bool"},
+ "external": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "firewall": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "ftp": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "interactive_commands": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "kernel": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "match": {"type": "str"},
+ "match_strings": {"elements": "str", "type": "list"},
+ "name": {"type": "str"},
+ "ntp": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "pfe": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "security": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "structured_data": {
+ "options": {
+ "brief": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "user": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "list",
+ },
+ "hosts": {
+ "elements": "dict",
+ "options": {
+ "allow_duplicates": {"type": "bool"},
+ "any": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "authorization": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "change_log": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "conflict_log": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "daemon": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "dfc": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "exclude_hostname": {"type": "bool"},
+ "explicit_priority": {"type": "bool"},
+ "external": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "facility_override": {"type": "str"},
+ "firewall": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "ftp": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "interactive_commands": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "kernel": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "log_prefix": {"type": "str"},
+ "match": {"type": "str"},
+ "match_strings": {"elements": "str", "type": "list"},
+ "name": {"type": "str"},
+ "ntp": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "pfe": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "port": {"type": "int"},
+ "routing_instance": {"type": "str"},
+ "security": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "source_address": {"type": "str"},
+ "structured_data": {
+ "options": {
+ "brief": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "user": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "list",
+ },
+ "log_rotate_frequency": {"type": "int"},
+ "routing_instance": {"type": "str"},
+ "server": {
+ "options": {
+ "routing_instance": {
+ "options": {
+ "all": {"type": "bool"},
+ "default": {"type": "bool"},
+ "routing_instances": {
+ "elements": "dict",
+ "options": {
+ "disable": {"type": "bool"},
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "source_address": {"type": "str"},
+ "time_format": {
+ "options": {
+ "set": {"type": "bool"},
+ "millisecond": {"type": "bool"},
+ "year": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "users": {
+ "elements": "dict",
+ "options": {
+ "allow_duplicates": {"type": "bool"},
+ "any": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "authorization": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "change_log": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "conflict_log": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "daemon": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "dfc": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "external": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "firewall": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "ftp": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "interactive_commands": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "kernel": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "match": {"type": "str"},
+ "match_strings": {"elements": "str", "type": "list"},
+ "name": {"type": "str"},
+ "ntp": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "pfe": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "security": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "user": {
+ "options": {
+ "level": {
+ "choices": [
+ "alert",
+ "any",
+ "critical",
+ "emergency",
+ "error",
+ "info",
+ "none",
+ "notice",
+ "warning",
+ ],
+ "required": True,
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "parsed",
+ "gathered",
+ "rendered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ntp_global/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ntp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ntp_global/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ntp_global/ntp_global.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ntp_global/ntp_global.py
new file mode 100644
index 000000000..d8fdf2678
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ntp_global/ntp_global.py
@@ -0,0 +1,133 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 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_ntp_global module
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Ntp_globalArgs(object): # pylint: disable=R0903
+ """The arg spec for the junos_ntp_global module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "options": {
+ "authentication_keys": {
+ "elements": "dict",
+ "no_log": False,
+ "options": {
+ "algorithm": {
+ "choices": ["md5", "sha1", "sha256"],
+ "type": "str",
+ },
+ "id": {"type": "int"},
+ "key": {"type": "str", "no_log": True},
+ },
+ "type": "list",
+ },
+ "boot_server": {"type": "str"},
+ "broadcast_client": {"type": "bool"},
+ "broadcasts": {
+ "elements": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "key": {"type": "str", "no_log": False},
+ "routing_instance_name": {"type": "str"},
+ "ttl": {"type": "int"},
+ "version": {"type": "int"},
+ },
+ "type": "list",
+ },
+ "interval_range": {"type": "int"},
+ "multicast_client": {"type": "str"},
+ "peers": {
+ "elements": "dict",
+ "options": {
+ "key_id": {"type": "int", "no_log": False},
+ "peer": {"type": "str"},
+ "prefer": {"type": "bool"},
+ "version": {"type": "int"},
+ },
+ "type": "list",
+ },
+ "servers": {
+ "elements": "dict",
+ "options": {
+ "key_id": {"type": "int"},
+ "prefer": {"type": "bool"},
+ "routing_instance": {"type": "str"},
+ "server": {"type": "str"},
+ "version": {"type": "int"},
+ },
+ "type": "list",
+ },
+ "source_addresses": {
+ "elements": "dict",
+ "options": {
+ "routing_instance": {"type": "str"},
+ "source_address": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "threshold": {
+ "options": {
+ "action": {
+ "choices": ["accept", "reject"],
+ "type": "str",
+ },
+ "value": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "trusted_keys": {
+ "type": "list",
+ "elements": "dict",
+ "no_log": False,
+ "options": {"key_id": {"type": "int"}},
+ },
+ },
+ "type": "dict",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "deleted",
+ "overridden",
+ "parsed",
+ "gathered",
+ "rendered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospf_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospf_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospf_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospf_interfaces/ospf_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospf_interfaces/ospf_interfaces.py
new file mode 100644
index 000000000..5bf718991
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospf_interfaces/ospf_interfaces.py
@@ -0,0 +1,141 @@
+#
+# -*- 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_ospf_interfaces module
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Ospf_interfacesArgs(object): # pylint: disable=R0903
+ """The arg spec for the junos_ospf_interfaces module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "elements": "dict",
+ "options": {
+ "router_id": {"type": "str"},
+ "address_family": {
+ "elements": "dict",
+ "options": {
+ "afi": {
+ "choices": ["ipv4", "ipv6"],
+ "required": True,
+ "type": "str",
+ },
+ "processes": {
+ "options": {
+ "area": {
+ "options": {"area_id": {"type": "str"}},
+ "type": "dict",
+ },
+ "authentication": {
+ "options": {
+ "md5": {
+ "options": {
+ "key_id": {"type": "str"},
+ "key_value": {
+ "type": "str",
+ "no_log": True,
+ },
+ "start_time": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "simple_password": {
+ "type": "str",
+ "no_log": True,
+ },
+ },
+ "type": "dict",
+ },
+ "bandwidth_based_metrics": {
+ "elements": "dict",
+ "options": {
+ "bandwidth": {
+ "choices": ["1g", "10g"],
+ "type": "str",
+ },
+ "metric": {"type": "int"},
+ },
+ "type": "list",
+ },
+ "dead_interval": {"type": "int"},
+ "demand_circuit": {"type": "bool"},
+ "flood_reduction": {"type": "bool"},
+ "hello_interval": {"type": "int"},
+ "interface_type": {
+ "choices": ["nbma", "p2mp", "p2p"],
+ "type": "str",
+ },
+ "ipsec_sa": {"type": "str"},
+ "metric": {"type": "int"},
+ "mtu": {"type": "int"},
+ "no_advertise_adjacency_segment": {
+ "type": "bool",
+ },
+ "no_eligible_backup": {"type": "bool"},
+ "no_eligible_remote_backup": {"type": "bool"},
+ "no_interface_state_traps": {"type": "bool"},
+ "no_neighbor_down_notification": {
+ "type": "bool",
+ },
+ "node_link_protection": {"type": "str"},
+ "poll_interval": {"type": "int"},
+ "priority": {"type": "int"},
+ "passive": {"type": "bool"},
+ "retransmit_interval": {"type": "int"},
+ "secondary": {"type": "bool"},
+ "te_metric": {"type": "int"},
+ "transit_delay": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "list",
+ },
+ "name": {"required": True, "type": "str"},
+ },
+ "type": "list",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "parsed",
+ "rendered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv2/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv2/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv2/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv2/ospfv2.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv2/ospfv2.py
new file mode 100644
index 000000000..a160512a2
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv2/ospfv2.py
@@ -0,0 +1,125 @@
+# Copyright (C) 2020 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 arg spec for the junos_ospfv2 module
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Ospfv2Args(object): # pylint: disable=R0903
+ """The arg spec for the junos_ospfv2 module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "elements": "dict",
+ "options": {
+ "router_id": {"type": "str"},
+ "areas": {
+ "elements": "dict",
+ "options": {
+ "area_id": {"required": True, "type": "str"},
+ "area_range": {"type": "str"},
+ "stub": {
+ "type": "dict",
+ "options": {
+ "default_metric": {"type": "int"},
+ "set": {"type": "bool"},
+ },
+ },
+ "interfaces": {
+ "elements": "dict",
+ "options": {
+ "authentication": {
+ "type": "dict",
+ "options": {"type": {"type": "dict"}},
+ },
+ "bandwidth_based_metrics": {
+ "elements": "dict",
+ "options": {
+ "bandwidth": {
+ "choices": ["1g", "10g"],
+ "type": "str",
+ },
+ "metric": {"type": "int"},
+ },
+ "type": "list",
+ },
+ "name": {"required": True, "type": "str"},
+ "priority": {"type": "int"},
+ "metric": {"type": "int"},
+ "flood_reduction": {"type": "bool"},
+ "passive": {"type": "bool"},
+ "timers": {
+ "type": "dict",
+ "options": {
+ "dead_interval": {"type": "int"},
+ "hello_interval": {"type": "int"},
+ "poll_interval": {"type": "int"},
+ "retransmit_interval": {"type": "int"},
+ "transit_delay": {"type": "int"},
+ },
+ },
+ },
+ "type": "list",
+ },
+ },
+ "type": "list",
+ },
+ "external_preference": {"type": "int"},
+ "overload": {
+ "type": "dict",
+ "options": {"timeout": {"type": "int"}},
+ },
+ "preference": {"type": "int"},
+ "prefix_export_limit": {"type": "int"},
+ "reference_bandwidth": {
+ "choices": ["1g", "10g"],
+ "type": "str",
+ },
+ "rfc1583compatibility": {"type": "bool"},
+ "spf_options": {
+ "type": "dict",
+ "options": {
+ "delay": {"type": "int"},
+ "holddown": {"type": "int"},
+ "rapid_runs": {"type": "int"},
+ },
+ },
+ },
+ "type": "list",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv3/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv3/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv3/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv3/ospfv3.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv3/ospfv3.py
new file mode 100644
index 000000000..f08691e8f
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/ospfv3/ospfv3.py
@@ -0,0 +1,125 @@
+# Copyright (C) 2020 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 arg spec for the junos_ospfv3 module
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Ospfv3Args(object): # pylint: disable=R0903
+ """The arg spec for the junos_ospfv3 module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "elements": "dict",
+ "options": {
+ "router_id": {"type": "str"},
+ "areas": {
+ "elements": "dict",
+ "options": {
+ "area_id": {"required": True, "type": "str"},
+ "area_range": {"type": "str"},
+ "stub": {
+ "type": "dict",
+ "options": {
+ "default_metric": {"type": "int"},
+ "set": {"type": "bool"},
+ },
+ },
+ "interfaces": {
+ "elements": "dict",
+ "options": {
+ "authentication": {
+ "type": "dict",
+ "options": {"type": {"type": "dict"}},
+ },
+ "bandwidth_based_metrics": {
+ "elements": "dict",
+ "options": {
+ "bandwidth": {
+ "choices": ["1g", "10g"],
+ "type": "str",
+ },
+ "metric": {"type": "int"},
+ },
+ "type": "list",
+ },
+ "name": {"required": True, "type": "str"},
+ "priority": {"type": "int"},
+ "metric": {"type": "int"},
+ "flood_reduction": {"type": "bool"},
+ "passive": {"type": "bool"},
+ "timers": {
+ "type": "dict",
+ "options": {
+ "dead_interval": {"type": "int"},
+ "hello_interval": {"type": "int"},
+ "poll_interval": {"type": "int"},
+ "retransmit_interval": {"type": "int"},
+ "transit_delay": {"type": "int"},
+ },
+ },
+ },
+ "type": "list",
+ },
+ },
+ "type": "list",
+ },
+ "external_preference": {"type": "int"},
+ "overload": {
+ "type": "dict",
+ "options": {"timeout": {"type": "int"}},
+ },
+ "preference": {"type": "int"},
+ "prefix_export_limit": {"type": "int"},
+ "reference_bandwidth": {
+ "choices": ["1g", "10g"],
+ "type": "str",
+ },
+ "rfc1583compatibility": {"type": "bool"},
+ "spf_options": {
+ "type": "dict",
+ "options": {
+ "delay": {"type": "int"},
+ "holddown": {"type": "int"},
+ "rapid_runs": {"type": "int"},
+ },
+ },
+ },
+ "type": "list",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/prefix_lists/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/prefix_lists/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/prefix_lists/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/prefix_lists/prefix_lists.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/prefix_lists/prefix_lists.py
new file mode 100644
index 000000000..a85741c4a
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/prefix_lists/prefix_lists.py
@@ -0,0 +1,63 @@
+#
+# -*- 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_prefix_lists module
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Prefix_listsArgs(object): # pylint: disable=R0903
+ """The arg spec for the junos_prefix_lists module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "elements": "dict",
+ "options": {
+ "address_prefixes": {"elements": "str", "type": "list"},
+ "dynamic_db": {"type": "bool"},
+ "name": {"type": "str", "required": True},
+ },
+ "type": "list",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "parsed",
+ "gathered",
+ "rendered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_instances/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_instances/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_instances/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_instances/routing_instances.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_instances/routing_instances.py
new file mode 100644
index 000000000..93e69943b
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_instances/routing_instances.py
@@ -0,0 +1,108 @@
+#
+# -*- 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_routing_instances module
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Routing_instancesArgs(object): # pylint: disable=R0903
+ """The arg spec for the junos_routing_instances module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "elements": "dict",
+ "options": {
+ "connector_id_advertise": {"type": "bool"},
+ "description": {"type": "str"},
+ "egress_protection": {
+ "options": {
+ "context_identifier": {"type": "str"},
+ "protector": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "instance_role": {"choices": ["access", "nni"], "type": "str"},
+ "interfaces": {
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "protect_interface": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "l2vpn_id": {"type": "str"},
+ "name": {"type": "str"},
+ "no_irb_layer_2_copy": {"type": "bool"},
+ "no_local_switching": {"type": "bool"},
+ "no_normalization": {"type": "bool"},
+ "no_vrf_advertise": {"type": "bool"},
+ "no_vrf_propagate_ttl": {"type": "bool"},
+ "qualified_bum_pruning_mode": {"type": "bool"},
+ "route_distinguisher": {"type": "str"},
+ "routing_interface": {"elements": "str", "type": "list"},
+ "type": {
+ "choices": [
+ "evpn",
+ "evpn-vpws",
+ "forwarding",
+ "l2backhaul-vpn",
+ "l2vpn",
+ "layer2-control",
+ "mac-vrf",
+ "mpls-forwarding",
+ "mpls-internet-multicast",
+ "no-forwarding",
+ "virtual-router",
+ "vpls",
+ "vrf",
+ ],
+ "type": "str",
+ },
+ "vrf_exports": {"elements": "str", "type": "list"},
+ "vrf_imports": {"elements": "str", "type": "list"},
+ },
+ "type": "list",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "parsed",
+ "gathered",
+ "rendered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_options/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_options/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_options/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_options/routing_options.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_options/routing_options.py
new file mode 100644
index 000000000..270d5a815
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/routing_options/routing_options.py
@@ -0,0 +1,69 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 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_routing_options module
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Routing_optionsArgs(object): # pylint: disable=R0903
+ """The arg spec for the junos_routing_options module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "options": {
+ "autonomous_system": {
+ "options": {
+ "as_number": {"type": "str", "required": True},
+ "asdot_notation": {"type": "bool"},
+ "loops": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "router_id": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "deleted",
+ "overridden",
+ "parsed",
+ "gathered",
+ "rendered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies/security_policies.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies/security_policies.py
new file mode 100644
index 000000000..3c28c6418
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies/security_policies.py
@@ -0,0 +1,822 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2022 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.
+#
+#############################################
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+"""
+The arg spec for the junos_security_policies module
+"""
+
+
+class Security_policiesArgs(object): # pylint: disable=R0903
+ """The arg spec for the junos_security_policies module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "options": {
+ "from_zones": {
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "to_zones": {
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "policies": {
+ "elements": "dict",
+ "options": {
+ "description": {"type": "str"},
+ "match": {
+ "options": {
+ "application": {
+ "options": {
+ "any": {
+ "type": "bool",
+ },
+ "names": {
+ "elements": "str",
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "destination_address": {
+ "options": {
+ "addresses": {
+ "elements": "str",
+ "type": "list",
+ },
+ "any": {
+ "type": "bool",
+ },
+ "any_ipv4": {
+ "type": "bool",
+ },
+ "any_ipv6": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "destination_address_excluded": {
+ "type": "bool",
+ },
+ "dynamic_application": {
+ "options": {
+ "any": {
+ "type": "bool",
+ },
+ "names": {
+ "elements": "str",
+ "type": "list",
+ },
+ "none": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "from_zone": {
+ "options": {
+ "any": {
+ "type": "bool",
+ },
+ "junos_host": {
+ "type": "bool",
+ },
+ "names": {
+ "elements": "str",
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "source_address": {
+ "options": {
+ "addresses": {
+ "elements": "str",
+ "type": "list",
+ },
+ "any": {
+ "type": "bool",
+ },
+ "any_ipv4": {
+ "type": "bool",
+ },
+ "any_ipv6": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "source_address_excluded": {
+ "type": "bool",
+ },
+ "source_end_user_profile": {
+ "type": "str",
+ },
+ "source_identity": {
+ "options": {
+ "any": {
+ "type": "bool",
+ },
+ "authenticated_user": {
+ "type": "bool",
+ },
+ "names": {
+ "elements": "str",
+ "type": "list",
+ },
+ "unauthenticated_user": {
+ "type": "bool",
+ },
+ "unknown_user": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "to_zone": {
+ "options": {
+ "any": {
+ "type": "bool",
+ },
+ "junos_host": {
+ "type": "bool",
+ },
+ "names": {
+ "elements": "str",
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "url_category": {
+ "options": {
+ "any": {
+ "type": "bool",
+ },
+ "names": {
+ "elements": "str",
+ "type": "list",
+ },
+ "none": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "name": {"type": "str"},
+ "scheduler_name": {"type": "str"},
+ "then": {
+ "options": {
+ "count": {"type": "bool"},
+ "deny": {"type": "bool"},
+ "log": {
+ "options": {
+ "session_close": {
+ "type": "bool",
+ },
+ "session_init": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "permit": {
+ "options": {
+ "application_services": {
+ "options": {
+ "advanced_anti_malware_policy": {
+ "type": "str",
+ },
+ "application_firewalls": {
+ "elements": "dict",
+ "options": {
+ "rule_set": {
+ "type": "str",
+ },
+ },
+ "type": "list",
+ },
+ "application_traffic_control_rule_set": {
+ "type": "str",
+ },
+ "gprs_gtp_profile": {
+ "type": "str",
+ },
+ "gprs_sctp_profile": {
+ "type": "str",
+ },
+ "icap_redirect": {
+ "type": "str",
+ },
+ "idp": {
+ "type": "bool",
+ },
+ "idp_policy": {
+ "type": "str",
+ },
+ "packet_capture": {
+ "type": "bool",
+ },
+ "redirect_wx": {
+ "type": "bool",
+ },
+ "reverse_redirect_wx": {
+ "type": "bool",
+ },
+ "security_intelligence": {
+ "options": {
+ "add_destination_identity_to_feed": {
+ "type": "str",
+ },
+ "add_destination_ip_to_feed": {
+ "type": "str",
+ },
+ "add_source_identity_to_feed": {
+ "type": "str",
+ },
+ "add_source_ip_to_feed": {
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "security_intelligence_policy": {
+ "type": "str",
+ },
+ "ssl_proxy": {
+ "options": {
+ "enable": {
+ "type": "bool",
+ },
+ "profile_name": {
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "uac_policy": {
+ "options": {
+ "captive_portal": {
+ "type": "str",
+ },
+ "enable": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "utm_policy": {
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "destination_address": {
+ "choices": [
+ "drop-translated",
+ "drop-untranslated",
+ ],
+ "type": "str",
+ },
+ "firewall_authentication": {
+ "options": {
+ "pass_through": {
+ "no_log": True,
+ "options": {
+ "access_profile": {
+ "type": "str",
+ },
+ "auth_only_browser": {
+ "type": "bool",
+ },
+ "auth_user_agent": {
+ "type": "str",
+ },
+ "client_match": {
+ "type": "str",
+ },
+ "ssl_termination_profile": {
+ "type": "str",
+ },
+ "web_redirect": {
+ "type": "bool",
+ },
+ "web_redirect_to_https": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "push_to_identity_management": {
+ "type": "bool",
+ },
+ "user_firewall": {
+ "options": {
+ "access_profile": {
+ "type": "str",
+ },
+ "auth_only_browser": {
+ "type": "bool",
+ },
+ "auth_user_agent": {
+ "type": "str",
+ },
+ "domain": {
+ "type": "str",
+ },
+ "ssl_termination_profile": {
+ "type": "str",
+ },
+ "web_redirect": {
+ "type": "bool",
+ },
+ "web_redirect_to_https": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "web_authentication": {
+ "elements": "str",
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "tcp_options": {
+ "options": {
+ "initial_tcp_mss": {
+ "type": "int",
+ },
+ "reverse_tcp_mss": {
+ "type": "int",
+ },
+ "sequence_check_required": {
+ "type": "bool",
+ },
+ "syn_check_required": {
+ "type": "bool",
+ },
+ "window_scale": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "tunnel": {
+ "options": {
+ "ipsec_vpn": {
+ "type": "str",
+ },
+ "pair_policy": {
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "reject": {
+ "options": {
+ "enable": {
+ "type": "bool",
+ },
+ "profile": {
+ "type": "str",
+ },
+ "ssl_proxy": {
+ "options": {
+ "enable": {
+ "type": "bool",
+ },
+ "profile_name": {
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "list",
+ },
+ },
+ "type": "list",
+ },
+ },
+ "type": "list",
+ },
+ "global": {
+ "options": {
+ "policies": {
+ "elements": "dict",
+ "options": {
+ "description": {"type": "str"},
+ "match": {
+ "options": {
+ "application": {
+ "options": {
+ "any": {"type": "bool"},
+ "names": {
+ "elements": "str",
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "destination_address": {
+ "options": {
+ "addresses": {
+ "elements": "str",
+ "type": "list",
+ },
+ "any": {"type": "bool"},
+ "any_ipv4": {"type": "bool"},
+ "any_ipv6": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "destination_address_excluded": {
+ "type": "bool",
+ },
+ "dynamic_application": {
+ "options": {
+ "any": {"type": "bool"},
+ "names": {
+ "elements": "str",
+ "type": "list",
+ },
+ "none": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "from_zone": {
+ "options": {
+ "any": {"type": "bool"},
+ "junos_host": {"type": "bool"},
+ "names": {
+ "elements": "str",
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "source_address": {
+ "options": {
+ "addresses": {
+ "elements": "str",
+ "type": "list",
+ },
+ "any": {"type": "bool"},
+ "any_ipv4": {"type": "bool"},
+ "any_ipv6": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "source_address_excluded": {
+ "type": "bool",
+ },
+ "source_end_user_profile": {
+ "type": "str",
+ },
+ "source_identity": {
+ "options": {
+ "any": {"type": "bool"},
+ "authenticated_user": {
+ "type": "bool",
+ },
+ "names": {
+ "elements": "str",
+ "type": "list",
+ },
+ "unauthenticated_user": {
+ "type": "bool",
+ },
+ "unknown_user": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "to_zone": {
+ "options": {
+ "any": {"type": "bool"},
+ "junos_host": {"type": "bool"},
+ "names": {
+ "elements": "str",
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "url_category": {
+ "options": {
+ "any": {"type": "bool"},
+ "names": {
+ "elements": "str",
+ "type": "list",
+ },
+ "none": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "name": {"type": "str"},
+ "scheduler_name": {"type": "str"},
+ "then": {
+ "options": {
+ "count": {"type": "bool"},
+ "deny": {"type": "bool"},
+ "log": {
+ "options": {
+ "session_close": {
+ "type": "bool",
+ },
+ "session_init": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "permit": {
+ "options": {
+ "application_services": {
+ "options": {
+ "advanced_anti_malware_policy": {
+ "type": "str",
+ },
+ "application_firewalls": {
+ "elements": "dict",
+ "options": {
+ "rule_set": {
+ "type": "str",
+ },
+ },
+ "type": "list",
+ },
+ "application_traffic_control_rule_set": {
+ "type": "str",
+ },
+ "gprs_gtp_profile": {
+ "type": "str",
+ },
+ "gprs_sctp_profile": {
+ "type": "str",
+ },
+ "icap_redirect": {
+ "type": "str",
+ },
+ "idp": {
+ "type": "bool",
+ },
+ "idp_policy": {
+ "type": "str",
+ },
+ "packet_capture": {
+ "type": "bool",
+ },
+ "redirect_wx": {
+ "type": "bool",
+ },
+ "reverse_redirect_wx": {
+ "type": "bool",
+ },
+ "security_intelligence": {
+ "options": {
+ "add_destination_identity_to_feed": {
+ "type": "str",
+ },
+ "add_destination_ip_to_feed": {
+ "type": "str",
+ },
+ "add_source_identity_to_feed": {
+ "type": "str",
+ },
+ "add_source_ip_to_feed": {
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "security_intelligence_policy": {
+ "type": "str",
+ },
+ "ssl_proxy": {
+ "options": {
+ "enable": {
+ "type": "bool",
+ },
+ "profile_name": {
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "uac_policy": {
+ "options": {
+ "captive_portal": {
+ "type": "str",
+ },
+ "enable": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "utm_policy": {
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "destination_address": {
+ "choices": [
+ "drop-translated",
+ "drop-untranslated",
+ ],
+ "type": "str",
+ },
+ "firewall_authentication": {
+ "options": {
+ "pass_through": {
+ "no_log": True,
+ "options": {
+ "access_profile": {
+ "type": "str",
+ },
+ "auth_only_browser": {
+ "type": "bool",
+ },
+ "auth_user_agent": {
+ "type": "str",
+ },
+ "client_match": {
+ "type": "str",
+ },
+ "ssl_termination_profile": {
+ "type": "str",
+ },
+ "web_redirect": {
+ "type": "bool",
+ },
+ "web_redirect_to_https": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "push_to_identity_management": {
+ "type": "bool",
+ },
+ "user_firewall": {
+ "options": {
+ "access_profile": {
+ "type": "str",
+ },
+ "auth_only_browser": {
+ "type": "bool",
+ },
+ "auth_user_agent": {
+ "type": "str",
+ },
+ "domain": {
+ "type": "str",
+ },
+ "ssl_termination_profile": {
+ "type": "str",
+ },
+ "web_redirect": {
+ "type": "bool",
+ },
+ "web_redirect_to_https": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "web_authentication": {
+ "elements": "str",
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "tcp_options": {
+ "options": {
+ "initial_tcp_mss": {
+ "type": "int",
+ },
+ "reverse_tcp_mss": {
+ "type": "int",
+ },
+ "sequence_check_required": {
+ "type": "bool",
+ },
+ "syn_check_required": {
+ "type": "bool",
+ },
+ "window_scale": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "tunnel": {
+ "options": {
+ "ipsec_vpn": {
+ "type": "str",
+ },
+ "pair_policy": {
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "reject": {
+ "options": {
+ "enable": {"type": "bool"},
+ "profile": {"type": "str"},
+ "ssl_proxy": {
+ "options": {
+ "enable": {
+ "type": "bool",
+ },
+ "profile_name": {
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "gathered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies_global/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies_global/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies_global/security_policies_global.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies_global/security_policies_global.py
new file mode 100644
index 000000000..cac6c3466
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_policies_global/security_policies_global.py
@@ -0,0 +1,129 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2022 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_security_policies_global module
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Security_policies_globalArgs(object): # pylint: disable=R0903
+ """The arg spec for the junos_security_policies_global module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "options": {
+ "default_policy": {
+ "choices": ["deny-all", "permit-all"],
+ "type": "str",
+ },
+ "policy_rematch": {
+ "options": {
+ "enable": {"type": "bool"},
+ "extensive": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "policy_stats": {
+ "options": {
+ "enable": {"type": "bool"},
+ "system_wide": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "pre_id_default_policy_action": {
+ "options": {
+ "log": {
+ "options": {
+ "session_close": {"type": "bool"},
+ "session_init": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "session_timeout": {
+ "options": {
+ "icmp": {"type": "int"},
+ "icmp6": {"type": "int"},
+ "ospf": {"type": "int"},
+ "others": {"type": "int"},
+ "tcp": {"type": "int"},
+ "udp": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "traceoptions": {
+ "options": {
+ "file": {
+ "options": {
+ "files": {"type": "int"},
+ "match": {"type": "str"},
+ "no_world_readable": {"type": "bool"},
+ "size": {"type": "str"},
+ "world_readable": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "flag": {
+ "choices": [
+ "all",
+ "configuration",
+ "compilation",
+ "ipc",
+ "lookup",
+ "routing-socket",
+ "rules",
+ ],
+ "type": "str",
+ },
+ "no_remote_trace": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "gathered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_zones/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_zones/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_zones/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_zones/security_zones.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_zones/security_zones.py
new file mode 100644
index 000000000..9d9bc4830
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/security_zones/security_zones.py
@@ -0,0 +1,192 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2022 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_security_zones module
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Security_zonesArgs(object): # pylint: disable=R0903
+ """The arg spec for the junos_security_zones module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "options": {
+ "functional_zone_management": {
+ "options": {
+ "description": {"type": "str"},
+ "host_inbound_traffic": {
+ "options": {
+ "protocols": {
+ "elements": "dict",
+ "options": {
+ "except": {"type": "bool"},
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "system_services": {
+ "elements": "dict",
+ "options": {
+ "except": {"type": "bool"},
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "interfaces": {"elements": "str", "type": "list"},
+ "screen": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "zones": {
+ "elements": "dict",
+ "options": {
+ "address_book": {
+ "options": {
+ "address_sets": {
+ "elements": "dict",
+ "options": {
+ "address_sets": {
+ "elements": "str",
+ "type": "list",
+ },
+ "addresses": {
+ "elements": "str",
+ "type": "list",
+ },
+ "description": {"type": "str"},
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "addresses": {
+ "elements": "dict",
+ "options": {
+ "description": {"type": "str"},
+ "dns_name": {
+ "options": {
+ "ipv4_only": {"type": "bool"},
+ "ipv6_only": {"type": "bool"},
+ "name": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "ip_prefix": {"type": "str"},
+ "name": {"type": "str"},
+ "range_address": {
+ "options": {
+ "from": {"type": "str"},
+ "to": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "wildcard_address": {"type": "str"},
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "advance_policy_based_routing_profile": {
+ "type": "str",
+ },
+ "advanced_connection_tracking": {
+ "options": {
+ "mode": {
+ "choices": [
+ "allow-any-host",
+ "allow-target-host",
+ "allow-target-host-port",
+ ],
+ "type": "str",
+ },
+ "timeout": {"type": "int"},
+ "track_all_policies_to_this_zone": {
+ "type": "bool",
+ },
+ },
+ "type": "dict",
+ },
+ "application_tracking": {"type": "bool"},
+ "description": {"type": "str"},
+ "enable_reverse_reroute": {"type": "bool"},
+ "host_inbound_traffic": {
+ "options": {
+ "protocols": {
+ "elements": "dict",
+ "options": {
+ "except": {"type": "bool"},
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "system_services": {
+ "elements": "dict",
+ "options": {
+ "except": {"type": "bool"},
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "interfaces": {"elements": "str", "type": "list"},
+ "name": {"type": "str"},
+ "screen": {"type": "str"},
+ "source_identity_log": {"type": "bool"},
+ "tcp_rst": {"type": "bool"},
+ "unidirectional_session_refreshing": {"type": "bool"},
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "gathered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/snmp_server/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/snmp_server/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/snmp_server/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/snmp_server/snmp_server.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/snmp_server/snmp_server.py
new file mode 100644
index 000000000..d334f4ecc
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/snmp_server/snmp_server.py
@@ -0,0 +1,700 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 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_snmp_server module
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Snmp_serverArgs(object): # pylint: disable=R0903
+ """The arg spec for the junos_snmp_server module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "options": {
+ "arp": {
+ "options": {
+ "host_name_resolution": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "client_lists": {
+ "elements": "dict",
+ "options": {
+ "addresses": {
+ "elements": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "restrict": {"type": "bool"},
+ },
+ "type": "list",
+ },
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "communities": {
+ "elements": "dict",
+ "options": {
+ "authorization": {
+ "choices": ["read-only", "read-write"],
+ "type": "str",
+ },
+ "client_list_name": {"type": "str"},
+ "clients": {
+ "elements": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "restrict": {"type": "bool"},
+ },
+ "type": "list",
+ },
+ "logical_system": {"elements": "str", "type": "list"},
+ "name": {"type": "str"},
+ "routing_instances": {
+ "elements": "dict",
+ "options": {
+ "client_list_name": {"type": "str"},
+ "clients": {
+ "elements": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "restrict": {"type": "bool"},
+ },
+ "type": "list",
+ },
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "view": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "contact": {"type": "str"},
+ "customization": {
+ "options": {"ether_stats_ifd_only": {"type": "bool"}},
+ "type": "dict",
+ },
+ "description": {"type": "str"},
+ "engine_id": {
+ "options": {
+ "local": {"type": "str"},
+ "use_default_ip_address": {"type": "bool"},
+ "use_mac_address": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "filter_duplicates": {"type": "bool"},
+ "filter_interfaces": {
+ "options": {
+ "all_internal_interfaces": {"type": "bool"},
+ "interfaces": {"elements": "str", "type": "list"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "health_monitor": {
+ "options": {
+ "falling_threshold": {"type": "int"},
+ "idp": {"type": "bool"},
+ "interval": {"type": "int"},
+ "rising_threshold": {"type": "int"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "if_count_with_filter_interfaces": {"type": "bool"},
+ "interfaces": {"elements": "str", "type": "list"},
+ "location": {"type": "str"},
+ "logical_system_trap_filter": {"type": "bool"},
+ "name": {"type": "str"},
+ "nonvolatile": {
+ "options": {"commit_delay": {"type": "int"}},
+ "type": "dict",
+ },
+ "proxies": {
+ "elements": "dict",
+ "options": {
+ "device_name": {"type": "str"},
+ "logical_system": {"elements": "str", "type": "list"},
+ "name": {"type": "str"},
+ "routing_instances": {
+ "elements": "dict",
+ "options": {
+ "client_list_name": {"type": "str"},
+ "clients": {
+ "elements": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "restrict": {"type": "bool"},
+ },
+ "type": "list",
+ },
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "version_v1": {
+ "options": {
+ "no_default_comm_to_v3_config": {
+ "type": "bool",
+ },
+ "snmp_community": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "version_v2c": {
+ "options": {
+ "no_default_comm_to_v3_config": {
+ "type": "bool",
+ },
+ "snmp_community": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "version_v3": {
+ "options": {
+ "context": {"type": "bool"},
+ "security_name": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "list",
+ },
+ "rmon": {
+ "options": {
+ "alarms": {
+ "elements": "dict",
+ "options": {
+ "description": {"type": "str"},
+ "falling_event_index": {"type": "int"},
+ "falling_threshold": {"type": "int"},
+ "falling_threshold_interval": {"type": "int"},
+ "id": {"type": "str"},
+ "interval": {"type": "int"},
+ "request_type": {
+ "choices": [
+ "get-next-request",
+ "get-request",
+ "walk-request",
+ ],
+ "type": "str",
+ },
+ "rising_event_index": {"type": "int"},
+ "rising_threshold": {"type": "int"},
+ "sample_type": {
+ "choices": [
+ "absolute-value",
+ "delta-value",
+ ],
+ "type": "str",
+ },
+ "startup_alarm": {
+ "choices": [
+ "falling-alarm",
+ "rising-alarm",
+ "rising-or-falling-alarm",
+ ],
+ "type": "str",
+ },
+ "syslog_subtag": {"type": "str"},
+ "variable": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "events": {
+ "elements": "dict",
+ "options": {
+ "community": {"type": "str"},
+ "description": {"type": "str"},
+ "id": {"type": "int"},
+ "type": {
+ "choices": [
+ "log",
+ "log-and-trap",
+ "none",
+ "snmptrap",
+ ],
+ "type": "str",
+ },
+ },
+ "type": "list",
+ },
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "routing_instance_access": {
+ "options": {
+ "access_lists": {"elements": "str", "type": "list"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "snmp_v3": {
+ "options": {
+ "notify": {
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "tag": {"type": "str"},
+ "type": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "notify_filter": {
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "oids": {
+ "elements": "dict",
+ "options": {
+ "exclude": {"type": "bool"},
+ "include": {"type": "bool"},
+ "oid": {"type": "str"},
+ },
+ "type": "list",
+ },
+ },
+ "type": "list",
+ },
+ "snmp_community": {
+ "elements": "dict",
+ "options": {
+ "community_index": {"type": "str"},
+ "community_name": {"type": "str"},
+ "context": {"type": "str"},
+ "security_name": {"type": "str"},
+ "tag": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "target_addresses": {
+ "elements": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "address_mask": {"type": "str"},
+ "logical_system": {"type": "str"},
+ "name": {"type": "str"},
+ "port": {"type": "int"},
+ "retry_count": {"type": "int"},
+ "routing_instance": {"type": "str"},
+ "tag_list": {"type": "str"},
+ "target_parameters": {"type": "str"},
+ "timeout": {"type": "int"},
+ },
+ "type": "list",
+ },
+ "target_parameters": {
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "notify_filter": {"type": "str"},
+ "parameters": {
+ "options": {
+ "message_processing_model": {
+ "choices": ["v1", "v2c", "v3"],
+ "type": "str",
+ },
+ "security_level": {
+ "choices": [
+ "authentication",
+ "none",
+ "privacy",
+ ],
+ "type": "str",
+ },
+ "security_model": {
+ "choices": ["usm", "v1", "v2c"],
+ "type": "str",
+ },
+ "security_name": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "list",
+ },
+ "usm": {
+ "options": {
+ "local_engine": {
+ "options": {
+ "users": {
+ "elements": "dict",
+ "options": {
+ "authentication_md5": {
+ "options": {
+ "key": {
+ "type": "str",
+ "no_log": False,
+ },
+ "password": {
+ "type": "str",
+ "no_log": False,
+ },
+ },
+ "type": "dict",
+ },
+ "authentication_none": {
+ "type": "bool",
+ },
+ "authentication_sha": {
+ "options": {
+ "key": {
+ "type": "str",
+ "no_log": False,
+ },
+ "password": {
+ "type": "str",
+ "no_log": False,
+ },
+ },
+ "type": "dict",
+ },
+ "name": {"type": "str"},
+ "privacy_3des": {
+ "options": {
+ "key": {
+ "type": "str",
+ "no_log": False,
+ },
+ "password": {
+ "type": "str",
+ "no_log": False,
+ },
+ },
+ "type": "dict",
+ },
+ "privacy_aes128": {
+ "options": {
+ "key": {
+ "type": "str",
+ "no_log": False,
+ },
+ "password": {
+ "type": "str",
+ "no_log": False,
+ },
+ },
+ "type": "dict",
+ },
+ "privacy_des": {
+ "options": {
+ "key": {
+ "type": "str",
+ "no_log": False,
+ },
+ "password": {
+ "type": "str",
+ "no_log": False,
+ },
+ },
+ "type": "dict",
+ },
+ "privacy_none": {
+ "type": "bool",
+ },
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "remote_engine": {
+ "elements": "dict",
+ "options": {
+ "id": {"type": "str"},
+ "users": {
+ "elements": "dict",
+ "options": {
+ "authentication_md5": {
+ "options": {
+ "key": {
+ "type": "str",
+ "no_log": False,
+ },
+ "password": {
+ "type": "str",
+ "no_log": False,
+ },
+ },
+ "type": "dict",
+ },
+ "authentication_none": {
+ "type": "bool",
+ },
+ "authentication_sha": {
+ "options": {
+ "key": {
+ "type": "str",
+ "no_log": False,
+ },
+ "password": {
+ "type": "str",
+ "no_log": False,
+ },
+ },
+ "type": "dict",
+ },
+ "name": {"type": "str"},
+ "privacy_3des": {
+ "options": {
+ "key": {
+ "type": "str",
+ "no_log": False,
+ },
+ "password": {
+ "type": "str",
+ "no_log": False,
+ },
+ },
+ "type": "dict",
+ },
+ "privacy_aes128": {
+ "options": {
+ "key": {
+ "type": "str",
+ "no_log": False,
+ },
+ "password": {
+ "type": "str",
+ "no_log": False,
+ },
+ },
+ "type": "dict",
+ },
+ "privacy_des": {
+ "options": {
+ "key": {
+ "type": "str",
+ "no_log": False,
+ },
+ "password": {
+ "type": "str",
+ "no_log": False,
+ },
+ },
+ "type": "dict",
+ },
+ "privacy_none": {
+ "type": "bool",
+ },
+ },
+ "type": "list",
+ },
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "subagent": {
+ "options": {
+ "tcp": {
+ "options": {
+ "routing_instances_default": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "traceoptions": {
+ "options": {
+ "file": {
+ "options": {
+ "files": {"type": "int"},
+ "match": {"type": "str"},
+ "no_world_readable": {"type": "bool"},
+ "size": {"type": "int"},
+ "world_readable": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "flag": {
+ "options": {
+ "all": {"type": "bool"},
+ "general": {"type": "bool"},
+ "interface_stats": {"type": "bool"},
+ "nonvolatile_sets": {"type": "bool"},
+ "pdu": {"type": "bool"},
+ "protocol_timeouts": {"type": "bool"},
+ "routing_socket": {"type": "bool"},
+ "subagent": {"type": "bool"},
+ "timer": {"type": "bool"},
+ "varbind_error": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "memory_trace": {
+ "options": {
+ "set": {"type": "bool"},
+ "size": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "no_remote_trace": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "trap_groups": {
+ "elements": "dict",
+ "options": {
+ "categories": {
+ "options": {
+ "authentication": {"type": "bool"},
+ "chassis": {"type": "bool"},
+ "chassis_cluster": {"type": "bool"},
+ "configuration": {"type": "bool"},
+ "dot3oam_events": {"type": "bool"},
+ "link": {"type": "bool"},
+ "otn_alarms": {
+ "options": {
+ "oc_lof": {"type": "bool"},
+ "oc_lom": {"type": "bool"},
+ "oc_los": {"type": "bool"},
+ "odu_ais": {"type": "bool"},
+ "odu_bbe_threshold": {"type": "bool"},
+ "odu_bdi": {"type": "bool"},
+ "odu_bdodu_es_threshold": {
+ "type": "bool",
+ },
+ "odu_lck": {"type": "bool"},
+ "odu_oci": {"type": "bool"},
+ "odu_rx_aps_change": {"type": "bool"},
+ "odu_sd": {"type": "bool"},
+ "odu_ses_threshold": {"type": "bool"},
+ "odu_sf": {"type": "bool"},
+ "odu_ttim": {"type": "bool"},
+ "odu_uas_threshold": {"type": "bool"},
+ "opu_ptm": {"type": "bool"},
+ "otu_ais": {"type": "bool"},
+ "otu_bbe_threshold": {"type": "bool"},
+ "otu_bdi": {"type": "bool"},
+ "otu_es_threshold": {"type": "bool"},
+ "otu_fec_deg": {"type": "bool"},
+ "otu_fec_exe": {"type": "bool"},
+ "otu_iae": {"type": "bool"},
+ "otu_sd": {"type": "bool"},
+ "otu_ses_threshold": {"type": "bool"},
+ "otu_sf": {"type": "bool"},
+ "otu_ttim": {"type": "bool"},
+ "otu_uas_threshold": {"type": "bool"},
+ "set": {"type": "bool"},
+ "wavelength_lock": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "remote_operations": {"type": "bool"},
+ "rmon_alarm": {"type": "bool"},
+ "routing": {"type": "bool"},
+ "services": {"type": "bool"},
+ "startup": {"type": "bool"},
+ "vrrp_events": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "destination_port": {"type": "int"},
+ "logical_system": {"elements": "str", "type": "list"},
+ "name": {"type": "str"},
+ "routing_instance": {"type": "str"},
+ "targets": {"elements": "str", "type": "list"},
+ "version": {
+ "choices": ["all", "v1", "v2"],
+ "type": "str",
+ },
+ },
+ "type": "list",
+ },
+ "trap_options": {
+ "options": {
+ "agent_address": {
+ "options": {
+ "outgoing_interface": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "context_oid": {"type": "bool"},
+ "enterprise_oid": {"type": "bool"},
+ "logical_system": {"elements": "str", "type": "list"},
+ "routing_instance": {"type": "str"},
+ "set": {"type": "bool"},
+ "source_address": {
+ "options": {
+ "address": {"type": "str"},
+ "lowest_loopback": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "views": {
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "oids": {
+ "elements": "dict",
+ "options": {
+ "exclude": {"type": "bool"},
+ "include": {"type": "bool"},
+ "oid": {"type": "str"},
+ },
+ "type": "list",
+ },
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "deleted",
+ "overridden",
+ "parsed",
+ "gathered",
+ "rendered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/static_routes/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/static_routes/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/static_routes/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/static_routes/static_routes.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/static_routes/static_routes.py
new file mode 100644
index 000000000..34c01e8a5
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/static_routes/static_routes.py
@@ -0,0 +1,90 @@
+#
+# -*- 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",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/vlans/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/vlans/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/vlans/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/vlans/vlans.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/vlans/vlans.py
new file mode 100644
index 000000000..41eaa8d5c
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/argspec/vlans/vlans.py
@@ -0,0 +1,65 @@
+#
+# -*- 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"},
+ "l3_interface": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acl_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acl_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acl_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acl_interfaces/acl_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acl_interfaces/acl_interfaces.py
new file mode 100644
index 000000000..67f5fe309
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acl_interfaces/acl_interfaces.py
@@ -0,0 +1,260 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos_acl_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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Acl_interfaces(ConfigBase):
+ """
+ The junos_acl_interfaces class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["acl_interfaces"]
+
+ def __init__(self, module):
+ super(Acl_interfaces, self).__init__(module)
+
+ def get_acl_interfaces_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ acl_interfaces_facts = facts["ansible_network_resources"].get(
+ "junos_acl_interfaces",
+ )
+ if not acl_interfaces_facts:
+ return []
+ return acl_interfaces_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ state = self._module.params["state"]
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_acl_interfaces_facts = self.get_acl_interfaces_facts()
+ else:
+ existing_acl_interfaces_facts = []
+ if state == "gathered":
+ existing_acl_interfaces_facts = self.get_acl_interfaces_facts()
+ result["gathered"] = existing_acl_interfaces_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_acl_interfaces_facts(
+ data=running_config,
+ )
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_acl_interfaces_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ config_xmls = self.set_config(existing_acl_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_acl_interfaces_facts = self.get_acl_interfaces_facts()
+
+ result["before"] = existing_acl_interfaces_facts
+ if result["changed"]:
+ result["after"] = changed_acl_interfaces_facts
+
+ result["warnings"] = warnings
+ return result
+
+ def set_config(self, existing_acl_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_acl_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 in ("merged", "replaced", "overridden", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ 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 command generator when state is replaced
+
+ :rtype: A list
+ :returns: the xml necessary to migrate the current configuration
+ to the desired configuration
+ """
+ acl_intf_xml = []
+ acl_intf_xml.extend(self._state_deleted(want, have))
+ acl_intf_xml.extend(self._state_merged(want, have))
+ return acl_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
+ """
+ acl_intf_xml = []
+ acl_intf_xml.extend(self._state_deleted(have, have))
+ acl_intf_xml.extend(self._state_merged(want, have))
+ return acl_intf_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
+ """
+ acl_intf_xml = []
+ delete = {"delete": "delete"}
+
+ if not want:
+ want = have
+
+ acl_intf_xml = self._state_merged(want, have, delete=delete)
+ return acl_intf_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
+ """
+
+ acl_intf_xml = []
+
+ for config in want:
+ root_node, unit_node = self._get_common_xml_node(config["name"])
+ build_child_xml_node(unit_node, "name", "0")
+ family_node = build_child_xml_node(unit_node, "family")
+ for acl_filter in config["access_groups"]:
+ inet_family = "inet"
+ if acl_filter["afi"] == "ipv6":
+ inet_family = "inet6"
+ inet_node = build_child_xml_node(family_node, inet_family)
+ if acl_filter.get("acls"):
+ filter_node = build_child_xml_node(inet_node, "filter")
+ for acl in acl_filter["acls"]:
+ acl_node = None
+ if acl["direction"] == "in":
+ acl_node = build_child_xml_node(
+ filter_node,
+ "input-list",
+ acl["name"],
+ )
+ else:
+ acl_node = build_child_xml_node(
+ filter_node,
+ "output-list",
+ acl["name"],
+ )
+ if delete:
+ acl_node.attrib.update(delete)
+ elif delete:
+ build_child_xml_node(inet_node, "filter", None, delete)
+ acl_intf_xml.append(root_node)
+ return acl_intf_xml
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acls/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acls/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acls/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acls/acls.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acls/acls.py
new file mode 100644
index 000000000..540ffe271
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/acls/acls.py
@@ -0,0 +1,441 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos_acls 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Acls(ConfigBase):
+ """
+ The junos_acls class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["acls"]
+
+ def __init__(self, module):
+ super(Acls, self).__init__(module)
+
+ def get_acls_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ acls_facts = facts["ansible_network_resources"].get("junos_acls")
+ if not acls_facts:
+ return []
+ return acls_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ state = self._module.params["state"]
+
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_acls_facts = self.get_acls_facts()
+ else:
+ existing_acls_facts = {}
+ if state == "gathered":
+ existing_acls_facts = self.get_acls_facts()
+ result["gathered"] = existing_acls_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_acls_facts(data=running_config)
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_acls_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ diff = None
+ config_xmls = self.set_config(existing_acls_facts)
+ with locked_config(self._module):
+ for config_xml in 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_acls_facts = self.get_acls_facts()
+
+ result["before"] = existing_acls_facts
+ if result["changed"]:
+ result["after"] = changed_acls_facts
+
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_acls_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_acls_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("firewall")
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "rendered", "overridden") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ config_xmls = []
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ 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
+ """
+ acls_xml = []
+ acls_xml.extend(self._state_deleted(want, have))
+ acls_xml.extend(self._state_merged(want, have))
+ return acls_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
+ """
+ acls_xml = []
+ acls_xml.extend(self._state_deleted(have, have))
+ acls_xml.extend(self._state_merged(want, have))
+ return acls_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
+ """
+ acls_xml = []
+ family_node = build_root_xml_node("family")
+ delete = dict(delete="delete")
+
+ if not want:
+ want = have
+
+ for config in want:
+ try:
+ family = "inet6" if config.get("afi") == "ipv6" else "inet"
+ except KeyError:
+ family = "inet"
+ inet_node = build_child_xml_node(family_node, family)
+
+ # Look deeply into have to match replace correctly
+ existing_acls = []
+ for conf in have:
+ if conf.get("afi") == config.get("afi"):
+ existing_acls.extend(conf["acls"] or [])
+ acl_names = [acl["name"] for acl in existing_acls]
+
+ if not config["acls"]:
+ inet_node.attrib.update(delete)
+ continue
+
+ for acl in config["acls"]:
+ if acl["name"] not in acl_names:
+ continue
+
+ filter_node = build_child_xml_node(inet_node, "filter")
+ build_child_xml_node(filter_node, "name", acl["name"])
+ if not acl.get("aces"):
+ filter_node.attrib.update(delete)
+ continue
+
+ for ace in acl["aces"]:
+ # if ace["name"] not in ace_names:
+ term_node = build_child_xml_node(filter_node, "term")
+ build_child_xml_node(term_node, "name", ace["name"])
+ term_node.attrib.update(delete)
+
+ acls_xml.append(family_node)
+ return acls_xml
+
+ def _state_merged(self, want, have):
+ """The command generator when state is merged
+
+ :rtype: A list
+ :returns: the xml necessary to migrate the current configuration
+ to the desired configuration
+ """
+ acls_xml = []
+ family_node = build_root_xml_node("family")
+ for config in want:
+ try:
+ family = "inet6" if config.pop("afi") == "ipv6" else "inet"
+ except KeyError:
+ family = "inet"
+ inet_node = build_child_xml_node(family_node, family)
+
+ for acl in config.get("acls") or []:
+ filter_node = build_child_xml_node(inet_node, "filter")
+ build_child_xml_node(filter_node, "name", acl["name"])
+ for ace in acl.get("aces") or []:
+ term_node = build_child_xml_node(filter_node, "term")
+ build_child_xml_node(term_node, "name", ace["name"])
+
+ if ace.get("source") or ace.get("destination") or ace.get("protocol"):
+ from_node = build_child_xml_node(term_node, "from")
+ for direction in ("source", "destination"):
+ if ace.get(direction):
+ if ace[direction].get("address"):
+ addresses = ace[direction]["address"]
+ if not isinstance(addresses, list):
+ addresses = [addresses]
+ for address in addresses:
+ build_child_xml_node(
+ from_node,
+ "{0}-address".format(direction),
+ address,
+ )
+ if ace[direction].get("prefix_list"):
+ for prefix in ace[direction].get(
+ "prefix_list",
+ ):
+ build_child_xml_node(
+ from_node,
+ "{0}-prefix-list".format(
+ direction,
+ ),
+ prefix["name"],
+ )
+ if ace[direction].get("port_protocol"):
+ if "eq" in ace[direction]["port_protocol"]:
+ build_child_xml_node(
+ from_node,
+ "{0}-port".format(direction),
+ ace[direction]["port_protocol"]["eq"],
+ )
+ elif "range" in ace[direction]["port_protocol"]:
+ ports = "{0}-{1}".format(
+ ace[direction]["port_protocol"]["start"],
+ ace[direction]["port_protocol"]["end"],
+ )
+ build_child_xml_node(
+ from_node,
+ "{0}-port".format(direction),
+ ports,
+ )
+ if ace.get("protocol"):
+ build_child_xml_node(
+ from_node,
+ "protocol",
+ ace["protocol"],
+ )
+ if ace.get("protocol_options"):
+ if ace["protocol_options"].get("icmp"):
+ icmp_code = build_child_xml_node(
+ from_node,
+ "icmp-code",
+ )
+ icmp_type = build_child_xml_node(
+ from_node,
+ "icmp-type",
+ )
+ icmp = ace["protocol_options"]["icmp"]
+ if "dod_host_prohibited" in icmp:
+ build_child_xml_node(
+ icmp_code,
+ "destination-host-prohibited",
+ )
+ if "dod_net_prohibited" in icmp:
+ build_child_xml_node(
+ icmp_code,
+ "destination-network-prohibited",
+ )
+ if "echo" in icmp:
+ build_child_xml_node(
+ icmp_type,
+ "echo-request",
+ )
+ if "echo_reply" in icmp:
+ build_child_xml_node(
+ icmp_type,
+ "echo-reply",
+ )
+ if "host_tos_unreachable" in icmp:
+ build_child_xml_node(
+ icmp_code,
+ "host-unreachable-for-tos",
+ )
+ if "host_redirect" in icmp:
+ build_child_xml_node(
+ icmp_code,
+ "redirect-for-host",
+ )
+ if "host_tos_redirect" in icmp:
+ build_child_xml_node(
+ icmp_code,
+ "redirect-for-host-and-tos",
+ )
+ if "host_unknown" in icmp:
+ build_child_xml_node(
+ icmp_code,
+ "destination-host-unknown",
+ )
+ if "host_unreachable" in icmp:
+ build_child_xml_node(
+ icmp_code,
+ "host-unreachable",
+ )
+ if "net_redirect" in icmp:
+ build_child_xml_node(
+ icmp_code,
+ "redirect-for-network",
+ )
+ if "net_tos_redirect" in icmp:
+ build_child_xml_node(
+ icmp_code,
+ "redirect-for-tos-and-net",
+ )
+ if "network_unknown" in icmp:
+ build_child_xml_node(
+ icmp_code,
+ "destination-network-unknown",
+ )
+ if "port_unreachable" in icmp:
+ build_child_xml_node(
+ icmp_code,
+ "port-unreachable",
+ )
+ if "protocol_unreachable" in icmp:
+ build_child_xml_node(
+ icmp_code,
+ "protocol-unreachable",
+ )
+ if "reassembly_timeout" in icmp:
+ build_child_xml_node(
+ icmp_code,
+ "ttl-eq-zero-during-reassembly",
+ )
+ if "redirect" in icmp:
+ build_child_xml_node(icmp_type, "redirect")
+ if "router_advertisement" in icmp:
+ build_child_xml_node(
+ icmp_type,
+ "router-advertisement",
+ )
+ if "router_solicitation" in icmp:
+ build_child_xml_node(
+ icmp_type,
+ "router-solicit",
+ )
+ if "source_route_failed" in icmp:
+ build_child_xml_node(
+ icmp_code,
+ "source-route-failed",
+ )
+ if "time_exceeded" in icmp:
+ build_child_xml_node(
+ icmp_type,
+ "time-exceeded",
+ )
+ if "ttl_exceeded" in icmp:
+ build_child_xml_node(
+ icmp_code,
+ "ttl-eq-zero-during-transit",
+ )
+ if ace.get("grant"):
+ then_node = build_child_xml_node(term_node, "then")
+ if ace["grant"] == "permit":
+ build_child_xml_node(then_node, "accept")
+ if ace["grant"] == "deny":
+ build_child_xml_node(then_node, "discard")
+
+ acls_xml.append(family_node)
+ return acls_xml
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_address_family/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_address_family/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_address_family/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_address_family/bgp_address_family.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_address_family/bgp_address_family.py
new file mode 100644
index 000000000..064753ffb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_address_family/bgp_address_family.py
@@ -0,0 +1,917 @@
+#
+# -*- 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_bgp_address_family 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_empties,
+ to_list,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Bgp_address_family(ConfigBase):
+ """
+ The junos_bgp_address_family class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["bgp_address_family"]
+
+ def __init__(self, module):
+ super(Bgp_address_family, self).__init__(module)
+
+ def get_bgp_address_family_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ bgp_facts = facts["ansible_network_resources"].get(
+ "bgp_address_family",
+ )
+ if not bgp_facts:
+ return {}
+ return bgp_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ state = self._module.params["state"]
+
+ warnings = list()
+
+ if self.state in self.ACTION_STATES or self.state == "purged":
+ existing_bgp_address_family_facts = self.get_bgp_address_family_facts()
+ else:
+ existing_bgp_address_family_facts = {}
+ if state == "gathered":
+ existing_bgp_address_family_facts = self.get_bgp_address_family_facts()
+ result["gathered"] = existing_bgp_address_family_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_bgp_address_family_facts(
+ data=running_config,
+ )
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_bgp_address_family_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ diff = None
+ config_xmls = self.set_config(existing_bgp_address_family_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_bgp_address_family_facts = self.get_bgp_address_family_facts()
+
+ result["before"] = existing_bgp_address_family_facts
+ if result["changed"]:
+ result["after"] = changed_bgp_address_family_facts
+
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_bgp_address_family_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_bgp_address_family_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
+ """
+ self.autonomous_system = None
+ self.root = build_root_xml_node("configuration")
+ self.protocols = build_child_xml_node(self.root, "protocols")
+ self.bgp = build_child_xml_node(self.protocols, "bgp")
+ self.routing_options = build_child_xml_node(
+ self.root,
+ "routing-options",
+ )
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "rendered", "overridden") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ config_xmls = []
+ if state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state == "purged":
+ config_xmls = self._state_purged(want, have)
+ elif state in ("merged", "rendered"):
+ config_xmls = self._state_merged(want, have)
+ elif state == "replaced":
+ config_xmls = self._state_replaced(want, have)
+ elif state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+
+ for xml in config_xmls:
+ self.bgp.append(xml)
+ cfg_lst = []
+
+ if config_xmls:
+ for xml in self.root.getchildren():
+ xml = tostring(xml)
+ cfg_lst.append(xml)
+ return cfg_lst
+
+ 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
+ """
+ bgp_xml = []
+ bgp_xml.extend(self._state_deleted(want, have))
+ bgp_xml.extend(self._state_merged(want, have))
+
+ return bgp_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
+ """
+ family_xml = []
+
+ family_root = build_root_xml_node("family")
+
+ want = remove_empties(want)
+
+ # Generate xml node for autonomous-system
+ if want.get("as_number"):
+ build_child_xml_node(
+ self.routing_options,
+ "autonomous-system",
+ want.get("as_number"),
+ )
+ w_af_list = want.get("address_family")
+ # render global address family attribute commands
+ self.render_af(w_af_list, family_root)
+
+ # render commands for group address family attribute commands
+ if "groups" in want.keys():
+ groups = want.get("groups")
+ for group in groups:
+ groups_node = build_root_xml_node("group")
+ build_child_xml_node(groups_node, "name", group["name"])
+ g_family_root = build_child_xml_node(groups_node, "family")
+ w_gaf_list = group.get("address_family")
+ self.render_af(w_gaf_list, g_family_root)
+
+ # render neighbor address-family commands
+ if "neighbors" in group.keys():
+ neighbors = group.get("neighbors")
+ for neighbor in neighbors:
+ neighbors_node = build_child_xml_node(
+ groups_node,
+ "neighbor",
+ )
+ build_child_xml_node(
+ neighbors_node,
+ "name",
+ neighbor["neighbor_address"],
+ )
+ n_family_root = build_child_xml_node(
+ neighbors_node,
+ "family",
+ )
+ w_naf_list = neighbor.get("address_family")
+ self.render_af(w_naf_list, n_family_root)
+
+ family_xml.append(groups_node)
+
+ family_xml.append(family_root)
+
+ return family_xml
+
+ def render_af(self, w_af_list, family_root):
+ if w_af_list:
+ for waf in w_af_list:
+ # Add the nlri node
+ nlri_node = build_child_xml_node(family_root, waf["afi"])
+ # Read nlri_types list
+ nlri_types = waf.get("af_type")
+ for type in nlri_types:
+ # Add the node for nlri type
+ type_node = build_child_xml_node(nlri_node, type["type"])
+ # Add node for accepted-prefix-limit
+ if "accepted_prefix_limit" in type.keys():
+ apl = type.get("accepted_prefix_limit")
+ # build node for accepted-prefix-limit
+ apl_node = build_child_xml_node(
+ type_node,
+ "accepted-prefix-limit",
+ )
+ # Add node for maximum
+ if "maximum" in apl.keys():
+ build_child_xml_node(
+ apl_node,
+ "maximum",
+ apl["maximum"],
+ )
+ # Add node for teardown
+ td_node = None
+ if "limit_threshold" in apl.keys():
+ td_node = build_child_xml_node(
+ apl_node,
+ "teardown",
+ )
+ # add node for limit-threshold
+ build_child_xml_node(
+ td_node,
+ "limit-threshold",
+ apl.get("limit_threshold"),
+ )
+ elif "teardown" in apl.keys():
+ td_node = build_child_xml_node(
+ apl_node,
+ "teardown",
+ )
+ it_node = None
+ # Add node for teardown idle_timeout
+ if "idle_timeout_value" in apl.keys():
+ it_node = build_child_xml_node(
+ td_node,
+ "idle-timeout",
+ )
+ # add node for timeout
+ build_child_xml_node(
+ it_node,
+ "timeout",
+ apl.get("idle_timeout_value"),
+ )
+
+ elif "forever" in apl.keys():
+ if it_node is None:
+ it_node = build_child_xml_node(
+ td_node,
+ "idle-timeout",
+ )
+ if it_node is not None:
+ it_node = build_child_xml_node(
+ td_node,
+ "idle-timeout",
+ )
+ # add forever node
+ build_child_xml_node(it_node, "forever")
+
+ # Add node for add-path
+ if "add_path" in type.keys():
+ ap = type.get("add_path")
+ # build node for add_path
+ ap_node = build_child_xml_node(type_node, "add-path")
+ # add node for receive
+ if "receive" in ap.keys():
+ build_child_xml_node(ap_node, "receive")
+ if "send" in ap.keys():
+ # add node for send
+ send = ap.get("send")
+ send_node = build_child_xml_node(ap_node, "send")
+ # add node for path_count
+ if "path_count" in send.keys():
+ build_child_xml_node(
+ send_node,
+ "path-count",
+ send.get("path_count"),
+ )
+ # add node for include_backup_path
+ if "include_backup_path" in send.keys():
+ build_child_xml_node(
+ send_node,
+ "include-backup-path",
+ send.get("include_backup_path"),
+ )
+ # add node for path_selection_mode
+ if "path_selection_mode" in send.keys():
+ psm = send.get("path_selection_mode")
+ psm_node = build_child_xml_node(
+ send_node,
+ "path-selection-mode",
+ )
+ # add node for all_paths
+ if "all_paths" in psm.keys():
+ build_child_xml_node(psm_node, "all-paths")
+ # add node for equal_cost_paths
+ if "equal_cost_paths" in psm.keys():
+ build_child_xml_node(
+ psm_node,
+ "equal-cost-paths",
+ )
+ # add node for prefix_policy
+ if "prefix_policy" in send.keys():
+ build_child_xml_node(
+ send_node,
+ "prefix-policy",
+ send.get("prefix_policy"),
+ )
+ # Add node for aggregate_label
+ if "aggregate_label" in type.keys():
+ al = type.get("aggregate_label")
+ # build node for aggregate_label
+ al_node = build_child_xml_node(
+ type_node,
+ "aggregate_label",
+ )
+ # add node community
+ if "community" in al.keys():
+ build_child_xml_node(
+ al_node,
+ "community",
+ al.get("community"),
+ )
+
+ # Add node for aigp
+ if "aigp" in type.keys():
+ aigp = type.get("aigp")
+ # build node for aigp
+ if "disable" in aigp.keys():
+ aigp_node = build_child_xml_node(type_node, "aigp")
+ build_child_xml_node(aigp_node, "disable")
+ else:
+ build_child_xml_node(type_node, "aigp")
+
+ # Add node for damping
+ if "damping" in type.keys():
+ build_child_xml_node(type_node, "damping")
+
+ # Add node for defer_initial_multipath_build
+ if "defer_initial_multipath_build" in type.keys():
+ dimb = type.get("defer_initial_multipath_build")
+ # build node for defer_initial_multipath_build
+ dimb_node = build_child_xml_node(
+ type_node,
+ "defer-initial-multipath-build",
+ )
+ # add node maximum_delay
+ if dimb and "maximum_delay" in dimb.keys():
+ build_child_xml_node(
+ dimb_node,
+ "maximum-delay",
+ dimb.get("maximum_delay"),
+ )
+
+ # add node delay-route-advertisements
+ if "delay_route_advertisements" in type.keys():
+ dra = type.get("delay_route_advertisements")
+ # build node for delay_route_advertisements
+ dra_node = build_child_xml_node(
+ type_node,
+ "delay-route-advertisements",
+ )
+ # add maximum delay node
+ if (
+ "max_delay_route_age" in dra.keys()
+ or "max_delay_routing_uptime" in dra.keys()
+ ):
+ maxd_node = build_child_xml_node(
+ dra_node,
+ "maximum-delay",
+ )
+ # add node route-age
+ if "max_delay_route_age" in dra.keys():
+ build_child_xml_node(
+ maxd_node,
+ "route-age",
+ dra.get("max_delay_route_age"),
+ )
+
+ # add node routing-uptime
+ if "max_delay_routing_uptime" in dra.keys():
+ build_child_xml_node(
+ maxd_node,
+ "routing-uptime",
+ dra.get("max_delay_routing_uptime"),
+ )
+ # add minimum delay node
+ if (
+ "min_delay_inbound_convergence" in dra.keys()
+ or "min_delay_routing_uptime" in dra.keys()
+ ):
+ mind_node = build_child_xml_node(
+ dra_node,
+ "minimum-delay",
+ )
+ # add node inbound-convergence
+ if "min_delay_inbound_convergence" in dra.keys():
+ build_child_xml_node(
+ mind_node,
+ "inbound-convergence",
+ dra.get("min_delay_inbound_convergence"),
+ )
+
+ # add node routing-uptime
+ if "min_delay_routing_uptime" in dra.keys():
+ build_child_xml_node(
+ mind_node,
+ "routing-uptime",
+ dra.get("min_delay_routing_uptime"),
+ )
+
+ # add node entropy-label
+ if "entropy_label" in type.keys():
+ el = type.get("entropy_label")
+ # build node for entropy_label
+ el_node = build_child_xml_node(
+ type_node,
+ "entropy-label",
+ )
+ # add node import
+ if "import" in el.keys():
+ build_child_xml_node(
+ el_node,
+ "import",
+ el.get("import"),
+ )
+ # add node no_next_hop_validation
+ if "no_next_hop_validation" in el.keys():
+ build_child_xml_node(
+ el_node,
+ "no-next-hop-validation",
+ )
+
+ # add node explicit-null
+ if "explicit_null" in type.keys():
+ en = type.get("explicit_null")
+ # add node connected-only
+ if "connected_only" in en.keys():
+ en_node = build_child_xml_node(
+ type_node,
+ "explicit-null",
+ )
+ build_child_xml_node(en_node, "connected-only")
+ else:
+ # build node for explicit_null
+ build_child_xml_node(type_node, "explicit-null")
+
+ # add node extended-nexthop
+ if "extended_nexthop" in type.keys():
+ enh = type.get("extended_nexthop")
+ # add node extended-nexthop
+ if enh:
+ build_child_xml_node(type_node, "extended-nexthop")
+
+ # add node extended-nexthop-color
+ if "extended_nexthop_color" in type.keys():
+ enhc = type.get("extended_nexthop_color")
+ # add node extended-nexthop-color
+ if enhc:
+ build_child_xml_node(
+ type_node,
+ "extended-nexthop-color",
+ )
+
+ # add node forwarding-state-bit
+ if "graceful_restart_forwarding_state_bit" in type.keys():
+ grfs = type.get(
+ "graceful_restart_forwarding_state_bit",
+ )
+
+ # add node forwarding-state-bit
+ gr_node = build_child_xml_node(
+ type_node,
+ "graceful-restart",
+ )
+ build_child_xml_node(
+ gr_node,
+ "forwarding-state-bit",
+ grfs,
+ )
+
+ # add node local-ipv4-address
+ if "local_ipv4_address" in type.keys():
+ # add node local-ipv4-address
+ build_child_xml_node(
+ type_node,
+ "local-ipv4-address",
+ type.get("local_ipv4_address"),
+ )
+
+ # add node legacy-redirect-ip-action
+ if "legacy_redirect_ip_action" in type.keys():
+ lria = type.get("legacy_redirect_ip_action")
+ # add node legacy_redirect_ip_action
+ lria_node = build_child_xml_node(
+ type_node,
+ "legacy-redirect-ip-action",
+ )
+ if "send" in lria.keys():
+ build_child_xml_node(lria_node, "send")
+ if "receive" in lria.keys():
+ build_child_xml_node(lria_node, "receive")
+
+ # add node loops
+ if "loops" in type.keys():
+ build_child_xml_node(
+ type_node,
+ "loops",
+ type.get("loops"),
+ )
+
+ # add no-install
+ if "no_install" in type.keys():
+ if type.get("no_install"):
+ build_child_xml_node(type_node, "no-install")
+
+ # add node no-validate
+ if "no_validate" in type.keys():
+ build_child_xml_node(
+ type_node,
+ "no-validate",
+ type.get("no_validate"),
+ )
+
+ # add node output-queue-priority
+ if (
+ "output_queue_priority_expedited" in type.keys()
+ or "output_queue_priority_priority" in type.keys()
+ ):
+ # node for output-queue-priority
+ oqp_node = build_child_xml_node(
+ type_node,
+ "output-queue-priority",
+ )
+ # add node expedited
+ if "output_queue_priority_expedited" in type.keys() and type.get(
+ "output_queue_priority_expedited",
+ ):
+ build_child_xml_node(oqp_node, "expedited")
+ # add node priority
+ if "output_queue_priority_priority" in type.keys():
+ build_child_xml_node(
+ oqp_node,
+ "priority",
+ type.get("output_queue_priority_priority"),
+ )
+
+ # add per-prefix-label
+ if "per_prefix_label" in type.keys():
+ if type.get("per_prefix_label"):
+ build_child_xml_node(type_node, "per-prefix-label")
+
+ # add per-group-label
+ if "per_group_label" in type.keys():
+ if type.get("per_group_label"):
+ build_child_xml_node(type_node, "per-group-label")
+
+ # Add node for prefix-limit
+ if "prefix_limit" in type.keys():
+ pl = type.get("prefix_limit")
+ # build node for prefix-limit
+ pl_node = build_child_xml_node(
+ type_node,
+ "prefix-limit",
+ )
+ # Add node for maximum
+ if "maximum" in pl.keys():
+ build_child_xml_node(
+ pl_node,
+ "maximum",
+ pl["maximum"],
+ )
+ # Add node for teardown
+ td_node = None
+ if "limit_threshold" in pl.keys():
+ td_node = build_child_xml_node(
+ pl_node,
+ "teardown",
+ pl.get("limit_threshold"),
+ )
+ elif "teardown" in pl.keys():
+ td_node = build_child_xml_node(pl_node, "teardown")
+ it_node = None
+ # Add node for teardown idle_timeout
+ if "idle_timeout_value" in pl.keys():
+ it_node = build_child_xml_node(
+ td_node,
+ "idle-timeout",
+ pl.get("idle_timeout_value"),
+ )
+ elif "idle_timeout" in pl.keys():
+ it_node = build_child_xml_node(
+ td_node,
+ "idle-timeout",
+ )
+ if "forever" in pl.keys():
+ if it_node is None:
+ it_node = build_child_xml_node(
+ td_node,
+ "idle-timeout",
+ )
+ # add forever node
+ build_child_xml_node(it_node, "forever")
+
+ # add resolve-vpn
+ if "resolve_vpn" in type.keys():
+ if type.get("resolve_vpn"):
+ build_child_xml_node(type_node, "resolve-vpn")
+
+ # add rib
+ if "rib" in type.keys():
+ rib_node = build_child_xml_node(type_node, "rib")
+ # add node inet.3
+ build_child_xml_node(rib_node, "inet.3")
+
+ # add rib-group
+ if "ribgroup_name" in type.keys():
+ build_child_xml_node(
+ type_node,
+ "rib-group",
+ type.get("ribgroup_name"),
+ )
+
+ # add node route-refresh-priority
+ if (
+ "route_refresh_priority_expedited" in type.keys()
+ or "route_refresh_priority_priority" in type.keys()
+ ):
+ # node for route-refresh-priority
+ rrp_node = build_child_xml_node(
+ type_node,
+ "route-refresh-priority",
+ )
+ # add node expedited
+ if "route_refresh_priority_expedited" in type.keys() and type.get(
+ "route_refresh_priority_expedited",
+ ):
+ build_child_xml_node(rrp_node, "expedited")
+ # add node priority
+ if "route_refresh_priority_priority" in type.keys():
+ build_child_xml_node(
+ rrp_node,
+ "priority",
+ type.get("route_refresh_priority_priority"),
+ )
+
+ # add secondary-independent-resolution
+ if "secondary_independent_resolution" in type.keys():
+ if type.get("secondary_independent_resolution"):
+ build_child_xml_node(
+ type_node,
+ "secondary-independent-resolution",
+ )
+
+ # add node withdraw-priority
+ if (
+ "withdraw_priority_expedited" in type.keys()
+ or "withdraw_priority_priority" in type.keys()
+ ):
+ # node for withdraw-priority
+ wp_node = build_child_xml_node(
+ type_node,
+ "withdraw-priority",
+ )
+ # add node expedited
+ if "withdraw_priority_expedited" in type.keys() and type.get(
+ "withdraw_priority_expedited",
+ ):
+ build_child_xml_node(wp_node, "expedited")
+ # add node priority
+ if "withdraw_priority_priority" in type.keys():
+ build_child_xml_node(
+ wp_node,
+ "priority",
+ type.get("withdraw_priority_priority"),
+ )
+
+ # add strip-nexthop
+ if "strip_nexthop" in type.keys():
+ if type.get("strip_nexthop"):
+ build_child_xml_node(type_node, "strip-nexthop")
+
+ # add topology
+ if "topology" in type.keys():
+ topologies = type.get("topology")
+ top_node = build_child_xml_node(type_node, "topology")
+ for topology in topologies:
+ if "name" in topology.keys():
+ build_child_xml_node(
+ top_node,
+ "name",
+ topology.get("name"),
+ )
+ if "community" in topology.keys():
+ communities = topology.get("community")
+ for community in communities:
+ build_child_xml_node(
+ top_node,
+ "community",
+ community,
+ )
+
+ # add traffic-statistics
+ if "traffic_statistics" in type.keys():
+ ts = type.get("traffic_statistics")
+ ts_node = build_child_xml_node(
+ type_node,
+ "traffic-statistics",
+ )
+ # add node interval
+ if "interval" in ts.keys():
+ build_child_xml_node(
+ ts_node,
+ "interval",
+ ts.get("interval"),
+ )
+ # add node labeled-path
+ if "labeled_path" in ts.keys and ts.get(
+ "labeled_path",
+ ):
+ build_child_xml_node(ts_node, "labeled-path")
+
+ 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
+ """
+ bgp_xml = []
+ family_root = None
+ groups_node = None
+ existing_groups = []
+ if have is not None and have.get("address_family"):
+ h_af = have.get("address_family")
+ existing_af = [af["afi"] for af in h_af]
+
+ h_groups = have.get("groups")
+ if h_groups:
+ for group in h_groups:
+ existing_groups.append(group["name"])
+ if not want or not want.get("address_family"):
+ want = have
+
+ # Delete root address family
+ w_af = want["address_family"]
+ for af in w_af:
+ if af["afi"] not in existing_af:
+ continue
+ if family_root is None:
+ family_root = build_child_xml_node(self.bgp, "family")
+ build_child_xml_node(
+ family_root,
+ af["afi"],
+ None,
+ {"delete": "delete"},
+ )
+
+ # Delete group address-family
+ w_groups = want.get("groups")
+ if w_groups:
+ for group in w_groups:
+ if group["name"] not in existing_groups:
+ continue
+
+ groups_node = build_child_xml_node(self.bgp, "group")
+ build_child_xml_node(groups_node, "name", group["name"])
+
+ for h_group in h_groups:
+ if h_group["name"] == group["name"]:
+ address_family = h_group.get("address_family")
+ if address_family:
+ for af in address_family:
+ family_node = build_child_xml_node(
+ groups_node,
+ "family",
+ )
+ build_child_xml_node(
+ family_node,
+ af["afi"],
+ None,
+ {"delete": "delete"},
+ )
+ if "neighbors" in h_group.keys():
+ h_neighbors = h_group.get("neighbors")
+ for neighbor in h_neighbors:
+ if "address_family" in neighbor.keys():
+ neighbors_node = build_child_xml_node(
+ groups_node,
+ "neighbor",
+ )
+ build_child_xml_node(
+ neighbors_node,
+ "name",
+ neighbor["neighbor_address"],
+ )
+ address_family = neighbor.get(
+ "address_family",
+ )
+ for af in address_family:
+ family_node = build_child_xml_node(
+ neighbors_node,
+ "family",
+ )
+ build_child_xml_node(
+ family_node,
+ af["afi"],
+ None,
+ {"delete": "delete"},
+ )
+
+ if groups_node is not None:
+ bgp_xml.append(groups_node)
+ if family_root is not None:
+ bgp_xml.append(family_root)
+ return bgp_xml
+
+ def _state_overridden(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
+ """
+ bgp_xml = []
+ family_root = None
+ if have is not None and have.get("address_family"):
+ h_af = have.get("address_family")
+ existing_af = [af["afi"] for af in h_af]
+ for af in existing_af:
+ if family_root is None:
+ family_root = build_child_xml_node(self.bgp, "family")
+ build_child_xml_node(
+ family_root,
+ af,
+ None,
+ {"delete": "delete"},
+ )
+ if family_root is not None:
+ bgp_xml.append(family_root)
+ bgp_xml.extend(self._state_deleted(want, have))
+ bgp_xml.extend(self._state_merged(want, have))
+ return bgp_xml
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_global/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_global/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_global/bgp_global.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_global/bgp_global.py
new file mode 100644
index 000000000..da512c6f9
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/bgp_global/bgp_global.py
@@ -0,0 +1,792 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos_bgp_global 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_empties,
+ to_list,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Bgp_global(ConfigBase):
+ """
+ The junos_bgp_global class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["bgp_global"]
+
+ def __init__(self, module):
+ super(Bgp_global, self).__init__(module)
+
+ def get_bgp_global_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ bgp_facts = facts["ansible_network_resources"].get("bgp_global")
+ if not bgp_facts:
+ return {}
+ return bgp_facts
+
+ def execute_module(self):
+ """Execute the module
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ state = self._module.params["state"]
+
+ warnings = list()
+
+ if self.state in self.ACTION_STATES or self.state == "purged":
+ existing_bgp_global_facts = self.get_bgp_global_facts()
+ else:
+ existing_bgp_global_facts = {}
+ if state == "gathered":
+ existing_bgp_global_facts = self.get_bgp_global_facts()
+ result["gathered"] = existing_bgp_global_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_bgp_global_facts(data=running_config)
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_bgp_global_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ config_xmls = self.set_config(existing_bgp_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 config_xmls and 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_bgp_global_facts = self.get_bgp_global_facts()
+
+ result["before"] = existing_bgp_global_facts
+ if result["changed"]:
+ result["after"] = changed_bgp_global_facts
+
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_bgp_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_bgp_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
+ """
+ self.autonomous_system = None
+ self.root = build_root_xml_node("configuration")
+ self.protocols = build_child_xml_node(self.root, "protocols")
+ self.routing_options = build_child_xml_node(
+ self.root,
+ "routing-options",
+ )
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ config_xmls = []
+ temp_lst = []
+ if state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state == "purged":
+ config_xmls = self._state_purged(want, have)
+ elif state in ("merged", "rendered"):
+ config_xmls = self._state_merged(want, have)
+ elif state == "replaced":
+ config_xmls = self._state_replaced(want, have)
+
+ if config_xmls:
+ for xml in config_xmls:
+ self.protocols.append(xml)
+ for xml in self.root.getchildren():
+ xml = tostring(xml)
+ temp_lst.append(xml)
+ if state == "purged":
+ for xml in self.root.getchildren():
+ xml = tostring(xml)
+ temp_lst.append(xml)
+ return temp_lst
+
+ 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
+ """
+ bgp_xml = []
+ bgp_xml.extend(self._state_deleted(want, have))
+ bgp_xml.extend(self._state_merged(want, have))
+
+ return bgp_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
+ """
+ bgp_xml = []
+
+ want = remove_empties(want)
+ if want:
+ bgp_root = build_root_xml_node("bgp")
+ bool_parser = [
+ "accept-remote-nexthop",
+ "add-path-display-ipv4-address",
+ "advertise-from-main-vpn-tables",
+ "advertise-inactive",
+ "advertise-peer-as",
+ "damping",
+ "disable",
+ "egress-te-sid-stats",
+ "enforce-first-as",
+ "holddown-all-stale-labels",
+ "include-mp-next-hop",
+ "log-updown",
+ "mtu-discovery",
+ "no-advertise-peer-as",
+ "no-aggregator-id",
+ "no-client-reflect",
+ "no-precision-timers",
+ "passive",
+ "precision-timers",
+ "rfc6514-compliant-safi129",
+ "route-server-client",
+ "send-addpath-optimization",
+ "itcp-aggressive-transmission",
+ "unconfigured-peer-graceful-restart",
+ "vpn-apply-export",
+ "as-override",
+ "unconfigured-peer-graceful-restart",
+ "vpn-apply-export",
+ ]
+ cfg_parser = [
+ "authentication-algorithm",
+ "authentication-key",
+ "authentication-key-chain",
+ "description",
+ "export",
+ "forwarding-context",
+ "hold-time",
+ "import",
+ "ipsec-sa",
+ "keep",
+ "local-address",
+ "local-interface",
+ "local-preference",
+ "peer-as",
+ "preference",
+ "out-delay",
+ "sr-preference-override",
+ "stale-labels-holddown-period",
+ "tcp-mss",
+ "ttl",
+ "type",
+ ]
+ for item in bool_parser:
+ bgp_root = self._add_node(
+ want,
+ item,
+ item.replace("-", "_"),
+ bgp_root,
+ )
+
+ for item in cfg_parser:
+ bgp_root = self._add_node(
+ want,
+ item,
+ item.replace("-", "_"),
+ bgp_root,
+ True,
+ )
+
+ # Generate xml node for autonomous-system
+ if want.get("as_number"):
+ as_node = build_child_xml_node(
+ self.routing_options,
+ "autonomous-system",
+ want.get("as_number"),
+ )
+ # Add node for loops
+ if want.get("loops"):
+ build_child_xml_node(as_node, "loops", want.get("loops"))
+ # Add node for asdot_notation
+ if want.get("asdot_notation"):
+ if "asdot_notation" in want.keys():
+ build_child_xml_node(as_node, "asdot-notation")
+
+ # Generate commands for bgp node
+ self.parse_attrib(bgp_root, want)
+
+ # Generate commands for groups
+ if want.get("groups"):
+ groups = want.get("groups")
+
+ # Generate commands for each group in group list
+ for group in groups:
+ groups_node = build_child_xml_node(bgp_root, "group")
+ build_child_xml_node(groups_node, "name", group["name"])
+ # Parse the boolean value attributes
+ for item in bool_parser:
+ groups_node = self._add_node(
+ group,
+ item,
+ item.replace("-", "_"),
+ groups_node,
+ )
+
+ # Parse the non-boolean leaf attributes
+ for item in cfg_parser:
+ groups_node = self._add_node(
+ group,
+ item,
+ item.replace("-", "_"),
+ groups_node,
+ True,
+ )
+
+ # Generate commands for nodes with child attributes
+ self.parse_attrib(groups_node, group)
+
+ # Generate commands for each neighbors
+ if group.get("neighbors"):
+ neighbors = group.get("neighbors")
+ # Generate commands for each neighbor in neighbors list
+ for neighbor in neighbors:
+ neighbors_node = build_child_xml_node(
+ groups_node,
+ "neighbor",
+ )
+ build_child_xml_node(
+ neighbors_node,
+ "name",
+ neighbor["neighbor_address"],
+ )
+ # Parse the boolean value attributes
+ for item in bool_parser:
+ neighbors_node = self._add_node(
+ neighbor,
+ item,
+ item.replace("-", "_"),
+ neighbors_node,
+ )
+
+ # Parse the non-boolean leaf attributes
+ for item in cfg_parser:
+ neighbors_node = self._add_node(
+ neighbor,
+ item,
+ item.replace("-", "_"),
+ neighbors_node,
+ True,
+ )
+
+ # Generate commands for nodes with child attributes
+ self.parse_attrib(neighbors_node, neighbor)
+
+ bgp_xml.append(bgp_root)
+
+ return bgp_xml
+
+ def parse_attrib(self, bgp_root, want):
+ # Generate config commands for advertise-bgp-static
+ if want.get("advertise_bgp_static"):
+ ad_bgp_static_node = build_child_xml_node(
+ bgp_root,
+ "advertise-bgp-static",
+ )
+ ad_bgp_static = want.get("advertise_bgp_static")
+ if "policy" in ad_bgp_static.keys():
+ build_child_xml_node(
+ ad_bgp_static_node,
+ "policy",
+ ad_bgp_static["policy"],
+ )
+
+ # Generate config commands for advertise-external
+ if want.get("advertise_external"):
+ ad_ext_node = build_child_xml_node(bgp_root, "advertise-external")
+ ad_ext = want.get("advertise_external")
+ if "conditional" in ad_ext.keys():
+ build_child_xml_node(ad_ext_node, "conditional")
+
+ # Generate config commands for bfd-liveness-detection
+ if want.get("bfd_liveness_detection"):
+ bfd_live_node = build_child_xml_node(
+ bgp_root,
+ "bfd-liveness-detection",
+ )
+ bfd_live_detect = want.get("bfd_liveness_detection")
+
+ # Add node for authentication
+
+ if "authentication" in bfd_live_detect.keys():
+ bld_auth = bfd_live_detect["authentication"]
+ bld_auth_node = build_child_xml_node(
+ bfd_live_node,
+ "authentication",
+ )
+ # Add node for algorithm
+ if "algorithm" in bld_auth.keys():
+ build_child_xml_node(
+ bld_auth_node,
+ "algorithm",
+ bld_auth["algorithm"],
+ )
+ # Add node for key-chain
+ if "key_chain" in bld_auth.keys():
+ build_child_xml_node(
+ bld_auth_node,
+ "key-chain",
+ bld_auth["key_chain"],
+ )
+ # Add node for loose-check
+ if "loose_check" in bld_auth.keys():
+ b_val = bld_auth.get("loose_check")
+ if b_val is not None:
+ if b_val is True:
+ build_child_xml_node(bld_auth_node, "loose-check")
+ # Add node for detection-time
+ if "detection_time" in bfd_live_detect.keys():
+ d_time = bfd_live_detect["detection_time"]
+ bld_dtime_node = build_child_xml_node(
+ bfd_live_node,
+ "detection-time",
+ )
+ # Add node for threshold
+ if "threshold" in d_time.keys():
+ build_child_xml_node(
+ bld_dtime_node,
+ "threshold",
+ d_time["threshold"],
+ )
+ # Add node for transmit-interval
+ if "transmit_interval" in bfd_live_detect.keys():
+ t_int = bfd_live_detect["transmit_interval"]
+ t_int_node = build_child_xml_node(
+ bfd_live_node,
+ "transmit-interval",
+ )
+ # Add node for minimum-interval
+ if "minimum_interval" in t_int.keys():
+ build_child_xml_node(
+ t_int_node,
+ "minimum-interval",
+ t_int["minimum_interval"],
+ )
+ # Add node for holddown-interval
+ if "holddown_interval" in bfd_live_detect.keys():
+ build_child_xml_node(
+ bfd_live_node,
+ "holddown-interval",
+ bfd_live_detect["holddown_interval"],
+ )
+ # Add node for minimum-receive-interval
+ if "minimum_receive_interval" in bfd_live_detect.keys():
+ build_child_xml_node(
+ bfd_live_node,
+ "minimum-receive-interval",
+ bfd_live_detect["minimum_receive_interval"],
+ )
+ # Add node for minimum-interval
+ if "minimum_interval" in bfd_live_detect.keys():
+ build_child_xml_node(
+ bfd_live_node,
+ "minimum-interval",
+ bfd_live_detect["minimum_interval"],
+ )
+ # Add node for multiplier
+ if "multiplier" in bfd_live_detect.keys():
+ build_child_xml_node(
+ bfd_live_node,
+ "multiplier",
+ bfd_live_detect["multiplier"],
+ )
+ # Add node for no-adaptation
+ if "no_adaptation" in bfd_live_detect.keys():
+ b_val = bfd_live_detect.get("no_adaptation")
+ if b_val is not None:
+ if b_val is True:
+ build_child_xml_node(bfd_live_node, "no-adaptation")
+ # Add node for session-mode
+ if "session_mode" in bfd_live_detect.keys():
+ build_child_xml_node(
+ bfd_live_node,
+ "session-mode",
+ bfd_live_detect["session_mode"],
+ )
+ # Add node for version
+ if "version" in bfd_live_detect.keys():
+ build_child_xml_node(
+ bfd_live_node,
+ "version",
+ bfd_live_detect["version"],
+ )
+ # Generate config commands for bgp-error-tolerance
+ if want.get("bgp_error_tolerance"):
+ bgp_err_tol_node = build_child_xml_node(
+ bgp_root,
+ "bgp-error-tolerance",
+ )
+ bgp_err_tol = want.get("bgp_error_tolerance")
+ # Add node for malformed-route-limit"
+ if "malformed_route_limit" in bgp_err_tol.keys():
+ build_child_xml_node(
+ bgp_err_tol_node,
+ "malformed-route-limit",
+ bgp_err_tol["malformed_route_limit"],
+ )
+ # Add node for malformed-update-log-interval
+ if "malformed_update_log_interval" in bgp_err_tol.keys():
+ build_child_xml_node(
+ bgp_err_tol_node,
+ "malformed-update-log-interval",
+ bgp_err_tol["malformed_update_log_interval"],
+ )
+ # Generate config commands for no-malformed-route-limit
+ if "no_malformed_route_limit" in bgp_err_tol.keys():
+ b_val = bgp_err_tol.get("no_malformed_route_limit")
+ if b_val is not None:
+ if b_val is True:
+ build_child_xml_node(
+ bgp_err_tol_node,
+ "no-malformed-route-limit",
+ )
+
+ # Generate config commands for bmp
+ if want.get("bmp"):
+ bmp_node = build_child_xml_node(bgp_root, "bmp")
+ bmp = want.get("bmp")
+ # Add node for monitor
+ if "monitor" in bmp.keys():
+ b_val = bmp.get("monitor")
+ if b_val is not None:
+ if b_val is True:
+ build_child_xml_node(bmp_node, "monitor", "enable")
+ else:
+ build_child_xml_node(bmp_node, "monitor", "disable")
+
+ # Add node for route-monitoring
+ if "route_monitoring" in bmp.keys():
+ r_mon_node = build_child_xml_node(bmp_node, "route-monitoring")
+ r_mon = bmp["route_monitoring"]
+ # Add node for none
+ if "none" in r_mon.keys():
+ b_val = r_mon.get("none")
+ if b_val is not None:
+ if b_val is True:
+ build_child_xml_node(r_mon_node, "none")
+ # Add node for post-policy
+ if "post_policy_exclude_non_eligible" in r_mon.keys():
+ b_val = r_mon.get("post_policy_exclude_non_eligible")
+ if b_val is not None:
+ if b_val is True:
+ policy_node = build_child_xml_node(
+ r_mon_node,
+ "post-policy",
+ )
+ build_child_xml_node(
+ policy_node,
+ "exclude-non-eligible",
+ )
+ elif "post_policy" in r_mon.keys():
+ b_val = r_mon.get("post_policy")
+ if b_val is not None:
+ if b_val is True:
+ build_child_xml_node(r_mon_node, "post-policy")
+ # Add node for post-policy
+ if "pre_policy_exclude_non_feasible" in r_mon.keys():
+ b_val = r_mon.get("pre_policy_exclude_non_feasible")
+ if b_val is not None:
+ if b_val is True:
+ policy_node = build_child_xml_node(
+ r_mon_node,
+ "pre-policy",
+ )
+ build_child_xml_node(
+ policy_node,
+ "exclude-non-eligible",
+ )
+ elif "pre-policy" in r_mon.keys():
+ b_val = r_mon.get("pre_policy")
+ if b_val is not None:
+ if b_val is True:
+ build_child_xml_node(r_mon_node, "pre-policy")
+
+ # Generate config commands for egress-te
+ if want.get("egress_te"):
+ et_node = build_child_xml_node(bgp_root, "egress-te")
+ et = want.get("egress_te")
+ if "backup_path" in et:
+ build_child_xml_node(
+ et_node,
+ "backup-path",
+ et.get("backup_path"),
+ )
+
+ # Generate config commands for egress-te-backup-paths
+ if want.get("egress_te_backup_paths"):
+ etbp_node = build_child_xml_node(
+ bgp_root,
+ "egress-te-backup-paths",
+ )
+ etbp = want.get("egress_te_backup_paths")
+ # generate commands for templates
+ templates = etbp.get("templates")
+ for template in templates:
+ template_node = build_child_xml_node(etbp_node, "template")
+ # add name node
+ if "path_name" in template.keys():
+ build_child_xml_node(
+ template_node,
+ "name",
+ template.get("path_name"),
+ )
+ # add peers
+ if "peers" in template.keys():
+ peers = template.get("peers")
+ for peer in peers:
+ peer_node = build_child_xml_node(template_node, "peer")
+ build_child_xml_node(peer_node, "name", peer)
+ # add remote-nexthop
+ if "remote_nexthop" in template.keys():
+ build_child_xml_node(
+ template_node,
+ "remote-nexthop",
+ template.get("remote_nexthop"),
+ )
+ # add ip-forward
+ if "ip_forward" in template.keys():
+ ipf = template.get("ip_forward")
+ ipf_node = build_child_xml_node(
+ template_node,
+ "ip-forward",
+ )
+
+ if "rti_name" not in ipf.keys():
+ build_child_xml_node(
+ ipf_node,
+ "name",
+ ipf.get("rti_name"),
+ )
+
+ # Generate config commands for allow
+ if want.get("allow"):
+ allow = want.get("allow")
+ for network in allow:
+ build_child_xml_node(bgp_root, "allow", network)
+
+ # Generate config commands for optimal-route-reflection
+ if want.get("optimal_route_reflection"):
+ orr_node = build_child_xml_node(
+ bgp_root,
+ "optimal-route-reflection",
+ )
+ orr = want.get("optimal_route_reflection")
+ if "igp_backup" in orr.keys():
+ build_child_xml_node(
+ orr_node,
+ "igp-backup",
+ orr.get("igp_backup"),
+ )
+ if "igp_primary" in orr.keys():
+ build_child_xml_node(
+ orr_node,
+ "igp-primary",
+ orr.get("igp_primary"),
+ )
+
+ 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
+ """
+ bgp_xml = []
+ parser = [
+ "accept-remote-nexthop",
+ "add-path-display-ipv4-address",
+ "advertise-bgp-static",
+ "advertise-external",
+ "advertise-from-main-vpn-tables",
+ "advertise-inactive",
+ "advertise-peer-as",
+ "authentication-algorithm",
+ "authentication-key",
+ "authentication-key-chain",
+ "bfd-liveness-detection",
+ "bgp-error-tolerance",
+ "bmp",
+ "group",
+ "cluster",
+ "damping",
+ "description",
+ "disable",
+ "egress-te-sid-stats",
+ "enforce-first-as",
+ "export",
+ "forwarding-context",
+ "hold-time",
+ "holddown-all-stale-labels",
+ "import",
+ "include-mp-next-hop",
+ "ipsec-sa",
+ "keep",
+ "local-address",
+ "local-interface",
+ "local-preference",
+ "log-updown",
+ "mtu-discovery",
+ "no-advertise-peer-as",
+ "no-aggregator-id",
+ "no-client-reflect",
+ "no-precision-timers",
+ "passive",
+ "peer-as",
+ "precision-timers",
+ "preference",
+ "out-delay",
+ "rfc6514-compliant-safi129",
+ "route-server-client",
+ "send-addpath-optimization",
+ "sr-preference-override",
+ "stale-labels-holddown-period",
+ "tcp-aggressive-transmission",
+ "tcp-mss",
+ "ttl",
+ "unconfigured-peer-graceful-restart",
+ "vpn-apply-export",
+ ]
+ if have is not None:
+ bgp_root = build_root_xml_node("bgp")
+ for attrib in parser:
+ build_child_xml_node(
+ bgp_root,
+ attrib,
+ None,
+ {"delete": "delete"},
+ )
+ autonomous_system = have.get("as_number")
+ if autonomous_system:
+ build_child_xml_node(
+ self.routing_options,
+ "autonomous-system",
+ None,
+ {"delete": "delete"},
+ )
+ bgp_xml.append(bgp_root)
+ return bgp_xml
+
+ def _state_purged(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
+ """
+ bgp_xml = []
+ delete = {"delete": "delete"}
+ build_child_xml_node(self.protocols, "bgp", None, delete)
+ autonomous_system = have.get("as_number")
+ if autonomous_system:
+ build_child_xml_node(
+ self.routing_options,
+ "autonomous-system",
+ None,
+ {"delete": "delete"},
+ )
+ return bgp_xml
+
+ def _add_node(self, want, h_key, w_key, node, cfg=False):
+ """Append the child node to the root node
+ :param want: the desired configuration as a dictionary
+ :param h_key: the current configuration key
+ :param: node: root node
+ """
+ if cfg:
+ if want.get(w_key):
+ build_child_xml_node(node, h_key, want[w_key])
+ else:
+ if w_key in want.keys():
+ b_val = want.get(w_key)
+ if b_val is not None:
+ if b_val is True:
+ build_child_xml_node(node, h_key)
+ return node
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/hostname/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/hostname/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/hostname/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/hostname/hostname.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/hostname/hostname.py
new file mode 100644
index 000000000..0fab60f99
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/hostname/hostname.py
@@ -0,0 +1,199 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos_hostname 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_empties,
+ to_list,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Hostname(ConfigBase):
+ """
+ The junos_hostname class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["hostname"]
+
+ def __init__(self, module):
+ super(Hostname, self).__init__(module)
+
+ def get_hostname_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ hostname_facts = facts["ansible_network_resources"].get("hostname")
+ if not hostname_facts:
+ return {}
+ return hostname_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ state = self._module.params["state"]
+
+ warnings = list()
+
+ if self.state in self.ACTION_STATES or self.state == "purged":
+ existing_hostname_facts = self.get_hostname_facts()
+ else:
+ existing_hostname_facts = {}
+ if state == "gathered":
+ existing_hostname_facts = self.get_hostname_facts()
+ result["gathered"] = existing_hostname_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_hostname_facts(data=running_config)
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_hostname_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+
+ else:
+ diff = None
+ config_xmls = self.set_config(existing_hostname_facts)
+ with locked_config(self._module):
+ for config_xml in 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_hostname_facts = self.get_hostname_facts()
+
+ result["before"] = existing_hostname_facts
+ if result["changed"]:
+ result["after"] = changed_hostname_facts
+
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_hostname_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_hostname_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
+ """
+ self.root = build_root_xml_node("system")
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "rendered", "overridden") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ if state == "deleted":
+ self._state_deleted(want, have)
+ elif state in ("merged", "rendered", "replaced", "overridden"):
+ self._state_merged(want, have)
+ return tostring(self.root)
+
+ def _state_merged(self, want, have):
+ """The command generator when state is merged
+
+ :rtype: A list
+ :returns: the commands necessary to merge the provided into
+ the current configuration
+ """
+ want = remove_empties(want)
+
+ # add hostname node
+ if "hostname" in want.keys():
+ build_child_xml_node(self.root, "host-name", want.get("hostname"))
+
+ 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
+ """
+ hostname_xml = []
+ hostname_root = None
+ delete = {"delete": "delete"}
+ if have is not None:
+ hostname_root = build_child_xml_node(
+ self.root,
+ "host-name",
+ None,
+ delete,
+ )
+
+ if hostname_root is not None:
+ hostname_xml.append(hostname_root)
+ return hostname_xml
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/interfaces/interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/interfaces/interfaces.py
new file mode 100644
index 000000000..ad6b58668
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/interfaces/interfaces.py
@@ -0,0 +1,358 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+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, data=None):
+ """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,
+ data=data,
+ )
+ 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}
+ state = self._module.params["state"]
+
+ if self.state in self.ACTION_STATES:
+ existing_interfaces_facts = self.get_interfaces_facts()
+ else:
+ existing_interfaces_facts = []
+
+ if state == "gathered":
+ existing_interfaces_facts = self.get_interfaces_facts()
+ result["gathered"] = existing_interfaces_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_interfaces_facts(data=running_config)
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_interfaces_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ 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 in ("merged", "replaced", "overridden", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ 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")
+
+ if config.get("units"):
+ units = config.get("units")
+ for unit in units:
+ unit_node = build_child_xml_node(intf, "unit")
+ build_child_xml_node(unit_node, "name", str(unit["name"]))
+ build_child_xml_node(
+ unit_node,
+ "description",
+ unit["description"],
+ )
+
+ 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
+
+ if 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 any(
+ [
+ config["name"].startswith("gr"),
+ config["name"].startswith("lo"),
+ ],
+ ):
+ intf_fields.append("speed")
+
+ if not any(
+ [
+ config["name"].startswith("gr"),
+ 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 any(
+ [
+ config["name"].startswith("gr"),
+ 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")
+ have_cfg = self.in_have(config["name"], have)
+ if have_cfg:
+ logical_cfg = have_cfg
+ else:
+ logical_cfg = config
+ if logical_cfg.get("units"):
+ units = logical_cfg.get("units")
+ for unit in units:
+ unit_node = build_child_xml_node(intf, "unit")
+ build_child_xml_node(
+ unit_node,
+ "name",
+ str(unit["name"]),
+ )
+ build_child_xml_node(
+ unit_node,
+ "description",
+ None,
+ {"delete": "delete"},
+ )
+
+ for holdtime_field in ["up", "down"]:
+ build_child_xml_node(
+ holdtime_ele,
+ holdtime_field,
+ None,
+ {"delete": "delete"},
+ )
+ intf_xml.append(intf)
+
+ return intf_xml
+
+ def in_have(self, name, have):
+ for item in have:
+ if name == item["name"]:
+ return item
+ return None
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l2_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l2_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l2_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l2_interfaces/l2_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l2_interfaces/l2_interfaces.py
new file mode 100644
index 000000000..7cbb3a825
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l2_interfaces/l2_interfaces.py
@@ -0,0 +1,340 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+ build_subtree,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.utils.utils import (
+ get_resource_config,
+)
+
+
+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, data=None):
+ """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,
+ data=data,
+ )
+ 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}
+ state = self._module.params["state"]
+
+ if self.state in self.ACTION_STATES:
+ existing_l2_interfaces_facts = self.get_l2_interfaces_facts()
+ else:
+ existing_l2_interfaces_facts = []
+ if state == "gathered":
+ existing_l2_interfaces_facts = self.get_l2_interfaces_facts()
+ result["gathered"] = existing_l2_interfaces_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_l2_interfaces_facts(
+ data=running_config,
+ )
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_l2_interfaces_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ 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_interfaces_facts = self.get_l2_interfaces_facts()
+
+ result["before"] = existing_l2_interfaces_facts
+ if result["changed"]:
+ result["after"] = changed_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 in ("merged", "replaced", "overridden", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ 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 get_res_config(self, connection, config_filter):
+ """
+
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return get_resource_config(connection, config_filter=config_filter)
+
+ 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 = self.get_res_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
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l3_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l3_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l3_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l3_interfaces/l3_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l3_interfaces/l3_interfaces.py
new file mode 100644
index 000000000..c037ef03b
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/l3_interfaces/l3_interfaces.py
@@ -0,0 +1,288 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+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, data=None):
+ """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,
+ data=data,
+ )
+ 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}
+ state = self._module.params["state"]
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_l3_interfaces_facts = self.get_l3_interfaces_facts()
+ else:
+ existing_l3_interfaces_facts = []
+ if state == "gathered":
+ existing_l3_interfaces_facts = self.get_l3_interfaces_facts()
+ result["gathered"] = existing_l3_interfaces_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_l3_interfaces_facts(
+ data=running_config,
+ )
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_l3_interfaces_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ config_xmls = self.set_config(existing_l3_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_l3_interfaces_facts()
+
+ result["before"] = existing_l3_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 in ("merged", "replaced", "overridden", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ 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
+ 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
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp/lacp.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp/lacp.py
new file mode 100644
index 000000000..47ec993e1
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp/lacp.py
@@ -0,0 +1,255 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+ build_subtree,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ 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, data=None):
+ """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,
+ data=data,
+ )
+ 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}
+ state = self._module.params["state"]
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_lacp_facts = self.get_lacp_facts()
+ else:
+ existing_lacp_facts = {}
+ if state == "gathered":
+ existing_lacp_facts = self.get_lacp_facts()
+ result["gathered"] = existing_lacp_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_lacp_facts(data=running_config)
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_lacp_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ 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
+
+ result["warnings"] = warnings
+
+ 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 in ("merged", "replaced", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ 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
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp_interfaces/lacp_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp_interfaces/lacp_interfaces.py
new file mode 100644
index 000000000..79b099988
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lacp_interfaces/lacp_interfaces.py
@@ -0,0 +1,345 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+ build_subtree,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+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, data=None):
+ """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,
+ data=data,
+ )
+ 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}
+ state = self._module.params["state"]
+
+ if self.state in self.ACTION_STATES:
+ existing_lacp_interfaces_facts = self.get_lacp_interfaces_facts()
+ else:
+ existing_lacp_interfaces_facts = []
+
+ if state == "gathered":
+ existing_lacp_interfaces_facts = self.get_lacp_interfaces_facts()
+ result["gathered"] = existing_lacp_interfaces_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_lacp_interfaces_facts(
+ data=running_config,
+ )
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_lacp_interfaces_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ 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_interfaces_facts = self.get_lacp_interfaces_facts()
+
+ result["before"] = existing_lacp_interfaces_facts
+ if result["changed"]:
+ result["after"] = changed_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 in ("merged", "replaced", "overridden", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ 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",
+ )
+ if config["port_priority"] is not None:
+ build_child_xml_node(
+ element,
+ "port-priority",
+ config["port_priority"],
+ )
+ else:
+ build_child_xml_node(
+ element,
+ "port-priority",
+ None,
+ {"delete": "delete"},
+ )
+ if config["force_up"]:
+ build_child_xml_node(element, "force-up")
+ else:
+ build_child_xml_node(
+ element,
+ "force-up",
+ None,
+ {"delete": "delete"},
+ )
+ 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
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lag_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lag_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lag_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lag_interfaces/lag_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lag_interfaces/lag_interfaces.py
new file mode 100644
index 000000000..2b17498ee
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lag_interfaces/lag_interfaces.py
@@ -0,0 +1,365 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+ build_subtree,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.utils.utils import (
+ get_resource_config,
+)
+
+
+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, data=None):
+ """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,
+ data=data,
+ )
+ 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}
+ state = self._module.params["state"]
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_lag_interfaces_facts = self.get_lag_interfaces_facts()
+ else:
+ existing_lag_interfaces_facts = []
+ if state == "gathered":
+ existing_lag_interfaces_facts = self.get_lag_interfaces_facts()
+ result["gathered"] = existing_lag_interfaces_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_lag_interfaces_facts(
+ data=running_config,
+ )
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_lag_interfaces_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ 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, [])
+
+ 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
+
+ result["warnings"] = warnings
+
+ 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 in ("merged", "replaced", "overridden", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ 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>
+ """
+ if self._module.params["state"] != "rendered":
+ 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 self._module.params["state"] != "rendered":
+ 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
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_global/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_global/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_global/lldp_global.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_global/lldp_global.py
new file mode 100644
index 000000000..4efac0315
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_global/lldp_global.py
@@ -0,0 +1,269 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+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, data=None):
+ """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,
+ data=data,
+ )
+ 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}
+ state = self._module.params["state"]
+
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_lldp_global_facts = self.get_lldp_global_facts()
+ else:
+ existing_lldp_global_facts = {}
+ if state == "gathered":
+ existing_lldp_global_facts = self.get_lldp_global_facts()
+ result["gathered"] = existing_lldp_global_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_lldp_global_facts(data=running_config)
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_lldp_global_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ 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
+
+ result["warnings"] = warnings
+
+ 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 in ("merged", "replaced", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ if state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ 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
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_interfaces/lldp_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_interfaces/lldp_interfaces.py
new file mode 100644
index 000000000..262827459
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/lldp_interfaces/lldp_interfaces.py
@@ -0,0 +1,264 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+ build_subtree,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+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, data=None):
+ """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,
+ data=data,
+ )
+ 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}
+ state = self._module.params["state"]
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
+ else:
+ existing_lldp_interfaces_facts = []
+ if state == "gathered":
+ existing_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
+ result["gathered"] = existing_lldp_interfaces_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_lldp_interfaces_facts(
+ data=running_config,
+ )
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_lldp_interfaces_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ 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, [])
+
+ 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
+
+ result["warnings"] = warnings
+
+ 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 in ("merged", "replaced", "overridden", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ 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
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/logging_global/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/logging_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/logging_global/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/logging_global/logging_global.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/logging_global/logging_global.py
new file mode 100644
index 000000000..7411f87e0
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/logging_global/logging_global.py
@@ -0,0 +1,528 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos_logging_global 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.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_empties,
+ to_list,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Logging_global(ConfigBase):
+ """
+ The junos_logging_global class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["logging_global"]
+
+ def __init__(self, module):
+ super(Logging_global, self).__init__(module)
+
+ def get_logging_global_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ logging_global_facts = facts["ansible_network_resources"].get(
+ "logging_global",
+ )
+ if not logging_global_facts:
+ return {}
+ return logging_global_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ state = self._module.params["state"]
+
+ warnings = list()
+
+ if self.state in self.ACTION_STATES or self.state == "purged":
+ existing_logging_global_facts = self.get_logging_global_facts()
+ else:
+ existing_logging_global_facts = {}
+ if state == "gathered":
+ existing_logging_global_facts = self.get_logging_global_facts()
+ result["gathered"] = existing_logging_global_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_logging_global_facts(
+ data=running_config,
+ )
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_logging_global_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+
+ else:
+ diff = None
+ config_xmls = self.set_config(existing_logging_global_facts)
+ with locked_config(self._module):
+ for config_xml in 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_logging_global_facts = self.get_logging_global_facts()
+
+ result["before"] = existing_logging_global_facts
+ if result["changed"]:
+ result["after"] = changed_logging_global_facts
+
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_logging_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_logging_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 commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ self.root = build_root_xml_node("system")
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "rendered", "overridden") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ config_xmls = []
+ if state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ config_xmls = self._state_merged(want, have)
+ elif state == "replaced":
+ config_xmls = self._state_replaced(want, have)
+ elif state == "overridden":
+ config_xmls = self._state_replaced(want, have)
+ for xml in config_xmls:
+ self.root.append(xml)
+ return tostring(self.root)
+
+ def _state_replaced(self, want, have):
+ """The command generator when state is replaced
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ logging_xml = []
+ logging_xml.extend(self._state_deleted(want, have))
+ logging_xml.extend(self._state_merged(want, have))
+ return logging_xml
+
+ def _state_merged(self, want, have):
+ """The command generator when state is merged
+
+ :rtype: A list
+ :returns: the commands necessary to merge the provided into
+ the current configuration
+ """
+ logging_xml = []
+ want = remove_empties(want)
+ level_parser = [
+ "any",
+ "authorization",
+ "change_log",
+ "conflict_log",
+ "daemon",
+ "dfc",
+ "external",
+ "firewall",
+ "ftp",
+ "interactive_commands",
+ "kernel",
+ "ntp",
+ "pfe",
+ "security",
+ "user",
+ ]
+ want = remove_empties(want)
+ logging_node = build_root_xml_node("syslog")
+
+ # add allow-duplicates node
+ if "allow_duplicates" in want.keys() and want.get("allow_duplicates"):
+ build_child_xml_node(logging_node, "allow-duplicates")
+
+ # add archive node
+ if "archive" in want.keys():
+ self.render_archive(logging_node, want)
+
+ # add console node
+ if "console" in want.keys():
+ console = want.get("console")
+ # add any level node
+ for k, v in iteritems(console):
+ if v is not None:
+ console_node = build_child_xml_node(
+ logging_node,
+ "console",
+ )
+ build_child_xml_node(
+ console_node,
+ "name",
+ k.replace("_", "-"),
+ )
+ build_child_xml_node(console_node, v.get("level"))
+
+ # add file node
+ if "files" in want.keys():
+ files = want.get("files")
+ for file in files:
+ file_node = build_child_xml_node(logging_node, "file")
+ # add name node
+ build_child_xml_node(file_node, "name", file.get("name"))
+ # add allow-duplicates node
+ if "allow_duplicates" in file.keys() and file.get(
+ "allow_duplicates",
+ ):
+ build_child_xml_node(file_node, "allow-duplicates")
+ # add contents
+ for k, v in iteritems(file):
+ if k in level_parser and v is not None:
+ content_node = build_child_xml_node(
+ file_node,
+ "contents",
+ )
+ build_child_xml_node(
+ content_node,
+ "name",
+ k.replace("_", "-"),
+ )
+ build_child_xml_node(content_node, v.get("level"))
+ # add archive node
+ if "archive" in file.keys():
+ self.render_archive(file_node, file)
+ # add explicit-priority
+ if "explicit_priority" in file.keys() and file.get(
+ "explicit_priority",
+ ):
+ build_child_xml_node(file_node, "explicit-priority")
+ # add match node
+ if "match" in file.keys():
+ build_child_xml_node(file_node, "match", file.get("match"))
+ # add match-strings node
+ if "match_strings" in file.keys():
+ match_strings = file.get("match_strings")
+ for match in match_strings:
+ build_child_xml_node(file_node, "match-strings", match)
+ # add structured-data
+ if "structured_data" in file.keys():
+ structured_data = file.get("structured_data")
+ s_data_node = build_child_xml_node(
+ file_node,
+ "structured-data",
+ )
+ if "brief" in structured_data.keys() and structured_data.get("brief"):
+ build_child_xml_node(s_data_node, "brief")
+
+ # add host node
+ if "hosts" in want.keys():
+ hosts = want.get("hosts")
+ for host in hosts:
+ host_node = build_child_xml_node(logging_node, "host")
+ # add name node
+ build_child_xml_node(host_node, "name", host.get("name"))
+ # add allow-duplicates node
+ if "allow_duplicates" in host.keys() and host.get(
+ "allow_duplicates",
+ ):
+ build_child_xml_node(host_node, "allow-duplicates")
+ # add contents
+ for k, v in iteritems(host):
+ if k in level_parser and v is not None:
+ content_node = build_child_xml_node(
+ host_node,
+ "contents",
+ )
+ build_child_xml_node(
+ content_node,
+ "name",
+ k.replace("_", "-"),
+ )
+ build_child_xml_node(content_node, v.get("level"))
+ # add exclude-hostname node
+ if "exclude_hostname" in host.keys() and host.get(
+ "exclude_hostname",
+ ):
+ build_child_xml_node(host_node, "exclude-hostname")
+ # add facility_override node
+ if "facility_override" in host.keys():
+ build_child_xml_node(
+ host_node,
+ "facility-override",
+ host.get("facility_override"),
+ )
+ # add log_prefix node
+ if "log_prefix" in host.keys():
+ build_child_xml_node(
+ host_node,
+ "log-prefix",
+ host.get("log_prefix"),
+ )
+ # add match node
+ if "match" in host.keys():
+ build_child_xml_node(host_node, "match", host.get("match"))
+ # add match-strings node
+ if "match_strings" in host.keys():
+ match_strings = host.get("match_strings")
+ for match in match_strings:
+ build_child_xml_node(host_node, "match-strings", match)
+ # add port node
+ if "port" in host.keys():
+ build_child_xml_node(host_node, "port", host.get("port"))
+ # add routing_instance node
+ if "routing_instance" in host.keys():
+ build_child_xml_node(
+ host_node,
+ "routing-instance",
+ host.get("routing_instance"),
+ )
+ # add source_address node
+ if "source_address" in host.keys():
+ build_child_xml_node(
+ host_node,
+ "source-address",
+ host.get("source_address"),
+ )
+ # add structured-data
+ if "structured_data" in host.keys():
+ structured_data = host.get("structured_data")
+ if "set" not in structured_data.keys() or structured_data.get("set"):
+ s_data_node = build_child_xml_node(
+ host_node,
+ "structured-data",
+ )
+ if "brief" in structured_data.keys() and structured_data.get("brief"):
+ build_child_xml_node(s_data_node, "brief")
+
+ # add log_rotate_frequency node
+ if "log_rotate_frequency" in want.keys():
+ build_child_xml_node(
+ logging_node,
+ "log-rotate-frequency",
+ want.get("log_rotate_frequency"),
+ )
+
+ # add routing_instance node
+ if "routing_instance" in want.keys():
+ build_child_xml_node(
+ logging_node,
+ "routing-instance",
+ want.get("routing_instance"),
+ )
+
+ # add server node
+ if "server" in want.keys():
+ server = want.get("server")
+ if "set" not in server.keys() or server.get("set"):
+ server_node = build_child_xml_node(logging_node, "server")
+ if "routing_instance" in server.keys():
+ routing_instance = server.get("routing_instance")
+ if "all" in routing_instance.keys() and routing_instance.get(
+ "all",
+ ):
+ build_child_xml_node(server_node, "all")
+ if "default" in routing_instance.keys() and routing_instance.get("default"):
+ build_child_xml_node(server_node, "default")
+ if "routing_instances" in routing_instance.keys():
+ r_instances = routing_instance.get("routing_instances")
+ for instance in r_instances:
+ instance_node = build_child_xml_node(
+ server_node,
+ "name",
+ instance.get("name"),
+ )
+ if "disable" in instance.keys() and instance.get(
+ "disable",
+ ):
+ build_child_xml_node(instance_node, "disable")
+
+ # add source_address node
+ if "source_address" in want.keys():
+ build_child_xml_node(
+ logging_node,
+ "source-address",
+ want.get("source_address"),
+ )
+
+ # add time_format
+ if "time_format" in want.keys():
+ time_format = want.get("time_format")
+
+ time_node = build_child_xml_node(logging_node, "time-format")
+ if "millisecond" in time_format.keys() and time_format.get(
+ "millisecond",
+ ):
+ build_child_xml_node(time_node, "millisecond")
+ if "year" in time_format.keys() and time_format.get("year"):
+ build_child_xml_node(time_node, "year")
+
+ # add user node
+ if "users" in want.keys():
+ users = want.get("users")
+ for user in users:
+ user_node = build_child_xml_node(logging_node, "user")
+ # add name node
+ build_child_xml_node(user_node, "name", user.get("name"))
+ # add allow-duplicates node
+ if "allow_duplicates" in user.keys() and user.get(
+ "allow_duplicates",
+ ):
+ build_child_xml_node(user_node, "allow-duplicates")
+ # add contents
+ for k, v in iteritems(user):
+ if k in level_parser and v is not None:
+ content_node = build_child_xml_node(
+ user_node,
+ "contents",
+ )
+ build_child_xml_node(
+ content_node,
+ "name",
+ k.replace("_", "-"),
+ )
+ build_child_xml_node(content_node, v.get("level"))
+ # add match node
+ if "match" in user.keys():
+ build_child_xml_node(user_node, "match", user.get("match"))
+ # add match-strings node
+ if "match_strings" in user.keys():
+ match_strings = user.get("match_strings")
+ for match in match_strings:
+ build_child_xml_node(user_node, "match-strings", match)
+
+ if logging_node is not None:
+ logging_xml.append(logging_node)
+ return logging_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
+ """
+ logging_xml = []
+ logging_root = None
+ delete = {"delete": "delete"}
+ if have is not None:
+ logging_root = build_child_xml_node(
+ self.root,
+ "syslog",
+ None,
+ delete,
+ )
+
+ if logging_root is not None:
+ logging_xml.append(logging_root)
+ return logging_xml
+
+ def render_archive(self, root, want):
+ archive = want.get("archive")
+ archive_node = build_child_xml_node(root, "archive")
+
+ # add binary-data node
+ if "binary_data" in archive.keys() and archive.get("binary_data"):
+ build_child_xml_node(archive_node, "binary-data")
+ # add files node
+ if "files" in archive.keys():
+ build_child_xml_node(archive_node, "files", archive.get("files"))
+ # add no-binary-data node
+ if "no_binary_data" in archive.keys() and archive.get(
+ "no_binary_data",
+ ):
+ build_child_xml_node(archive_node, "no-binary-data")
+ # add size node
+ if "file_size" in archive.keys():
+ build_child_xml_node(
+ archive_node,
+ "size",
+ archive.get("file_size"),
+ )
+ # add world-readable node
+ if "world_readable" in archive.keys() and archive.get(
+ "world_readable",
+ ):
+ build_child_xml_node(archive_node, "world-readable")
+ # add no-world-readable node
+ if "no_world_readable" in archive.keys() and archive.get(
+ "no_world_readable",
+ ):
+ build_child_xml_node(archive_node, "no-world-readable")
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ntp_global/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ntp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ntp_global/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ntp_global/ntp_global.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ntp_global/ntp_global.py
new file mode 100644
index 000000000..60da74702
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ntp_global/ntp_global.py
@@ -0,0 +1,388 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos_ntp_global 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_empties,
+ to_list,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Ntp_global(ConfigBase):
+ """
+ The junos_ntp_global class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["ntp_global"]
+
+ def __init__(self, module):
+ super(Ntp_global, self).__init__(module)
+
+ def get_ntp_global_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ ntp_global_facts = facts["ansible_network_resources"].get("ntp_global")
+ if not ntp_global_facts:
+ return {}
+ return ntp_global_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ state = self._module.params["state"]
+
+ warnings = list()
+
+ if self.state in self.ACTION_STATES or self.state == "purged":
+ existing_ntp_global_facts = self.get_ntp_global_facts()
+ else:
+ existing_ntp_global_facts = {}
+ if state == "gathered":
+ existing_ntp_global_facts = self.get_ntp_global_facts()
+ result["gathered"] = existing_ntp_global_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_ntp_global_facts(data=running_config)
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_ntp_global_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+
+ else:
+ diff = None
+ config_xmls = self.set_config(existing_ntp_global_facts)
+ with locked_config(self._module):
+ for config_xml in 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_ntp_global_facts = self.get_ntp_global_facts()
+
+ result["before"] = existing_ntp_global_facts
+ if result["changed"]:
+ result["after"] = changed_ntp_global_facts
+
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_ntp_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_ntp_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 commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ self.root = build_root_xml_node("system")
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "rendered", "overridden") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ config_xmls = []
+ if state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ config_xmls = self._state_merged(want, have)
+ elif state == "replaced":
+ config_xmls = self._state_replaced(want, have)
+ elif state == "overridden":
+ config_xmls = self._state_replaced(want, have)
+ for xml in config_xmls:
+ self.root.append(xml)
+ return tostring(self.root)
+
+ def _state_replaced(self, want, have):
+ """The command generator when state is replaced
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ ntp_xml = []
+ ntp_xml.extend(self._state_deleted(want, have))
+ ntp_xml.extend(self._state_merged(want, have))
+ return ntp_xml
+
+ def _state_merged(self, want, have):
+ """The command generator when state is merged
+
+ :rtype: A list
+ :returns: the commands necessary to merge the provided into
+ the current configuration
+ """
+ ntp_xml = []
+ want = remove_empties(want)
+ ntp_node = build_root_xml_node("ntp")
+
+ # add authentication-keys node
+ if "authentication_keys" in want.keys():
+ auth_keys = want.get("authentication_keys")
+ for key in auth_keys:
+ key_node = build_child_xml_node(ntp_node, "authentication-key")
+ # add name node
+ build_child_xml_node(key_node, "name", key.get("id"))
+ # add type node
+ build_child_xml_node(key_node, "type", key.get("algorithm"))
+ # add value node
+ build_child_xml_node(key_node, "value", key.get("key"))
+
+ # add boot_server node
+ if "boot_server" in want.keys():
+ build_child_xml_node(
+ ntp_node,
+ "boot-server",
+ want.get("boot_server"),
+ )
+
+ # add broadcast node
+ if "broadcasts" in want.keys():
+ broadcasts = want.get("broadcasts")
+ for item in broadcasts:
+ broadcast_node = build_child_xml_node(ntp_node, "broadcast")
+ # add name node
+ build_child_xml_node(
+ broadcast_node,
+ "name",
+ item.get("address"),
+ )
+ # add key node
+ if "key" in item.keys():
+ build_child_xml_node(
+ broadcast_node,
+ "key",
+ item.get("key"),
+ )
+ # add routing-instance-name node
+ if "routing_instance_name" in item.keys():
+ build_child_xml_node(
+ broadcast_node,
+ "routing-instance-name",
+ item.get("routing_instance_name"),
+ )
+ # add ttl node
+ if "ttl" in item.keys():
+ build_child_xml_node(
+ broadcast_node,
+ "ttl",
+ item.get("ttl"),
+ )
+ # add version node
+ if "version" in item.keys():
+ build_child_xml_node(
+ broadcast_node,
+ "version",
+ item.get("version"),
+ )
+
+ # add broadcast_client node
+ if "broadcast_client" in want.keys() and want.get("broadcast_client"):
+ build_child_xml_node(ntp_node, "broadcast-client")
+
+ # add interval_range node
+ if "interval_range" in want.keys():
+ build_child_xml_node(
+ ntp_node,
+ "interval-range",
+ want.get("interval_range"),
+ )
+
+ # add multicast_client node
+ if "multicast_client" in want.keys():
+ build_child_xml_node(
+ ntp_node,
+ "multicast-client",
+ want.get("multicast_client"),
+ )
+
+ # add peers node
+ if "peers" in want.keys():
+ peers = want.get("peers")
+ for item in peers:
+ peer_node = build_child_xml_node(ntp_node, "peer")
+ # add name node
+ build_child_xml_node(peer_node, "name", item.get("peer"))
+ # add key node
+ if "key_id" in item.keys():
+ build_child_xml_node(peer_node, "key", item.get("key_id"))
+ # add prefer node
+ if "prefer" in item.keys() and item.get("prefer"):
+ build_child_xml_node(peer_node, "prefer")
+ # add version node
+ if "version" in item.keys():
+ build_child_xml_node(
+ peer_node,
+ "version",
+ item.get("version"),
+ )
+
+ # add server node
+ if "servers" in want.keys():
+ servers = want.get("servers")
+ for item in servers:
+ server_node = build_child_xml_node(ntp_node, "server")
+ # add name node
+ build_child_xml_node(server_node, "name", item.get("server"))
+ # add key node
+ if "key_id" in item.keys():
+ build_child_xml_node(
+ server_node,
+ "key",
+ item.get("key_id"),
+ )
+ # add routing-instance node
+ if "routing_instance" in item.keys():
+ build_child_xml_node(
+ server_node,
+ "routing-instance",
+ item.get("routing_instance"),
+ )
+ # add prefer node
+ if "prefer" in item.keys() and item.get("prefer"):
+ build_child_xml_node(server_node, "prefer")
+ # add version node
+ if "version" in item.keys():
+ build_child_xml_node(
+ server_node,
+ "version",
+ item.get("version"),
+ )
+ # add source_address node
+ if "source_addresses" in want.keys():
+ source_addresses = want.get("source_addresses")
+ for item in source_addresses:
+ source_node = build_child_xml_node(ntp_node, "source-address")
+ # add name node
+ build_child_xml_node(
+ source_node,
+ "name",
+ item.get("source_address"),
+ )
+ # add routing-instance node
+ if "routing_instance" in item.keys():
+ build_child_xml_node(
+ source_node,
+ "routing-instance",
+ item.get("routing_instance"),
+ )
+ # add threshold node
+ if "threshold" in want.keys():
+ threshold = want.get("threshold")
+ threshold_node = build_child_xml_node(ntp_node, "threshold")
+ if "value" in threshold.keys():
+ build_child_xml_node(
+ threshold_node,
+ "value",
+ threshold.get("value"),
+ )
+ if "action" in threshold.keys():
+ build_child_xml_node(
+ threshold_node,
+ "action",
+ threshold.get("action"),
+ )
+
+ # add trusted key
+ if "trusted_keys" in want.keys():
+ trusted_keys = want.get("trusted_keys")
+ for key in trusted_keys:
+ build_child_xml_node(ntp_node, "trusted-key", key["key_id"])
+
+ if ntp_node is not None:
+ ntp_xml.append(ntp_node)
+ return ntp_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
+ """
+ ntp_xml = []
+ ntp_root = None
+ delete = {"delete": "delete"}
+ if have is not None:
+ ntp_root = build_child_xml_node(self.root, "ntp", None, delete)
+
+ if ntp_root is not None:
+ ntp_xml.append(ntp_root)
+ return ntp_xml
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospf_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospf_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospf_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospf_interfaces/ospf_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospf_interfaces/ospf_interfaces.py
new file mode 100644
index 000000000..2cbc8f24f
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospf_interfaces/ospf_interfaces.py
@@ -0,0 +1,362 @@
+#
+# -*- 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_ospf_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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_empties,
+ to_list,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Ospf_interfaces(ConfigBase):
+ """
+ The junos_ospf_interfaces class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["ospf_interfaces"]
+
+ def __init__(self, module):
+ super(Ospf_interfaces, self).__init__(module)
+
+ def get_ospf_interfaces_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ ospf_interfaces_facts = facts["ansible_network_resources"].get(
+ "junos_ospf_interfaces",
+ )
+ if not ospf_interfaces_facts:
+ return []
+ return ospf_interfaces_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ state = self._module.params["state"]
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_ospf_interfaces_facts = self.get_ospf_interfaces_facts()
+ else:
+ existing_ospf_interfaces_facts = []
+ if state == "gathered":
+ existing_ospf_interfaces_facts = self.get_ospf_interfaces_facts()
+ result["gathered"] = existing_ospf_interfaces_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_ospf_interfaces_facts(
+ data=running_config,
+ )
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_ospf_interfaces_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ config_xmls = self.set_config(existing_ospf_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_ospf_interfaces_facts = self.get_ospf_interfaces_facts()
+
+ result["before"] = existing_ospf_interfaces_facts
+ if result["changed"]:
+ result["after"] = changed_ospf_interfaces_facts
+
+ result["warnings"] = warnings
+ return result
+
+ def set_config(self, existing_ospf_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_ospf_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
+ """
+ self.router_id = None
+ self.root = build_root_xml_node("configuration")
+ self.protocols = build_child_xml_node(self.root, "protocols")
+ self.routing_options = build_child_xml_node(
+ self.root,
+ "routing-options",
+ )
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "overridden", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ config_xmls = []
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ config_xmls = self._state_merged(want, have)
+ elif state == "replaced":
+ config_xmls = self._state_replaced(want, have)
+
+ for xml in config_xmls:
+ self.protocols.append(xml)
+
+ return [tostring(xml) for xml in self.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
+ """
+ ospf_interfaces_xml = []
+ ospf_interfaces_xml.extend(self._state_deleted(want, have))
+ ospf_interfaces_xml.extend(self._state_merged(want, have))
+ return ospf_interfaces_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
+ """
+ ospf_interfaces_xml = []
+ ospf_interfaces_xml.extend(self._state_deleted(None, have))
+ ospf_interfaces_xml.extend(self._state_merged(want, have))
+ return ospf_interfaces_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
+ """
+ ospf_interfaces_xml = []
+ delete = {"delete": "delete"}
+ protocol = build_root_xml_node("ospf")
+ if not want:
+ for h in have:
+ for af in h["address_family"]:
+ area_node = build_child_xml_node(protocol, "area")
+ processes = af.get("processes")
+ area = processes.get("area")
+ area_id = area.get("area_id")
+ build_child_xml_node(area_node, "name", area_id)
+ ospf_interfacesnode = build_child_xml_node(
+ area_node,
+ "interface",
+ )
+ build_child_xml_node(
+ ospf_interfacesnode,
+ "name",
+ h.get("name"),
+ )
+ ospf_interfacesnode.attrib.update(delete)
+ else:
+ for w in want:
+ for h in have:
+ if h["name"] == w["name"]:
+ for af in h["address_family"]:
+ area_node = build_child_xml_node(protocol, "area")
+ processes = af.get("processes")
+ area = processes.get("area")
+ area_id = area.get("area_id")
+ build_child_xml_node(area_node, "name", area_id)
+ ospf_interfacesnode = build_child_xml_node(
+ area_node,
+ "interface",
+ )
+ build_child_xml_node(
+ ospf_interfacesnode,
+ "name",
+ h.get("name"),
+ )
+ ospf_interfacesnode.attrib.update(delete)
+ ospf_interfaces_xml.append(protocol)
+ return ospf_interfaces_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
+ """
+ ospf_interfaces_xml = []
+ protocol = build_root_xml_node("ospf")
+ for ospf_interfaces in want:
+ ospf_interfaces = remove_empties(ospf_interfaces)
+ if "router_id" in ospf_interfaces.keys():
+ self.router_id = ospf_interfaces.get("router_id")
+ build_child_xml_node(
+ self.routing_options,
+ "router-id",
+ self.router_id,
+ )
+ for af in ospf_interfaces["address_family"]:
+ area_node = build_child_xml_node(protocol, "area")
+ processes = af.get("processes")
+ area = processes.get("area")
+ area_id = area.get("area_id")
+ build_child_xml_node(area_node, "name", area_id)
+
+ intf_node = build_child_xml_node(area_node, "interface")
+ build_child_xml_node(
+ intf_node,
+ "name",
+ ospf_interfaces.get("name"),
+ )
+ if delete:
+ if have:
+ existing_config = have[0]
+ if existing_config["name"] == ospf_interfaces["name"]:
+ intf_node.attrib.update(delete)
+ if processes.get("priority"):
+ build_child_xml_node(
+ intf_node,
+ "priority",
+ processes.get("priority"),
+ )
+ if processes.get("flood_reduction"):
+ build_child_xml_node(intf_node, "flood-reduction")
+
+ if processes.get("metric"):
+ build_child_xml_node(
+ intf_node,
+ "metric",
+ processes.get("metric"),
+ )
+
+ if processes.get("passive"):
+ build_child_xml_node(intf_node, "passive")
+
+ if processes.get("bandwidth_based_metrics"):
+ bw_metrics_node = build_child_xml_node(
+ intf_node,
+ "bandwidth-based-metrics",
+ )
+ bw_metrics = processes.get("bandwidth_based_metrics")
+ for bw_metric in bw_metrics:
+ bw_metric_node = build_child_xml_node(
+ bw_metrics_node,
+ "bandwidth",
+ )
+ build_child_xml_node(
+ bw_metric_node,
+ "name",
+ bw_metric.get("bandwidth"),
+ )
+ build_child_xml_node(
+ bw_metric_node,
+ "metric",
+ bw_metric.get("metric"),
+ )
+ if processes.get("dead_interval"):
+ build_child_xml_node(
+ intf_node,
+ "dead-interval",
+ processes.get("dead_interval"),
+ )
+ if processes.get("hello_interval"):
+ build_child_xml_node(
+ intf_node,
+ "hello-interval",
+ processes.get("hello_interval"),
+ )
+ if processes.get("poll_interval"):
+ build_child_xml_node(
+ intf_node,
+ "poll-interval",
+ processes.get("poll_interval"),
+ )
+ if processes.get("retransmit_interval"):
+ build_child_xml_node(
+ intf_node,
+ "retransmit-interval",
+ processes.get("retransmit_interval"),
+ )
+
+ ospf_interfaces_xml.append(protocol)
+ return ospf_interfaces_xml
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv2/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv2/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv2/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv2/ospfv2.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv2/ospfv2.py
new file mode 100644
index 000000000..23730746f
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv2/ospfv2.py
@@ -0,0 +1,439 @@
+# Copyright (C) 2020 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_ospfv2 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_empties,
+ to_list,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Ospfv2(ConfigBase):
+ """
+ The junos_ospfv2 class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["ospf"]
+
+ def __init__(self, module):
+ super(Ospfv2, self).__init__(module)
+
+ def get_ospf_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ ospf_facts = facts["ansible_network_resources"].get("ospfv2")
+ if not ospf_facts:
+ return []
+ return ospf_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ state = self._module.params["state"]
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_ospf_facts = self.get_ospf_facts()
+ else:
+ existing_ospf_facts = []
+ if state == "gathered":
+ existing_ospf_facts = self.get_ospf_facts()
+ result["gathered"] = existing_ospf_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_ospf_facts(data=running_config)
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_ospf_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ config_xmls = self.set_config(existing_ospf_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 config_xmls and 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_ospf_facts = self.get_ospf_facts()
+
+ result["before"] = existing_ospf_facts
+ if result["changed"]:
+ result["after"] = changed_ospf_facts
+
+ result["warnings"] = warnings
+ return result
+
+ def set_config(self, existing_ospf_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_ospf_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
+ """
+ self.router_id = None
+ self.root = build_root_xml_node("configuration")
+ self.protocols = build_child_xml_node(self.root, "protocols")
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "overridden", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ config_xmls = []
+ commands = []
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ config_xmls = self._state_merged(want, have)
+ elif state == "replaced":
+ config_xmls = self._state_replaced(want, have)
+
+ if config_xmls:
+ for xml in config_xmls:
+ self.protocols.append(xml)
+
+ commands = [tostring(xml) for xml in self.root.getchildren()]
+ return commands
+ # return [tostring(xml) for xml in self.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
+ """
+ ospf_xml = []
+ ospf_xml.extend(self._state_deleted(want, have))
+ ospf_xml.extend(self._state_merged(want, have))
+ return ospf_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
+ """
+ ospf_xml = []
+ ospf_xml.extend(self._state_deleted(want, have))
+ ospf_xml.extend(self._state_merged(want, have))
+ return ospf_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
+ """
+ ospf_xml = []
+ delete = {"delete": "delete"}
+ if have:
+ for have_ospf in have:
+ have_areas = have_ospf.get("areas") or []
+ for area in have_areas:
+ ospf_node = build_child_xml_node(self.protocols, "ospf")
+ area_node = build_child_xml_node(
+ ospf_node,
+ "area",
+ area["area_id"],
+ )
+ area_node.attrib.update(delete)
+ ospf_xml.append(ospf_node)
+ return ospf_xml
+
+ def _state_merged(self, want, have):
+ """The command generator when state is merged
+
+ :rtype: A list
+ :returns: the xml necessary to migrate the current configuration
+ to the desired configuration
+ """
+ ospf_xml = []
+ protocol = build_root_xml_node("ospf")
+ for ospf in want:
+ ospf = remove_empties(ospf)
+ if "router_id" in ospf.keys():
+ self.routing_options = build_child_xml_node(
+ self.root,
+ "routing-options",
+ )
+ ospf = remove_empties(ospf)
+ self.router_id = ospf.get("router_id")
+ build_child_xml_node(
+ self.routing_options,
+ "router-id",
+ self.router_id,
+ )
+
+ if ospf.get("spf_options"):
+ spf_options_node = build_child_xml_node(
+ protocol,
+ "spf-options",
+ )
+
+ if ospf["spf_options"].get("delay"):
+ build_child_xml_node(
+ spf_options_node,
+ "delay",
+ ospf["spf_options"].get("delay"),
+ )
+
+ if ospf["spf_options"].get("holddown"):
+ build_child_xml_node(
+ spf_options_node,
+ "holddown",
+ ospf["spf_options"].get("holddown"),
+ )
+
+ if ospf["spf_options"].get("delay"):
+ build_child_xml_node(
+ spf_options_node,
+ "rapid-runs",
+ ospf["spf_options"].get("rapid_runs"),
+ )
+
+ if ospf.get("overload"):
+ overload_node = build_child_xml_node(protocol, "overload")
+ if ospf["overload"].get("timeout"):
+ build_child_xml_node(
+ overload_node,
+ "timeout",
+ ospf["overload"].get("timeout"),
+ )
+
+ if ospf.get("external_preference"):
+ build_child_xml_node(
+ protocol,
+ "external-preference",
+ ospf["external_preference"],
+ )
+
+ if ospf.get("preference"):
+ build_child_xml_node(
+ protocol,
+ "preference",
+ ospf["preference"],
+ )
+
+ if ospf.get("prefix_export_limit"):
+ build_child_xml_node(
+ protocol,
+ "prefix-export-limit",
+ ospf["prefix_export_limit"],
+ )
+
+ if ospf.get("reference_bandwidth"):
+ build_child_xml_node(
+ protocol,
+ "reference-bandwidth",
+ ospf.get("reference_bandwidth"),
+ )
+
+ if "rfc1583compatibility" in ospf.keys():
+ if not ospf["rfc1583compatibility"]:
+ build_child_xml_node(protocol, "no-rfc-1583")
+
+ if "areas" in ospf.keys():
+ for area in ospf["areas"]:
+ area_node = build_child_xml_node(protocol, "area")
+ area_id = area.get("area_id")
+ build_child_xml_node(area_node, "name", area_id)
+ if area.get("area_range"):
+ area_range_node = build_child_xml_node(
+ area_node,
+ "area-range",
+ )
+ build_child_xml_node(
+ area_range_node,
+ "name",
+ area["area_range"],
+ )
+
+ for intf in area.get("interfaces"):
+ intf_node = build_child_xml_node(
+ area_node,
+ "interface",
+ )
+ build_child_xml_node(
+ intf_node,
+ "name",
+ intf.get("name"),
+ )
+
+ if intf.get("priority"):
+ build_child_xml_node(
+ intf_node,
+ "priority",
+ intf.get("priority"),
+ )
+
+ if intf.get("flood_reduction"):
+ build_child_xml_node(
+ intf_node,
+ "flood-reduction",
+ None,
+ )
+
+ if intf.get("metric"):
+ build_child_xml_node(
+ intf_node,
+ "metric",
+ intf["metric"],
+ )
+
+ if intf.get("passive"):
+ build_child_xml_node(intf_node, "passive")
+
+ if intf.get("bandwidth_based_metrics"):
+ bw_metrics_node = build_child_xml_node(
+ intf_node,
+ "bandwidth-based-metrics",
+ )
+ bw_metrics = intf.get("bandwidth_based_metrics")
+ for bw_metric in bw_metrics:
+ bw_metric_node = build_child_xml_node(
+ bw_metrics_node,
+ "bandwidth",
+ )
+ build_child_xml_node(
+ bw_metric_node,
+ "name",
+ bw_metric.get("bandwidth"),
+ )
+ build_child_xml_node(
+ bw_metric_node,
+ "metric",
+ bw_metric.get("metric"),
+ )
+ if intf.get("timers"):
+ if intf["timers"].get("dead_interval"):
+ build_child_xml_node(
+ intf_node,
+ "dead-interval",
+ intf["timers"].get("dead_interval"),
+ )
+ if intf["timers"].get("hello_interval"):
+ build_child_xml_node(
+ intf_node,
+ "hello-interval",
+ intf["timers"].get("hello_interval"),
+ )
+ if intf["timers"].get("poll_interval"):
+ build_child_xml_node(
+ intf_node,
+ "poll-interval",
+ intf["timers"].get("poll_interval"),
+ )
+ if intf["timers"].get("retransmit_interval"):
+ build_child_xml_node(
+ intf_node,
+ "retransmit-interval",
+ intf["timers"].get("retransmit_interval"),
+ )
+
+ if area.get("stub"):
+ if area["stub"]["set"]:
+ stub_node = build_child_xml_node(area_node, "stub")
+ if area["stub"].get("default_metric"):
+ build_child_xml_node(
+ stub_node,
+ "default-metric",
+ area["stub"].get("default_metric"),
+ )
+
+ ospf_xml.append(protocol)
+ return ospf_xml
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv3/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv3/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv3/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv3/ospfv3.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv3/ospfv3.py
new file mode 100644
index 000000000..a9aea34ec
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/ospfv3/ospfv3.py
@@ -0,0 +1,454 @@
+# Copyright (C) 2020 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_ospfv3 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_empties,
+ to_list,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Ospfv3(ConfigBase):
+ """
+ The junos_ospfv3 class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["ospfv3"]
+
+ def __init__(self, module):
+ super(Ospfv3, self).__init__(module)
+
+ def get_ospfv3_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ ospfv3_facts = facts["ansible_network_resources"].get("junos_ospfv3")
+ if not ospfv3_facts:
+ return []
+ return ospfv3_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ state = self._module.params["state"]
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_ospfv3_facts = self.get_ospfv3_facts()
+ else:
+ existing_ospfv3_facts = []
+ if state == "gathered":
+ existing_ospfv3_facts = self.get_ospfv3_facts()
+ result["gathered"] = existing_ospfv3_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_ospfv3_facts(data=running_config)
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_ospfv3_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ config_xmls = self.set_config(existing_ospfv3_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_ospfv3_facts = self.get_ospfv3_facts()
+
+ result["before"] = existing_ospfv3_facts
+ if result["changed"]:
+ result["after"] = changed_ospfv3_facts
+
+ result["warnings"] = warnings
+ return result
+
+ def set_config(self, existing_ospfv3_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_ospfv3_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
+ """
+ self.router_id = None
+ self.root = build_root_xml_node("configuration")
+ self.protocols = build_child_xml_node(self.root, "protocols")
+ self.routing_options = build_child_xml_node(
+ self.root,
+ "routing-options",
+ )
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "overridden", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ config_xmls = []
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ config_xmls = self._state_merged(want, have)
+ elif state == "replaced":
+ config_xmls = self._state_replaced(want, have)
+
+ for xml in config_xmls:
+ self.protocols.append(xml)
+
+ return [tostring(xml) for xml in self.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
+ """
+ ospfv3_xml = []
+ ospfv3_xml.extend(self._state_deleted(want, have))
+ ospfv3_xml.extend(self._state_merged(want, have))
+ return ospfv3_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
+ """
+ ospfv3_xml = []
+ ospfv3_xml.extend(self._state_deleted(None, have))
+ ospfv3_xml.extend(self._state_merged(want, have))
+ return ospfv3_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
+ """
+ ospfv3_xml = []
+ delete = {"delete": "delete"}
+
+ if not want:
+ ospfv3node = build_child_xml_node(self.protocols, "ospf3")
+ ospfv3node.attrib.update(delete)
+ if have:
+ router_id = have[0].get("router_id")
+ if router_id:
+ build_child_xml_node(
+ self.routing_options,
+ "router-id",
+ self.router_id,
+ attrib=delete,
+ )
+ return ospfv3node
+
+ ospfv3_xml = self._state_merged(want, have, delete=delete)
+ return ospfv3_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
+ """
+ ospfv3_xml = []
+ protocol = build_root_xml_node("ospf3")
+ for ospfv3 in want:
+ ospfv3 = remove_empties(ospfv3)
+ if "router_id" in ospfv3.keys():
+ self.router_id = ospfv3.get("router_id")
+ build_child_xml_node(
+ self.routing_options,
+ "router-id",
+ self.router_id,
+ )
+
+ if ospfv3.get("spf_options"):
+ spf_options_node = build_child_xml_node(
+ protocol,
+ "spf-options",
+ )
+ if delete and not ospfv3.get("spf_options").values():
+ spf_options_node.attrib.update(delete)
+
+ if ospfv3["spf_options"].get("delay"):
+ delay_node = build_child_xml_node(
+ spf_options_node,
+ "delay",
+ ospfv3["spf_options"].get("delay"),
+ )
+ if delete:
+ delay_node.attrib.update(delete)
+
+ if ospfv3["spf_options"].get("holddown"):
+ holddown_node = build_child_xml_node(
+ spf_options_node,
+ "holddown",
+ ospfv3["spf_options"].get("holddown"),
+ )
+ if delete:
+ holddown_node.attrib.update(delete)
+
+ if ospfv3["spf_options"].get("delay"):
+ delay_node = build_child_xml_node(
+ spf_options_node,
+ "rapid-runs",
+ ospfv3["spf_options"].get("rapid_runs"),
+ )
+ if delete:
+ delay_node.attrib.update(delete)
+
+ if ospfv3.get("overload"):
+ overload_node = build_child_xml_node(protocol, "overload")
+ if ospfv3["overload"].get("timeout"):
+ build_child_xml_node(
+ overload_node,
+ "timeout",
+ ospfv3["overload"].get("timeout"),
+ )
+ if delete:
+ overload_node.attrib.update(delete)
+
+ if ospfv3.get("external_preference"):
+ ext_pref_node = build_child_xml_node(
+ protocol,
+ "external-preference",
+ ospfv3["externall_preference"],
+ )
+ if delete:
+ ext_pref_node.attrib.update(delete)
+
+ if ospfv3.get("preference"):
+ pref_node = build_child_xml_node(
+ protocol,
+ "preference",
+ ospfv3["preference"],
+ )
+ if delete:
+ pref_node.attrib.update(delete)
+
+ if ospfv3.get("prefix_export_limit"):
+ prefix_export_node = build_child_xml_node(
+ protocol,
+ "prefix-export-limit",
+ ospfv3["prefix_export_limit"],
+ )
+ if delete:
+ prefix_export_node.attrib.update(delete)
+
+ if ospfv3.get("reference_bandwidth"):
+ ref_bw_node = build_child_xml_node(
+ protocol,
+ "reference-bandwidth",
+ ospfv3.get("reference_bandwidth"),
+ )
+ if delete:
+ ref_bw_node.attrib.update(delete)
+
+ if "rfc1583compatibility" in ospfv3.keys():
+ if not ospfv3["rfc1583compatibility"]:
+ build_child_xml_node(protocol, "no-rfc-1583")
+
+ for area in ospfv3["areas"]:
+ area_node = build_child_xml_node(protocol, "area")
+ area_id = area.get("area_id")
+ build_child_xml_node(area_node, "name", area_id)
+ if area.get("area_range"):
+ area_range_node = build_child_xml_node(
+ area_node,
+ "area-range",
+ )
+ build_child_xml_node(
+ area_range_node,
+ "name",
+ area["area_range"],
+ )
+ if delete:
+ area_range_node.attrib.update(delete)
+
+ for intf in area.get("interfaces"):
+ intf_node = build_child_xml_node(area_node, "interface")
+ build_child_xml_node(intf_node, "name", intf.get("name"))
+ if delete:
+ if have:
+ existing_config = have[0]
+ for existing_area in existing_config["areas"]:
+ if existing_area["area_id"] == area_id:
+ if len(existing_area["interfaces"]) == 1:
+ area_node.attrib.update(delete)
+ else:
+ intf_node.attrib.update(delete)
+
+ if intf.get("priority"):
+ build_child_xml_node(
+ intf_node,
+ "priority",
+ intf.get("priority"),
+ )
+
+ if intf.get("flood_reduction"):
+ build_child_xml_node(intf_node, "flood-reduction")
+
+ if intf.get("metric"):
+ build_child_xml_node(
+ intf_node,
+ "metric",
+ intf["metric"],
+ )
+
+ if intf.get("passive"):
+ build_child_xml_node(intf_node, "passive")
+
+ if intf.get("bandwidth_based_metrics"):
+ bw_metrics_node = build_child_xml_node(
+ intf_node,
+ "bandwidth-based-metrics",
+ )
+ bw_metrics = intf.get("bandwidth_based_metrics")
+ for bw_metric in bw_metrics:
+ bw_metric_node = build_child_xml_node(
+ bw_metrics_node,
+ "bandwidth",
+ )
+ build_child_xml_node(
+ bw_metric_node,
+ "name",
+ bw_metric.get("bandwidth"),
+ )
+ build_child_xml_node(
+ bw_metric_node,
+ "metric",
+ bw_metric.get("metric"),
+ )
+ if intf.get("timers"):
+ if intf["timers"].get("dead_interval"):
+ build_child_xml_node(
+ intf_node,
+ "dead-interval",
+ intf["timers"].get("dead_interval"),
+ )
+ if intf["timers"].get("hello_interval"):
+ build_child_xml_node(
+ intf_node,
+ "hello-interval",
+ intf["timers"].get("hello_interval"),
+ )
+ if intf["timers"].get("poll_interval"):
+ build_child_xml_node(
+ intf_node,
+ "poll-interval",
+ intf["timers"].get("poll_interval"),
+ )
+ if intf["timers"].get("retransmit_interval"):
+ build_child_xml_node(
+ intf_node,
+ "retransmit-interval",
+ intf["timers"].get("retransmit_interval"),
+ )
+
+ if area.get("stub"):
+ if area["stub"]["set"]:
+ stub_node = build_child_xml_node(area_node, "stub")
+ if area["stub"].get("default_metric"):
+ build_child_xml_node(
+ stub_node,
+ "default-metric",
+ area["stub"].get("default_metric"),
+ )
+ ospfv3_xml.append(protocol)
+ return ospfv3_xml
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/prefix_lists/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/prefix_lists/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/prefix_lists/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/prefix_lists/prefix_lists.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/prefix_lists/prefix_lists.py
new file mode 100644
index 000000000..e98a272d8
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/prefix_lists/prefix_lists.py
@@ -0,0 +1,280 @@
+#
+# -*- 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_prefix_lists 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_empties,
+ to_list,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Prefix_lists(ConfigBase):
+ """
+ The junos_prefix_lists class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["prefix_lists"]
+
+ def __init__(self, module):
+ super(Prefix_lists, self).__init__(module)
+
+ def get_prefix_lists_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ prefix_lists_facts = facts["ansible_network_resources"].get(
+ "prefix_lists",
+ )
+ if not prefix_lists_facts:
+ return []
+ return prefix_lists_facts
+
+ def execute_module(self):
+ """Execute the module
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ state = self._module.params["state"]
+
+ warnings = list()
+
+ if self.state in self.ACTION_STATES or self.state == "purged":
+ existing_prefix_lists_facts = self.get_prefix_lists_facts()
+ else:
+ existing_prefix_lists_facts = {}
+ if state == "gathered":
+ existing_prefix_lists_facts = self.get_prefix_lists_facts()
+ result["gathered"] = existing_prefix_lists_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_prefix_lists_facts(data=running_config)
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_prefix_lists_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ diff = None
+ config_xmls = self.set_config(existing_prefix_lists_facts)
+ with locked_config(self._module):
+ for config_xml in 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_prefix_lists_facts = self.get_prefix_lists_facts()
+
+ result["before"] = existing_prefix_lists_facts
+ if result["changed"]:
+ result["after"] = changed_prefix_lists_facts
+
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_prefix_lists_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_prefix_lists_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
+ """
+ self.root = build_root_xml_node("policy-options")
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "rendered", "overridden") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ config_xmls = []
+ if state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ config_xmls = self._state_merged(want, have)
+ elif state == "replaced":
+ config_xmls = self._state_replaced(want, have)
+ elif state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+
+ for xml in config_xmls:
+ self.root.append(xml)
+ return tostring(self.root)
+
+ def _state_replaced(self, want, have):
+ """The command generator when state is replaced
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ rinst_xml = []
+ rinst_xml.extend(self._state_deleted(want, have))
+ rinst_xml.extend(self._state_merged(want, have))
+
+ return rinst_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
+ """
+ plist_xml = []
+ delete = {"delete": "delete"}
+ if have is not None:
+ have_plist = [entry["name"] for entry in have]
+ want_plist = [entry["name"] for entry in want]
+
+ for instance in have_plist:
+ if instance not in want_plist:
+ plist_node = build_root_xml_node("prefix-list")
+ build_child_xml_node(plist_node, "name", instance)
+ plist_node.attrib.update(delete)
+ plist_xml.append(plist_node)
+ plist_xml.extend(self._state_deleted(want, have))
+ plist_xml.extend(self._state_merged(want, have))
+
+ return plist_xml
+
+ def _state_merged(self, want, have):
+ """The command generator when state is merged
+ :rtype: A list
+ :returns: the commands necessary to merge the provided into
+ the current configuration
+ """
+ prefix_list_xml = []
+ for instance in want:
+ instance = remove_empties(instance)
+
+ # generate node: prefix-list
+ prefix_root = build_root_xml_node("prefix-list")
+
+ # generate node: name
+ if "name" in instance.keys():
+ build_child_xml_node(prefix_root, "name", instance.get("name"))
+
+ # generate node: prefix-list-item
+ if "address_prefixes" in instance.keys():
+ address_prefixes = instance.get("address_prefixes")
+
+ for entry in address_prefixes:
+ add_prefix_node = build_child_xml_node(
+ prefix_root,
+ "prefix-list-item",
+ )
+ # generate name node
+ build_child_xml_node(add_prefix_node, "name", entry)
+
+ # generate node: dynamic_db
+ if "dynamic_db" in instance.keys() and instance.get("dynamic_db"):
+ build_child_xml_node(prefix_root, "dynamic-db")
+
+ prefix_list_xml.append(prefix_root)
+
+ return prefix_list_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
+ """
+ plist_xml = []
+ existing_plist = []
+ plist_node = None
+ delete = {"delete": "delete"}
+ if have is not None:
+ # get the instances in running config
+ # form existing instance list
+ for h_rinst in have:
+ existing_plist.append(h_rinst["name"])
+
+ # Delete target routing-instance
+ if want:
+ for entry in want:
+ if entry["name"] not in existing_plist:
+ continue
+ plist_node = build_root_xml_node("prefix-list")
+ build_child_xml_node(plist_node, "name", entry["name"])
+ plist_node.attrib.update(delete)
+ plist_xml.append(plist_node)
+
+ else:
+ # Delete all the routing-instance
+ plist_node = build_root_xml_node("prefix-list")
+ plist_node.attrib.update(delete)
+ plist_xml.append(plist_node)
+
+ if plist_node is not None:
+ plist_xml.append(plist_node)
+ return plist_xml
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_instances/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_instances/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_instances/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_instances/routing_instances.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_instances/routing_instances.py
new file mode 100644
index 000000000..445454d57
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_instances/routing_instances.py
@@ -0,0 +1,365 @@
+#
+# -*- 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_routing_instances 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Routing_instances(ConfigBase):
+ """
+ The junos_routing_instances class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["routing_instances"]
+
+ def __init__(self, module):
+ super(Routing_instances, self).__init__(module)
+
+ def get_routing_instances_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ routing_instances_facts = facts["ansible_network_resources"].get(
+ "routing_instances",
+ )
+ if not routing_instances_facts:
+ return []
+ return routing_instances_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ state = self._module.params["state"]
+
+ warnings = list()
+
+ if self.state in self.ACTION_STATES or self.state == "purged":
+ existing_routing_instances_facts = self.get_routing_instances_facts()
+ else:
+ existing_routing_instances_facts = {}
+ if state == "gathered":
+ existing_routing_instances_facts = self.get_routing_instances_facts()
+ result["gathered"] = existing_routing_instances_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_routing_instances_facts(
+ data=running_config,
+ )
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_routing_instances_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ diff = None
+ config_xmls = self.set_config(existing_routing_instances_facts)
+ with locked_config(self._module):
+ for config_xml in 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_routing_instances_facts = self.get_routing_instances_facts()
+
+ result["before"] = existing_routing_instances_facts
+ if result["changed"]:
+ result["after"] = changed_routing_instances_facts
+
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_routing_instances_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_routing_instances_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
+ """
+ self.root = build_root_xml_node("routing-instances")
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "rendered", "overridden") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ config_xmls = []
+ if state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ config_xmls = self._state_merged(want, have)
+ elif state == "replaced":
+ config_xmls = self._state_replaced(want, have)
+ elif state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ for xml in config_xmls:
+ self.root.append(xml)
+ return tostring(self.root)
+
+ def _state_replaced(self, want, have):
+ """The command generator when state is replaced
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ rinst_xml = []
+ rinst_xml.extend(self._state_deleted(want, have))
+ rinst_xml.extend(self._state_merged(want, have))
+
+ return rinst_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
+ """
+ rinst_xml = []
+ delete = {"delete": "delete"}
+ if have is not None:
+ have_rinst = [instance["name"] for instance in have]
+ want_rinst = [instance["name"] for instance in want]
+
+ for instance in have_rinst:
+ if instance not in want_rinst:
+ rinstance_node = build_root_xml_node("instance")
+ build_child_xml_node(rinstance_node, "name", instance)
+ rinstance_node.attrib.update(delete)
+ rinst_xml.append(rinstance_node)
+ rinst_xml.extend(self._state_deleted(want, have))
+ rinst_xml.extend(self._state_merged(want, have))
+
+ return rinst_xml
+
+ def _state_merged(self, want, have):
+ """The command generator when state is merged
+
+ :rtype: A list
+ :returns: the commands necessary to merge the provided into
+ the current configuration
+ """
+ instance_xml = []
+ rinst_node = None
+ for instance in want:
+ rinst_node = build_root_xml_node("instance")
+
+ # add node routing table-name
+ build_child_xml_node(rinst_node, "name", instance["name"])
+
+ # add node connector-id-advertise
+ if instance.get("connector_id_advertise"):
+ build_child_xml_node(rinst_node, "connector-id-advertise")
+
+ # add node description
+ if instance.get("description"):
+ build_child_xml_node(
+ rinst_node,
+ "description",
+ instance["description"],
+ )
+
+ # add node instance-role
+ if instance.get("instance_role"):
+ build_child_xml_node(
+ rinst_node,
+ "instance-role",
+ instance["insatnce_role"],
+ )
+
+ # add node instance-type
+ if instance.get("type"):
+ build_child_xml_node(
+ rinst_node,
+ "instance-type",
+ instance["type"],
+ )
+
+ # add child node interface
+ if instance.get("interfaces"):
+ interfaces = instance.get("interfaces")
+ for interface in interfaces:
+ int_node = build_child_xml_node(rinst_node, "interface")
+ if interface.get("protect_interface"):
+ build_child_xml_node(
+ int_node,
+ "protect-interface",
+ interface["protect-interface"],
+ )
+ build_child_xml_node(int_node, "name", interface["name"])
+
+ # add node l2vpn-id TODO
+ if instance.get("l2vpn_id"):
+ build_child_xml_node(
+ rinst_node,
+ "l2vpn-id",
+ instance["l2vpn_id"],
+ )
+
+ # add node no-irb-layer2-copy
+ if instance.get("no_irb_layer2_copy"):
+ build_child_xml_node(rinst_node, "no-irb-layer2-copy")
+
+ # add node no-local-switching
+ if instance.get("no_local_switching"):
+ build_child_xml_node(rinst_node, "no-local-switching")
+
+ # add node no-vrf-advertise
+ if instance.get("no_vrf_advertise"):
+ build_child_xml_node(rinst_node, "no-vrf-advertise")
+
+ # add node no-vrf-propagate-ttl
+ if instance.get("no_vrf_propagate_ttl"):
+ build_child_xml_node(rinst_node, "no-vrf-propagate-ttl")
+
+ # add node qualified-bum-pruning-mode
+ if instance.get("qualified_bum_pruning_mode"):
+ build_child_xml_node(rinst_node, "qualified-bum-pruning-mode")
+
+ # add node route-distinguisher
+ if instance.get("route_distinguisher"):
+ rd_instance = build_child_xml_node(
+ rinst_node,
+ "route-distinguisher",
+ )
+ build_child_xml_node(
+ rd_instance,
+ "rd-type",
+ instance.get("route_distinguisher"),
+ )
+
+ # add node vrf-import
+ if instance.get("vrf_imports"):
+ vrf_imports = instance.get("vrf_imports")
+ for vrf in vrf_imports:
+ build_child_xml_node(rinst_node, "vrf-import", vrf)
+
+ # add node vrf-export
+ if instance.get("vrf_exports"):
+ vrf_exports = instance.get("vrf_exports")
+ for vrf in vrf_exports:
+ build_child_xml_node(rinst_node, "vrf-export", vrf)
+
+ if rinst_node is not None:
+ instance_xml.append(rinst_node)
+
+ return instance_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
+ """
+ rinst_xml = []
+ existing_rinsts = []
+ rinstance_node = None
+ delete = {"delete": "delete"}
+ if have is not None:
+ # get the instances in running config
+ # form existing instance list
+ for h_rinst in have:
+ existing_rinsts.append(h_rinst["name"])
+
+ # Delete target routing-instance
+ if want:
+ for instance in want:
+ if instance["name"] not in existing_rinsts:
+ continue
+ rinstance_node = build_root_xml_node("instance")
+ build_child_xml_node(
+ rinstance_node,
+ "name",
+ instance["name"],
+ )
+ rinstance_node.attrib.update(delete)
+ rinst_xml.append(rinstance_node)
+
+ else:
+ # Delete all the routing-instance
+ rinstance_node = build_root_xml_node("instance")
+ rinstance_node.attrib.update(delete)
+ rinst_xml.append(rinstance_node)
+
+ if rinstance_node is not None:
+ rinst_xml.append(rinstance_node)
+ return rinst_xml
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_options/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_options/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_options/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_options/routing_options.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_options/routing_options.py
new file mode 100644
index 000000000..1bdacb6f6
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/routing_options/routing_options.py
@@ -0,0 +1,250 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos_routing_options 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_empties,
+ to_list,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Routing_options(ConfigBase):
+ """
+ The junos_routing_options class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["routing_options"]
+
+ def __init__(self, module):
+ super(Routing_options, self).__init__(module)
+
+ def get_routing_options_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ routing_options_facts = facts["ansible_network_resources"].get(
+ "routing_options",
+ )
+ if not routing_options_facts:
+ return {}
+ return routing_options_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ state = self._module.params["state"]
+
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_routing_options_facts = self.get_routing_options_facts()
+ else:
+ existing_routing_options_facts = {}
+ if state == "gathered":
+ existing_routing_options_facts = self.get_routing_options_facts()
+ result["gathered"] = existing_routing_options_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_routing_options_facts(
+ data=running_config,
+ )
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_routing_options_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+
+ else:
+ diff = None
+ config_xmls = self.set_config(existing_routing_options_facts)
+ with locked_config(self._module):
+ for config_xml in 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_routing_options_facts = self.get_routing_options_facts()
+
+ result["before"] = existing_routing_options_facts
+ if result["changed"]:
+ result["after"] = changed_routing_options_facts
+
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_routing_options_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_routing_options_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
+ """
+ self.root = build_root_xml_node("configuration")
+ self.routing_options = build_child_xml_node(
+ self.root,
+ "routing-options",
+ )
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "rendered", "overridden") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ temp_lst = []
+ if state == "deleted":
+ self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ self._state_merged(want, have)
+ elif state == "replaced":
+ self._state_replaced(want, have)
+ elif state == "overridden":
+ self._state_replaced(want, have)
+ if self.root is not None:
+ for xml in self.root.getchildren():
+ xml = tostring(xml)
+ temp_lst.append(xml)
+ return temp_lst
+
+ def _state_replaced(self, want, have):
+ """The command generator when state is replaced
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ self._state_deleted(want, have)
+ self._state_merged(want, have)
+
+ def _state_merged(self, want, have):
+ """The command generator when state is merged
+
+ :rtype: A list
+ :returns: the commands necessary to merge the provided into
+ the current configuration
+ """
+ routing_xml = []
+ want = remove_empties(want)
+
+ # add authentication-keys node
+ if "autonomous_system" in want.keys():
+ as_num = want.get("autonomous_system")
+ # Generate xml node for autonomous-system
+ if as_num.get("as_number"):
+ as_node = build_child_xml_node(
+ self.routing_options,
+ "autonomous-system",
+ as_num.get("as_number"),
+ )
+ # Add node for loops
+ if as_num.get("loops"):
+ build_child_xml_node(as_node, "loops", as_num.get("loops"))
+ # Add node for asdot_notation
+ if as_num.get("asdot_notation"):
+ if "asdot_notation" in as_num.keys():
+ build_child_xml_node(as_node, "asdot-notation")
+ if "router_id" in want.keys():
+ build_child_xml_node(
+ self.routing_options,
+ "router-id",
+ want.get("router_id"),
+ )
+ return routing_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
+ """
+ delete = {"delete": "delete"}
+ if have is not None:
+ if "autonomous_system" in have.keys():
+ build_child_xml_node(
+ self.routing_options,
+ "autonomous-system",
+ None,
+ delete,
+ )
+ if "router_id" in have.keys():
+ build_child_xml_node(
+ self.routing_options,
+ "router-id",
+ None,
+ delete,
+ )
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies/security_policies.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies/security_policies.py
new file mode 100644
index 000000000..12933198e
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies/security_policies.py
@@ -0,0 +1,796 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2022 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos_security_policies 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_empties,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Security_policies(ConfigBase):
+ """
+ The junos_security_policies class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["security_policies"]
+
+ def __init__(self, module):
+ super(Security_policies, self).__init__(module)
+
+ def get_security_policies_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ security_policies_facts = facts["ansible_network_resources"].get(
+ "security_policies",
+ )
+ if not security_policies_facts:
+ return {}
+ return security_policies_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+
+ warnings = list()
+
+ if self.state in self.ACTION_STATES or self.state == "purged":
+ existing_security_policies_facts = self.get_security_policies_facts()
+ else:
+ existing_security_policies_facts = {}
+ if self.state == "gathered":
+ existing_security_policies_facts = self.get_security_policies_facts()
+ result["gathered"] = existing_security_policies_facts
+
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_security_policies_facts(
+ data=running_config,
+ )
+
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_security_policies_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls
+
+ else:
+ diff = None
+ config_xmls = self.set_config(existing_security_policies_facts)
+ with locked_config(self._module):
+ diff = load_config(self._module, config_xmls, [])
+
+ 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_security_policies_facts = self.get_security_policies_facts()
+
+ result["before"] = existing_security_policies_facts
+ if result["changed"]:
+ result["after"] = changed_security_policies_facts
+
+ result["warnings"] = warnings
+ return result
+
+ def set_config(self, existing_security_policies_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_security_policies_facts
+ resp = self.set_state(want, have)
+ return 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
+ """
+ self.root = build_root_xml_node("security")
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "rendered", "overridden") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ config_xmls = []
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ config_xmls = self._state_merged(want, have)
+ elif state == "replaced":
+ config_xmls = self._state_replaced(want, have)
+ for xml in config_xmls:
+ self.root.append(xml)
+ return tostring(self.root)
+
+ def _state_replaced(self, want, have):
+ """The command generator when state is replaced
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ security_policies_xml = []
+ security_policies_xml.extend(self._state_deleted(want, have))
+ security_policies_xml.extend(self._state_merged(want, have))
+ return security_policies_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
+ """
+ security_policies_xml = []
+ security_policies_xml.extend(self._state_deleted(want, have))
+ security_policies_xml.extend(self._state_merged(want, have))
+ return security_policies_xml
+
+ def _state_merged(self, want, _have):
+ """The command generator when state is merged
+
+ :rtype: A list
+ :returns: the commands necessary to merge the provided into
+ the current configuration
+ """
+ security_policies_xml = []
+ want = remove_empties(want)
+ security_policies_node = build_root_xml_node("policies")
+
+ def build_policies(node, policies):
+ for policy in policies:
+ policy_node = build_child_xml_node(node, "policy")
+
+ build_child_xml_node(policy_node, "name", policy["name"])
+
+ if "description" in policy:
+ build_child_xml_node(
+ policy_node,
+ "description",
+ policy["description"],
+ )
+
+ if "scheduler_name" in policy:
+ build_child_xml_node(
+ policy_node,
+ "scheduler-name",
+ policy["scheduler_name"],
+ )
+
+ # add match criteria node
+ match_node = build_child_xml_node(policy_node, "match")
+ match = policy["match"]
+
+ for source_address in match["source_address"]:
+ if source_address == "any_ipv6":
+ build_child_xml_node(
+ match_node,
+ "source-address",
+ "any-ipv6",
+ )
+ elif source_address == "any_ipv4":
+ build_child_xml_node(
+ match_node,
+ "source-address",
+ "any-ipv4",
+ )
+ elif source_address == "any":
+ build_child_xml_node(
+ match_node,
+ "source-address",
+ "any",
+ )
+ elif source_address == "addresses":
+ for address in match["source_address"]["addresses"]:
+ build_child_xml_node(
+ match_node,
+ "source-address",
+ address,
+ )
+
+ if "source_address_excluded" in match:
+ build_child_xml_node(match_node, "source-address-excluded")
+
+ for destination_address in match["destination_address"]:
+ if destination_address == "any_ipv6":
+ build_child_xml_node(
+ match_node,
+ "destination-address",
+ "any-ipv6",
+ )
+ elif destination_address == "any_ipv4":
+ build_child_xml_node(
+ match_node,
+ "destination-address",
+ "any-ipv4",
+ )
+ elif destination_address == "any":
+ build_child_xml_node(
+ match_node,
+ "destination-address",
+ "any",
+ )
+ elif destination_address == "addresses":
+ for address in match["destination_address"]["addresses"]:
+ build_child_xml_node(
+ match_node,
+ "destination-address",
+ address,
+ )
+ else:
+ pass
+
+ if "destination_address_excluded" in match:
+ build_child_xml_node(
+ match_node,
+ "destination-address-excluded",
+ )
+
+ for application in match["application"]:
+ if application == "any":
+ build_child_xml_node(match_node, "application", "any")
+ elif application == "names":
+ for name in match["application"]["names"]:
+ build_child_xml_node(
+ match_node,
+ "application",
+ name,
+ )
+
+ if "source_end_user_profile" in match:
+ build_child_xml_node(
+ match_node,
+ "source-end-user-profile",
+ match["source_end_user_profile"],
+ )
+
+ if "source_identity" in match:
+ source_identities = match["source_identity"]
+ for source_identity in source_identities:
+ if source_identity == "any":
+ build_child_xml_node(
+ match_node,
+ "source-identity",
+ "any",
+ )
+ if source_identity == "authenticated_user":
+ build_child_xml_node(
+ match_node,
+ "source-identity",
+ "authenticated-user",
+ )
+ if source_identity == "unauthenticated_user":
+ build_child_xml_node(
+ match_node,
+ "source-identity",
+ "unauthenticated-user",
+ )
+ if source_identity == "unknown_user":
+ build_child_xml_node(
+ match_node,
+ "source-identity",
+ "unknown-user",
+ )
+ elif source_identity == "names":
+ for name in match["source_identity"]["names"]:
+ build_child_xml_node(
+ match_node,
+ "source-identity",
+ name,
+ )
+
+ if "url_category" in match:
+ url_categories = match["url_category"]
+ for url_category in url_categories:
+ if url_category == "any":
+ build_child_xml_node(
+ match_node,
+ "url-category",
+ "any",
+ )
+ elif url_category == "none":
+ build_child_xml_node(
+ match_node,
+ "url-category",
+ "none",
+ )
+ elif url_category == "names":
+ for name in match["url_category"]["names"]:
+ build_child_xml_node(
+ match_node,
+ "url-category",
+ name,
+ )
+
+ if "dynamic_application" in match:
+ dynamic_applications = match["dynamic_application"]
+ for dynamic_application in dynamic_applications:
+ if dynamic_application == "any":
+ build_child_xml_node(
+ match_node,
+ "dynamic-application",
+ "any",
+ )
+ elif dynamic_application == "none":
+ build_child_xml_node(
+ match_node,
+ "dynamic-application",
+ "none",
+ )
+ elif dynamic_application == "names":
+ for name in match["dynamic_application"]["names"]:
+ build_child_xml_node(
+ match_node,
+ "dynamic-application",
+ name,
+ )
+
+ # add action node
+ then_node = build_child_xml_node(policy_node, "then")
+ then = policy["then"]
+
+ if "deny" in then:
+ build_child_xml_node(then_node, "deny")
+
+ if "count" in then:
+ build_child_xml_node(then_node, "count", " ")
+
+ if "log" in then:
+ log_node = build_child_xml_node(then_node, "log")
+ if policy["then"]["log"] and "session_init" in policy["then"]["log"]:
+ build_child_xml_node(log_node, "session-init")
+ if policy["then"]["log"] and "session_close" in policy["then"]["log"]:
+ build_child_xml_node(log_node, "session-close")
+
+ if "reject" in then:
+ reject = then["reject"]
+ reject_node = build_child_xml_node(
+ then_node,
+ "reject",
+ " ",
+ )
+ if reject and "profile" in reject:
+ build_child_xml_node(
+ reject_node,
+ "profile",
+ reject["profile"],
+ )
+ if reject and "ssl_proxy" in reject:
+ ssl_node = build_child_xml_node(
+ reject_node,
+ "ssl-proxy",
+ " ",
+ )
+ if reject["ssl_proxy"] and "profile_name" in reject["ssl_proxy"]:
+ build_child_xml_node(
+ ssl_node,
+ "profile-name",
+ reject["ssl_proxy"]["profile_name"],
+ )
+
+ if "permit" in then:
+ permit_node = build_child_xml_node(then_node, "permit")
+ permit = then["permit"]
+ if "application_services" in permit:
+ application_services = permit["application_services"]
+ application_services_node = build_child_xml_node(
+ permit_node,
+ "application-services",
+ )
+ if "advanced_anti_malware_policy" in application_services:
+ build_child_xml_node(
+ application_services_node,
+ "advanced-anti-malware-policy",
+ application_services["advanced_anti_malware_policy"],
+ )
+ if "application_traffic_control_rule_set" in application_services:
+ application_traffic_control_node = build_child_xml_node(
+ application_services_node,
+ "application-traffic-control",
+ )
+ build_child_xml_node(
+ application_traffic_control_node,
+ "rule-set",
+ application_services["application_traffic_control_rule_set"],
+ )
+ if "gprs_gtp_profile" in application_services:
+ build_child_xml_node(
+ application_services_node,
+ "gprs-gtp-profile",
+ application_services["gprs_gtp_profile"],
+ )
+ if "gprs_sctp_profile" in application_services:
+ build_child_xml_node(
+ application_services_node,
+ "gprs-sctp-profile",
+ application_services["gprs_sctp_profile"],
+ )
+ if "icap_redirect" in application_services:
+ build_child_xml_node(
+ application_services_node,
+ "icap-redirect",
+ application_services["icap_redirect"],
+ )
+ if "idp" in application_services:
+ build_child_xml_node(
+ application_services_node,
+ "idp",
+ )
+ if "idp_policy" in application_services:
+ build_child_xml_node(
+ application_services_node,
+ "idp-policy",
+ application_services["idp_policy"],
+ )
+ if "redirect_wx" in application_services:
+ build_child_xml_node(
+ application_services_node,
+ "redirect-wx",
+ )
+ if "reverse_redirect_wx" in application_services:
+ build_child_xml_node(
+ application_services_node,
+ "reverse-redirect-wx",
+ )
+ if "security_intelligence_policy" in application_services:
+ build_child_xml_node(
+ application_services_node,
+ "security-intelligence-policy",
+ application_services["security_intelligence_policy"],
+ )
+ if "ssl_proxy" in application_services:
+ ssl_node = build_child_xml_node(
+ application_services_node,
+ "ssl-proxy",
+ " ",
+ )
+ if (
+ application_services["ssl_proxy"]
+ and "profile_name" in application_services["ssl_proxy"]
+ ):
+ build_child_xml_node(
+ ssl_node,
+ "profile-name",
+ application_services["ssl_proxy"]["profile_name"],
+ )
+ if "uac_policy" in application_services:
+ uac_node = build_child_xml_node(
+ application_services_node,
+ "uac-policy",
+ " ",
+ )
+ if (
+ application_services["uac_policy"]
+ and "captive_portal" in application_services["uac_policy"]
+ ):
+ build_child_xml_node(
+ uac_node,
+ "captive-portal",
+ application_services["uac_policy"]["captive_portal"],
+ )
+ if "utm_policy" in application_services:
+ build_child_xml_node(
+ application_services_node,
+ "utm-policy",
+ application_services["utm_policy"],
+ )
+ if "destination_address" in permit:
+ permit_destination_address_node = build_child_xml_node(
+ permit_node,
+ "destination-address",
+ )
+ if permit["destination_address"] == "drop-untranslated":
+ build_child_xml_node(
+ permit_destination_address_node,
+ "drop-untranslated",
+ )
+ if permit["destination_address"] == "drop-translated":
+ build_child_xml_node(
+ permit_destination_address_node,
+ "drop-translated",
+ )
+ if "firewall_authentication" in permit:
+ f_a_node = build_child_xml_node(
+ permit_node,
+ "firewall-authentication",
+ )
+ f_a = permit["firewall_authentication"]
+ if "pass_through" in f_a:
+ pass_through_node = build_child_xml_node(
+ f_a_node,
+ "pass-through",
+ " ",
+ )
+ if "access_profile" in f_a["pass_through"]:
+ build_child_xml_node(
+ pass_through_node,
+ "access-profile",
+ f_a["pass_through"]["access_profile"],
+ )
+ if "auth_only_browser" in f_a["pass_through"]:
+ build_child_xml_node(
+ pass_through_node,
+ "auth-only-browser",
+ " ",
+ )
+ if "auth_user_agent" in f_a["pass_through"]:
+ if (
+ f_a["pass_through"]["auth_user_agent"]
+ and f_a["pass_through"]["auth_user_agent"] is not True
+ ):
+ build_child_xml_node(
+ pass_through_node,
+ "auth-user-agent",
+ f_a["pass_through"]["auth_user_agent"],
+ )
+ else:
+ build_child_xml_node(
+ pass_through_node,
+ "auth-user-agent",
+ " ",
+ )
+
+ if "client_match" in f_a["pass_through"]:
+ build_child_xml_node(
+ pass_through_node,
+ "client-match",
+ f_a["pass_through"]["client_match"],
+ )
+ if "ssl_termination_profile" in f_a["pass_through"]:
+ build_child_xml_node(
+ pass_through_node,
+ "ssl-termination-profile",
+ f_a["pass_through"]["ssl_termination_profile"],
+ )
+ if "web_redirect" in f_a["pass_through"]:
+ build_child_xml_node(
+ pass_through_node,
+ "web-redirect",
+ )
+ if "web_redirect_to_https" in f_a["pass_through"]:
+ build_child_xml_node(
+ pass_through_node,
+ "web-redirect-to-https",
+ )
+ if "push_to_identity_management" in f_a:
+ build_child_xml_node(
+ f_a_node,
+ "push-to-identity-management",
+ )
+ if "user_firewall" in f_a:
+ user_firewall_node = build_child_xml_node(
+ f_a_node,
+ "user-firewall",
+ " ",
+ )
+ if "access_profile" in f_a["user_firewall"]:
+ build_child_xml_node(
+ user_firewall_node,
+ "access-profile",
+ f_a["user_firewall"]["access_profile"],
+ )
+ if "auth_only_browser" in f_a["user_firewall"]:
+ if (
+ f_a["pass_through"]["auth_user_agent"]
+ and f_a["pass_through"]["auth_user_agent"] is not True
+ ):
+ build_child_xml_node(
+ pass_through_node,
+ "auth-user-agent",
+ f_a["pass_through"]["auth_user_agent"],
+ )
+ else:
+ build_child_xml_node(
+ pass_through_node,
+ "auth-user-agent",
+ " ",
+ )
+ if "domain" in f_a["user_firewall"]:
+ build_child_xml_node(
+ user_firewall_node,
+ "domain",
+ f_a["user_firewall"]["domain"],
+ )
+ if "ssl_termination_profile" in f_a["user_firewall"]:
+ build_child_xml_node(
+ user_firewall_node,
+ "ssl-termination-profile",
+ f_a["user_firewall"]["ssl_termination_profile"],
+ )
+ if "web_redirect" in f_a["user_firewall"]:
+ build_child_xml_node(
+ user_firewall_node,
+ "web-redirect",
+ " ",
+ )
+ if "web_redirect_to_https" in f_a["user_firewall"]:
+ build_child_xml_node(
+ user_firewall_node,
+ "web-redirect-to-https",
+ " ",
+ )
+
+ if "web_authentication" in f_a:
+ web_authentication_node = build_child_xml_node(
+ f_a_node,
+ "web-authentication",
+ " ",
+ )
+ for client_match in f_a["web_authentication"]:
+ build_child_xml_node(
+ web_authentication_node,
+ "client-match",
+ client_match,
+ )
+
+ if "tcp_options" in permit:
+ tcp_options_node = build_child_xml_node(
+ permit_node,
+ "tcp-options",
+ " ",
+ )
+ tcp_options = permit["tcp_options"]
+ if "initial_tcp_mss" in tcp_options:
+ build_child_xml_node(
+ tcp_options_node,
+ "initial-tcp-mss",
+ tcp_options["initial_tcp_mss"],
+ )
+ if "reverse_tcp_mss" in tcp_options:
+ build_child_xml_node(
+ tcp_options_node,
+ "reverse-tcp-mss",
+ tcp_options["reverse_tcp_mss"],
+ )
+ if "sequence_check_required" in tcp_options:
+ build_child_xml_node(
+ tcp_options_node,
+ "sequence-check-required",
+ )
+ if "syn_check_required" in tcp_options:
+ build_child_xml_node(
+ tcp_options_node,
+ "syn-check-required",
+ )
+ if "window_scale" in tcp_options:
+ build_child_xml_node(
+ tcp_options_node,
+ "window-scale",
+ )
+
+ if "tunnel" in permit:
+ tunnel_node = build_child_xml_node(
+ permit_node,
+ "tunnel",
+ " ",
+ )
+ if "ipsec_vpn" in permit["tunnel"]:
+ build_child_xml_node(tunnel_node, "ipsec-vpn")
+ if "pair_policy" in permit["tunnel"]:
+ build_child_xml_node(tunnel_node, "pair-policy")
+
+ # add zone-pair policies
+ if "from_zones" in want.keys():
+ from_zones = want.get("from_zones")
+ for from_zone in from_zones:
+ for to_zone in from_zone["to_zones"]:
+ policy_node = build_child_xml_node(
+ security_policies_node,
+ "policy",
+ )
+ build_child_xml_node(
+ policy_node,
+ "from-zone-name",
+ from_zone["name"],
+ )
+ build_child_xml_node(
+ policy_node,
+ "to-zone-name",
+ to_zone["name"],
+ )
+ build_policies(policy_node, to_zone["policies"])
+
+ # add global policies
+ if "global" in want.keys():
+ global_node = build_child_xml_node(
+ security_policies_node,
+ "global",
+ )
+ global_policies = want.get("global").get("policies")
+ build_policies(global_node, global_policies)
+
+ if security_policies_node is not None:
+ security_policies_xml.append(security_policies_node)
+ return security_policies_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
+ """
+ security_policies_xml = []
+ security_policies_root = None
+ delete = {"delete": "delete"}
+ if have is not None:
+ security_policies_root = build_child_xml_node(
+ self.root,
+ "policies",
+ None,
+ delete,
+ )
+
+ if security_policies_root is not None:
+ security_policies_xml.append(security_policies_root)
+ return security_policies_xml
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies_global/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies_global/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies_global/security_policies_global.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies_global/security_policies_global.py
new file mode 100644
index 000000000..5fcbfc8c8
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_policies_global/security_policies_global.py
@@ -0,0 +1,394 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2022 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos_security_policies_global 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_empties,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Security_policies_global(ConfigBase):
+ """
+ The junos_security_policies_global class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["security_policies_global"]
+
+ def __init__(self, module):
+ super(Security_policies_global, self).__init__(module)
+
+ def get_security_policies_global_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ security_policies_global_facts = facts["ansible_network_resources"].get(
+ "security_policies_global",
+ )
+ if not security_policies_global_facts:
+ return {}
+ return security_policies_global_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+
+ warnings = list()
+
+ if self.state in self.ACTION_STATES or self.state == "purged":
+ existing_security_policies_global_facts = self.get_security_policies_global_facts()
+ else:
+ existing_security_policies_global_facts = {}
+ if self.state == "gathered":
+ existing_security_policies_global_facts = self.get_security_policies_global_facts()
+ result["gathered"] = existing_security_policies_global_facts
+
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_security_policies_global_facts(
+ data=running_config,
+ )
+
+ elif self.state == "rendered":
+ config_xmls = self.set_config(
+ existing_security_policies_global_facts,
+ )
+ if config_xmls:
+ result["rendered"] = config_xmls
+
+ else:
+ diff = None
+ config_xmls = self.set_config(
+ existing_security_policies_global_facts,
+ )
+ with locked_config(self._module):
+ diff = load_config(self._module, config_xmls, [])
+
+ 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_security_policies_global_facts = self.get_security_policies_global_facts()
+
+ result["before"] = existing_security_policies_global_facts
+ if result["changed"]:
+ result["after"] = changed_security_policies_global_facts
+
+ result["warnings"] = warnings
+ return result
+
+ def set_config(self, existing_security_policies_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_security_policies_global_facts
+ resp = self.set_state(want, have)
+ return 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
+ """
+ self.root = build_root_xml_node("security")
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "rendered", "overridden") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ config_xmls = []
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ config_xmls = self._state_merged(want, have)
+ elif state == "replaced":
+ config_xmls = self._state_replaced(want, have)
+ for xml in config_xmls:
+ self.root.append(xml)
+ return tostring(self.root)
+
+ def _state_replaced(self, want, have):
+ """The command generator when state is replaced
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ security_policies_global_xml = []
+ security_policies_global_xml.extend(self._state_deleted(want, have))
+ security_policies_global_xml.extend(self._state_merged(want, have))
+ return security_policies_global_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
+ """
+ security_policies_global_xml = []
+ security_policies_global_xml.extend(self._state_deleted(want, have))
+ security_policies_global_xml.extend(self._state_merged(want, have))
+ return security_policies_global_xml
+
+ def _state_merged(self, want, _have):
+ """The command generator when state is merged
+
+ :rtype: A list
+ :returns: the commands necessary to merge the provided into
+ the current configuration
+ """
+ security_policies_global_xml = []
+ want = remove_empties(want)
+ security_policies_global_node = build_root_xml_node("policies")
+ if "default_policy" in want.keys():
+ default_policy_node = build_child_xml_node(
+ security_policies_global_node,
+ "default-policy",
+ )
+ default_policy = want.get("default_policy")
+ if default_policy == "deny-all":
+ build_child_xml_node(default_policy_node, "deny-all")
+ if default_policy == "permit-all":
+ build_child_xml_node(default_policy_node, "permit-all")
+
+ if "policy_rematch" in want.keys():
+ policy_rematch_node = build_child_xml_node(
+ security_policies_global_node,
+ "policy-rematch",
+ " ",
+ )
+ policy_rematch = want.get("policy_rematch") or {}
+ if "extensive" in policy_rematch and policy_rematch["extensive"] is True:
+ build_child_xml_node(policy_rematch_node, "extensive")
+
+ if "policy_stats" in want.keys():
+ policy_stats_node = build_child_xml_node(
+ security_policies_global_node,
+ "policy-stats",
+ " ",
+ )
+ policy_stats = want.get("policy_stats") or {}
+ if "system_wide" in policy_stats:
+ if policy_stats["system_wide"] is True:
+ build_child_xml_node(
+ policy_stats_node,
+ "system-wide",
+ "enable",
+ )
+ else:
+ build_child_xml_node(
+ policy_stats_node,
+ "system-wide",
+ "disable",
+ )
+
+ if "pre_id_default_policy_action" in want.keys():
+ pre_id_node = build_child_xml_node(
+ security_policies_global_node,
+ "pre-id-default-policy",
+ )
+ pre_id_node = build_child_xml_node(pre_id_node, "then")
+ pre_id = want.get("pre_id_default_policy_action")
+
+ if "log" in pre_id:
+ log_node = build_child_xml_node(pre_id_node, "log")
+ if "session_close" in pre_id["log"]:
+ build_child_xml_node(log_node, "session-close")
+ if "session_init" in pre_id["log"]:
+ build_child_xml_node(log_node, "session-init")
+
+ if "session_timeout" in pre_id:
+ session_timeout_node = build_child_xml_node(
+ pre_id_node,
+ "session-timeout",
+ )
+ if "icmp" in pre_id["session_timeout"]:
+ build_child_xml_node(
+ session_timeout_node,
+ "icmp",
+ pre_id["session_timeout"]["icmp"],
+ )
+ if "icmp6" in pre_id["session_timeout"]:
+ build_child_xml_node(
+ session_timeout_node,
+ "icmp6",
+ pre_id["session_timeout"]["icmp6"],
+ )
+ if "ospf" in pre_id["session_timeout"]:
+ build_child_xml_node(
+ session_timeout_node,
+ "ospf",
+ pre_id["session_timeout"]["ospf"],
+ )
+ if "others" in pre_id["session_timeout"]:
+ build_child_xml_node(
+ session_timeout_node,
+ "others",
+ pre_id["session_timeout"]["others"],
+ )
+ if "tcp" in pre_id["session_timeout"]:
+ build_child_xml_node(
+ session_timeout_node,
+ "tcp",
+ pre_id["session_timeout"]["tcp"],
+ )
+ if "udp" in pre_id["session_timeout"]:
+ build_child_xml_node(
+ session_timeout_node,
+ "udp",
+ pre_id["session_timeout"]["udp"],
+ )
+
+ if "traceoptions" in want.keys():
+ traceoptions_node = build_child_xml_node(
+ security_policies_global_node,
+ "traceoptions",
+ )
+ traceoptions = want.get("traceoptions")
+
+ if "file" in traceoptions:
+ file_node = build_child_xml_node(traceoptions_node, "file")
+ if "files" in traceoptions["file"]:
+ build_child_xml_node(
+ file_node,
+ "files",
+ traceoptions["file"]["files"],
+ )
+ if "match" in traceoptions["file"]:
+ build_child_xml_node(
+ file_node,
+ "match",
+ traceoptions["file"]["match"],
+ )
+ if "size" in traceoptions["file"]:
+ build_child_xml_node(
+ file_node,
+ "size",
+ traceoptions["file"]["size"],
+ )
+ if "world_readable" in traceoptions["file"]:
+ build_child_xml_node(file_node, "world-readable")
+ if "no_world_readable" in traceoptions["file"]:
+ build_child_xml_node(file_node, "no-world-readable")
+
+ if "flag" in traceoptions:
+ if traceoptions["flag"] == "all":
+ flag_node = build_child_xml_node(traceoptions_node, "flag")
+ build_child_xml_node(flag_node, "name", "all")
+ elif traceoptions["flag"] == "configuration":
+ flag_node = build_child_xml_node(traceoptions_node, "flag")
+ build_child_xml_node(flag_node, "name", "configuration")
+ elif traceoptions["flag"] == "compilation":
+ flag_node = build_child_xml_node(traceoptions_node, "flag")
+ build_child_xml_node(flag_node, "name", "compilation")
+ elif traceoptions["flag"] == "ipc":
+ flag_node = build_child_xml_node(traceoptions_node, "flag")
+ build_child_xml_node(flag_node, "name", "ipc")
+ elif traceoptions["flag"] == "lookup":
+ flag_node = build_child_xml_node(traceoptions_node, "flag")
+ build_child_xml_node(flag_node, "name", "lookup")
+ elif traceoptions["flag"] == "routing-socket":
+ flag_node = build_child_xml_node(traceoptions_node, "flag")
+ build_child_xml_node(flag_node, "name", "routing-socket")
+ elif traceoptions["flag"] == "rules":
+ flag_node = build_child_xml_node(traceoptions_node, "flag")
+ build_child_xml_node(flag_node, "name", "rules")
+
+ if "no_remote_trace" in traceoptions:
+ build_child_xml_node(traceoptions_node, "no-remote-trace")
+
+ if security_policies_global_node is not None:
+ security_policies_global_xml.append(security_policies_global_node)
+ return security_policies_global_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
+ """
+ security_policies_global_xml = []
+ security_policies_global_root = None
+ delete = {"delete": "delete"}
+ if have is not None:
+ security_policies_global_root = build_child_xml_node(
+ self.root,
+ "policies",
+ None,
+ delete,
+ )
+
+ if security_policies_global_root is not None:
+ security_policies_global_xml.append(security_policies_global_root)
+ return security_policies_global_xml
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_zones/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_zones/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_zones/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_zones/security_zones.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_zones/security_zones.py
new file mode 100644
index 000000000..af69c9a45
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/security_zones/security_zones.py
@@ -0,0 +1,515 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2022 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos_security_zones 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_empties,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Security_zones(ConfigBase):
+ """
+ The junos_security_zones class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["security_zones"]
+
+ def __init__(self, module):
+ super(Security_zones, self).__init__(module)
+
+ def get_security_zones_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ security_zones_facts = facts["ansible_network_resources"].get(
+ "security_zones",
+ )
+ if not security_zones_facts:
+ return {}
+ return security_zones_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+
+ warnings = list()
+
+ if self.state in self.ACTION_STATES or self.state == "purged":
+ existing_security_zones_facts = self.get_security_zones_facts()
+ else:
+ existing_security_zones_facts = {}
+ if self.state == "gathered":
+ existing_security_zones_facts = self.get_security_zones_facts()
+ result["gathered"] = existing_security_zones_facts
+
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_security_zones_facts(
+ data=running_config,
+ )
+
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_security_zones_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls
+
+ else:
+ diff = None
+ config_xmls = self.set_config(existing_security_zones_facts)
+ with locked_config(self._module):
+ diff = load_config(self._module, config_xmls, [])
+
+ 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_security_zones_facts = self.get_security_zones_facts()
+
+ result["before"] = existing_security_zones_facts
+ if result["changed"]:
+ result["after"] = changed_security_zones_facts
+
+ result["warnings"] = warnings
+ return result
+
+ def set_config(self, existing_security_zones_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_security_zones_facts
+ resp = self.set_state(want, have)
+ return 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
+ """
+ self.root = build_root_xml_node("security")
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "rendered", "overridden") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ config_xmls = []
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ config_xmls = self._state_merged(want, have)
+ elif state == "replaced":
+ config_xmls = self._state_replaced(want, have)
+ for xml in config_xmls:
+ self.root.append(xml)
+ return tostring(self.root)
+
+ def _state_replaced(self, want, have):
+ """The command generator when state is replaced
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ security_zones_xml = []
+ security_zones_xml.extend(self._state_deleted(want, have))
+ security_zones_xml.extend(self._state_merged(want, have))
+ return security_zones_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
+ """
+ security_zones_xml = []
+ security_zones_xml.extend(self._state_deleted(want, have))
+ security_zones_xml.extend(self._state_merged(want, have))
+ return security_zones_xml
+
+ def _state_merged(self, want, _have):
+ """The command generator when state is merged
+
+ :rtype: A list
+ :returns: the commands necessary to merge the provided into
+ the current configuration
+ """
+ zones_xml = []
+ want = remove_empties(want)
+ zones_node = build_root_xml_node("zones")
+
+ def build_host_inbound_traffic(node, host_inbound_traffic):
+ host_inbound_traffic_node = build_child_xml_node(
+ node,
+ "host-inbound-traffic",
+ )
+
+ if "protocols" in host_inbound_traffic:
+ for protocol in host_inbound_traffic["protocols"]:
+ protocol_node = build_child_xml_node(
+ host_inbound_traffic_node,
+ "protocols",
+ )
+ build_child_xml_node(
+ protocol_node,
+ "name",
+ protocol["name"],
+ )
+ if "except" in protocol:
+ build_child_xml_node(protocol_node, "except")
+ if "system_services" in host_inbound_traffic:
+ for system_service in host_inbound_traffic["system_services"]:
+ system_service_node = build_child_xml_node(
+ host_inbound_traffic_node,
+ "system-services",
+ )
+ build_child_xml_node(
+ system_service_node,
+ "name",
+ system_service["name"],
+ )
+ if "except" in system_service:
+ build_child_xml_node(system_service_node, "except")
+
+ # add zone-pair policies
+ if "functional_zone_management" in want.keys():
+ functional_zone_management = want.get("functional_zone_management")
+ functional_zone_node = build_child_xml_node(
+ zones_node,
+ "functional-zone",
+ )
+ functional_zone_management_node = build_child_xml_node(
+ functional_zone_node,
+ "management",
+ )
+
+ if "description" in functional_zone_management:
+ build_child_xml_node(
+ functional_zone_management_node,
+ "description",
+ functional_zone_management["description"],
+ )
+ if "host_inbound_traffic" in functional_zone_management:
+ build_host_inbound_traffic(
+ functional_zone_management_node,
+ functional_zone_management["host_inbound_traffic"],
+ )
+ if "interfaces" in functional_zone_management:
+ for interface in functional_zone_management["interfaces"]:
+ interface_node = build_child_xml_node(
+ functional_zone_management_node,
+ "interfaces",
+ )
+ build_child_xml_node(interface_node, "name", interface)
+ if "screen" in functional_zone_management:
+ build_child_xml_node(
+ functional_zone_management_node,
+ "screen",
+ functional_zone_management["screen"],
+ )
+
+ # add global policies
+ if "zones" in want.keys():
+ security_zones = want.get("zones")
+
+ for security_zone in security_zones:
+ security_zone_node = build_child_xml_node(
+ zones_node,
+ "security-zone",
+ )
+ if "name" in security_zone:
+ build_child_xml_node(
+ security_zone_node,
+ "name",
+ security_zone["name"],
+ )
+ if "address_book" in security_zone:
+ address_book_node = build_child_xml_node(
+ security_zone_node,
+ "address-book",
+ )
+
+ if "addresses" in security_zone["address_book"]:
+ for address in security_zone["address_book"]["addresses"]:
+ address_node = build_child_xml_node(
+ address_book_node,
+ "address",
+ )
+
+ build_child_xml_node(
+ address_node,
+ "name",
+ address["name"],
+ )
+ if "ip_prefix" in address:
+ build_child_xml_node(
+ address_node,
+ "ip-prefix",
+ address["ip_prefix"],
+ )
+ elif "dns_name" in address:
+ dns_node = build_child_xml_node(
+ address_node,
+ "dns-name",
+ )
+ build_child_xml_node(
+ dns_node,
+ "name",
+ address["dns_name"]["name"],
+ )
+ if "ipv4_only" in address["dns_name"]:
+ build_child_xml_node(dns_node, "ipv4-only")
+ if "ipv6_only" in address["dns_name"]:
+ build_child_xml_node(dns_node, "ipv6-only")
+ elif "range_address" in address:
+ range_address_node = build_child_xml_node(
+ address_node,
+ "range-address",
+ )
+ build_child_xml_node(
+ range_address_node,
+ "name",
+ address["range_address"]["from"],
+ )
+ to_node = build_child_xml_node(
+ range_address_node,
+ "to",
+ )
+ build_child_xml_node(
+ to_node,
+ "range-high",
+ address["range_address"]["to"],
+ )
+ elif "wildcard_address" in address:
+ wildcard_node = build_child_xml_node(
+ address_node,
+ "wildcard-address",
+ )
+ build_child_xml_node(
+ wildcard_node,
+ "name",
+ address["wildcard_address"],
+ )
+ if "description" in address:
+ build_child_xml_node(
+ address_node,
+ "description",
+ address["description"],
+ )
+ if "address_sets" in security_zone["address_book"]:
+ for address_set in security_zone["address_book"]["address_sets"]:
+ address_set_node = build_child_xml_node(
+ address_book_node,
+ "address-set",
+ )
+
+ build_child_xml_node(
+ address_set_node,
+ "name",
+ address_set["name"],
+ )
+ if "addresses" in address_set:
+ for address in address_set["addresses"]:
+ addr_node = build_child_xml_node(
+ address_set_node,
+ "address",
+ )
+ build_child_xml_node(
+ addr_node,
+ "name",
+ address,
+ )
+ if "address_sets" in address_set:
+ for address in address_set["address_sets"]:
+ addr_node = build_child_xml_node(
+ address_set_node,
+ "address-set",
+ )
+ build_child_xml_node(
+ addr_node,
+ "name",
+ address,
+ )
+ if "description" in address_set:
+ build_child_xml_node(
+ address_set_node,
+ "description",
+ address_set["description"],
+ )
+
+ if "advance_policy_based_routing_profile" in security_zone:
+ routing_profile_node = build_child_xml_node(
+ security_zone_node,
+ "advance-policy-based-routing-profile",
+ )
+ build_child_xml_node(
+ routing_profile_node,
+ "profile",
+ security_zone["advance_policy_based_routing_profile"],
+ )
+ if "advanced_connection_tracking" in security_zone:
+ act_node = build_child_xml_node(
+ security_zone_node,
+ "advanced-connection-tracking",
+ )
+ if "mode" in security_zone["advanced_connection_tracking"]:
+ build_child_xml_node(
+ act_node,
+ "mode",
+ security_zone["advanced_connection_tracking"]["mode"],
+ )
+ if "timeout" in security_zone["advanced_connection_tracking"]:
+ build_child_xml_node(
+ act_node,
+ "timeout",
+ security_zone["advanced_connection_tracking"]["timeout"],
+ )
+ if (
+ "track_all_policies_to_this_zone"
+ in security_zone["advanced_connection_tracking"]
+ ):
+ build_child_xml_node(
+ act_node,
+ "track-all-policies-to-this-zone",
+ )
+ if "application_tracking" in security_zone:
+ build_child_xml_node(
+ security_zone_node,
+ "application-tracking",
+ )
+ if "description" in security_zone:
+ build_child_xml_node(
+ security_zone_node,
+ "description",
+ security_zone["description"],
+ )
+ if "enable_reverse_reroute" in security_zone:
+ build_child_xml_node(
+ security_zone_node,
+ "enable-reverse-reroute",
+ )
+ if "host_inbound_traffic" in security_zone:
+ build_host_inbound_traffic(
+ security_zone_node,
+ security_zone["host_inbound_traffic"],
+ )
+ if "interfaces" in security_zone:
+ for interface in security_zone["interfaces"]:
+ interface_node = build_child_xml_node(
+ security_zone_node,
+ "interfaces",
+ )
+ build_child_xml_node(interface_node, "name", interface)
+ if "screen" in security_zone:
+ build_child_xml_node(
+ security_zone_node,
+ "screen",
+ security_zone["screen"],
+ )
+ if "source_identity_log" in security_zone:
+ build_child_xml_node(
+ security_zone_node,
+ "source-identity-log",
+ )
+ if "tcp_rst" in security_zone:
+ build_child_xml_node(security_zone_node, "tcp-rst")
+ if "unidirectional_session_refreshing" in security_zone:
+ build_child_xml_node(
+ security_zone_node,
+ "unidirectional-session-refreshing",
+ )
+
+ if zones_node is not None:
+ zones_xml.append(zones_node)
+ return zones_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
+ """
+ security_zones_xml = []
+ security_zones_root = None
+ delete = {"delete": "delete"}
+ if have is not None:
+ security_zones_root = build_child_xml_node(
+ self.root,
+ "zones",
+ None,
+ delete,
+ )
+
+ if security_zones_root is not None:
+ security_zones_xml.append(security_zones_root)
+ return security_zones_xml
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/snmp_server/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/snmp_server/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/snmp_server/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/snmp_server/snmp_server.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/snmp_server/snmp_server.py
new file mode 100644
index 000000000..754b890d1
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/snmp_server/snmp_server.py
@@ -0,0 +1,897 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos_snmp_server 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_empties,
+ to_list,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+class Snmp_server(ConfigBase):
+ """
+ The junos_snmp_server class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["snmp_server"]
+
+ def __init__(self, module):
+ super(Snmp_server, self).__init__(module)
+
+ def get_snmp_server_facts(self, data=None):
+ """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,
+ data=data,
+ )
+ snmp_server_facts = facts["ansible_network_resources"].get(
+ "snmp_server",
+ )
+ if not snmp_server_facts:
+ return {}
+ return snmp_server_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ state = self._module.params["state"]
+
+ warnings = list()
+
+ if self.state in self.ACTION_STATES or self.state == "purged":
+ existing_snmp_server_facts = self.get_snmp_server_facts()
+ else:
+ existing_snmp_server_facts = {}
+ if state == "gathered":
+ existing_snmp_server_facts = self.get_snmp_server_facts()
+ result["gathered"] = existing_snmp_server_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_snmp_server_facts(data=running_config)
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_snmp_server_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+
+ else:
+ diff = None
+ config_xmls = self.set_config(existing_snmp_server_facts)
+ with locked_config(self._module):
+ for config_xml in 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_snmp_server_facts = self.get_snmp_server_facts()
+
+ result["before"] = existing_snmp_server_facts
+ if result["changed"]:
+ result["after"] = changed_snmp_server_facts
+
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_snmp_server_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_snmp_server_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
+ """
+ self.root = build_root_xml_node("configuration")
+ self.snmp = build_child_xml_node(self.root, "snmp")
+ cmd_lst = []
+ state = self._module.params["state"]
+ if state in ("merged", "replaced", "rendered", "overridden") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ if state == "deleted":
+ self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ self._state_merged(want, have)
+ elif state == "replaced":
+ self._state_replaced(want, have)
+ elif state == "overridden":
+ self._state_replaced(want, have)
+
+ if self.root is not None:
+ for xml in self.root.getchildren():
+ xml = tostring(xml)
+ cmd_lst.append(xml)
+ return cmd_lst
+
+ def _state_replaced(self, want, have):
+ """The command generator when state is replaced
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ self._state_deleted(want, have)
+ self.snmp = build_child_xml_node(self.root, "snmp")
+ self._state_merged(want, have)
+
+ def _state_merged(self, want, have):
+ """The command generator when state is merged
+
+ :rtype: A list
+ :returns: the commands necessary to merge the provided into
+ the current configuration
+ """
+ want = remove_empties(want)
+ snmp_node = self.snmp
+ # add arp node
+ if "arp" in want.keys():
+ arp = want.get("arp")
+ if arp.get("host_name_resolution"):
+ arp_node = build_child_xml_node(snmp_node, "arp")
+ build_child_xml_node(arp_node, "host-name-resolution")
+ elif arp.get("set"):
+ build_child_xml_node(snmp_node, "arp")
+
+ # add node client list
+ if "client_lists" in want.keys():
+ client_lists = want.get("client_lists")
+ for client in client_lists:
+ client_node = build_child_xml_node(snmp_node, "client-list")
+ # add name node
+ build_child_xml_node(client_node, "name", client.get("name"))
+ if "addresses" in client.keys():
+ addresses = client.get("addresses")
+ for address in addresses:
+ add_lst_node = build_child_xml_node(
+ client_node,
+ "client-address-list",
+ )
+ build_child_xml_node(
+ add_lst_node,
+ "name",
+ address["address"],
+ )
+ if address.get("restrict"):
+ build_child_xml_node(add_lst_node, "restrict")
+
+ # add routing_instance_access
+ if "routing_instance_access" in want.keys():
+ ria = want.get("routing_instance_access")
+
+ if "access_lists" not in ria.keys() and ria.get("set"):
+ build_child_xml_node(snmp_node, "routing-instance-access")
+ elif "access_lists" in ria.keys():
+ ria_node = build_child_xml_node(
+ snmp_node,
+ "routing-instance-access",
+ )
+ access_lists = ria.get("access_lists")
+ for item in access_lists:
+ al_node = build_child_xml_node(ria_node, "access-list")
+ build_child_xml_node(al_node, "name", item)
+ # add communities node
+ if "communities" in want.keys():
+ communities = want.get("communities")
+ for community in communities:
+ comm_node = build_child_xml_node(snmp_node, "community")
+ build_child_xml_node(comm_node, "name", community["name"])
+ if "authorization" in community.keys():
+ build_child_xml_node(
+ comm_node,
+ "authorization",
+ community["authorization"],
+ )
+ if "clients" in community.keys():
+ clients = community.get("clients")
+ for client in clients:
+ client_node = build_child_xml_node(
+ comm_node,
+ "clients",
+ )
+ build_child_xml_node(
+ client_node,
+ "name",
+ client["address"],
+ )
+ if client.get("restrict"):
+ build_child_xml_node(client_node, "restrict")
+ if "client_list_name" in community.keys():
+ build_child_xml_node(
+ comm_node,
+ "client-list-name",
+ community.get("client_list_name"),
+ )
+ if "routing_instances" in community.keys():
+ routing_instances = community.get("routing_instances")
+ for inst in routing_instances:
+ inst_node = build_child_xml_node(
+ comm_node,
+ "routing-instance",
+ )
+ build_child_xml_node(inst_node, "name", inst["name"])
+ if "clients" in inst.keys():
+ clients = inst.get("clients")
+ for client in clients:
+ client_node = build_child_xml_node(
+ inst_node,
+ "clients",
+ )
+ build_child_xml_node(
+ client_node,
+ "name",
+ client["address"],
+ )
+ if client.get("restrict"):
+ build_child_xml_node(
+ client_node,
+ "restrict",
+ )
+ if "client_list_name" in inst.keys():
+ build_child_xml_node(
+ inst_node,
+ "client-list-name",
+ inst.get("client_list_name"),
+ )
+ if "view" in community.keys():
+ build_child_xml_node(
+ comm_node,
+ "view",
+ community.get("view"),
+ )
+
+ # add contact node
+ if "contact" in want.keys():
+ build_child_xml_node(snmp_node, "contact", want.get("contact"))
+
+ # add customization node
+ if "customization" in want.keys():
+ custom = want.get("customization")
+ if custom.get("ether_stats_ifd_only"):
+ custom_node = build_child_xml_node(snmp_node, "customization")
+ build_child_xml_node(custom_node, "ether-stats-ifd-only")
+
+ # add description node
+ if "description" in want.keys():
+ build_child_xml_node(
+ snmp_node,
+ "description",
+ want.get("description"),
+ )
+
+ # add engine_id
+ if "engine_id" in want.keys():
+ engine = want.get("engine_id")
+ engine_node = build_child_xml_node(snmp_node, "engine-id")
+ if "local" in engine.keys():
+ build_child_xml_node(engine_node, "local", engine["local"])
+ if engine.get("use_default_ip_address"):
+ build_child_xml_node(engine_node, "use-default-ip-address")
+ if engine.get("use_mac_address"):
+ build_child_xml_node(engine_node, "use-mac-address")
+
+ # add filter_duplicates node
+ if want.get("filter_duplicates"):
+ build_child_xml_node(snmp_node, "filter-duplicates")
+
+ # add filter_interfaces node
+ if "filter_interfaces" in want.keys():
+ fints = want.get("filter_interfaces")
+
+ if "all_internal_interfaces" not in fints.keys() and "interfaces" not in fints.keys():
+ build_child_xml_node(snmp_node, "filter-interfaces")
+ else:
+ fints_node = build_child_xml_node(
+ snmp_node,
+ "filter-interfaces",
+ )
+ if "all_internal_interfaces" in fints.keys():
+ build_child_xml_node(fints_node, "all-internal-interfaces")
+ if "interfaces" in fints.keys():
+ interfaces = fints.get("interfaces")
+ for item in interfaces:
+ int_node = build_child_xml_node(
+ fints_node,
+ "interfaces",
+ )
+ build_child_xml_node(int_node, "name", item)
+
+ # add health_monitor node
+ if "health_monitor" in want.keys():
+ health = want.get("health_monitor")
+
+ if "falling_threshold" not in health.keys() and "rising_threshold" not in health.keys():
+ if "idp" not in health.keys() and "interval" not in health.keys():
+ build_child_xml_node(snmp_node, "health-monitor")
+ else:
+ health_node = build_child_xml_node(snmp_node, "health-monitor")
+ if "falling_threshold" in health.keys():
+ build_child_xml_node(
+ health_node,
+ "falling-threshold",
+ health.get("falling_threshold"),
+ )
+ if "rising_threshold" in health.keys():
+ build_child_xml_node(
+ health_node,
+ "rising-threshold",
+ health.get("rising_threshold"),
+ )
+ if "interval" in health.keys():
+ build_child_xml_node(
+ health_node,
+ "interval",
+ health.get("interval"),
+ )
+ if health.get("idp"):
+ build_child_xml_node(health_node, "idp")
+
+ # add if_count_with_filter_interfaces
+ if want.get("if_count_with_filter_interfaces"):
+ build_child_xml_node(snmp_node, "if-count-with-filter-interfaces")
+
+ # add interfaces node
+ if "interfaces" in want.keys():
+ interfaces = want.get("interfaces")
+ for item in interfaces:
+ build_child_xml_node(snmp_node, "interface", item)
+
+ # add location
+ if "location" in want.keys():
+ build_child_xml_node(snmp_node, "location", want.get("location"))
+
+ # add logical_system_trap_filter
+ if want.get("logical_system_trap_filter"):
+ build_child_xml_node(snmp_node, "logical-system-trap-filter")
+
+ # add name
+ if "name" in want.keys():
+ build_child_xml_node(snmp_node, "system-name", want.get("name"))
+
+ # add nonvolatile
+ if "nonvolatile" in want.keys():
+ nonvolatile = want.get("nonvolatile")
+ non_node = build_child_xml_node(snmp_node, "nonvolatile")
+ if "commit_delay" in nonvolatile.keys():
+ build_child_xml_node(
+ non_node,
+ "commit-delay",
+ nonvolatile.get("commit_delay"),
+ )
+
+ # add rmon
+ if "rmon" in want.keys():
+ rmon = want.get("rmon")
+
+ if "alarms" not in rmon.keys() and "events" not in rmon.keys() and want.get("set"):
+ build_child_xml_node(snmp_node, "rmon")
+ else:
+ rmon_node = build_child_xml_node(snmp_node, "rmon")
+ if "alarms" in rmon.keys():
+ alarms = rmon.get("alarms")
+ for alarm in alarms:
+ alarm_node = build_child_xml_node(rmon_node, "alarm")
+ for key in alarm.keys():
+ if key == "id":
+ build_child_xml_node(
+ alarm_node,
+ "name",
+ alarm.get("id"),
+ )
+ else:
+ build_child_xml_node(
+ alarm_node,
+ key.replace("_", "-"),
+ alarm.get(key),
+ )
+ if "events" in rmon.keys():
+ events = rmon.get("events")
+ for event in events:
+ event_node = build_child_xml_node(rmon_node, "event")
+ for key in event.keys():
+ if key == "id":
+ build_child_xml_node(
+ event_node,
+ "name",
+ event.get("id"),
+ )
+ else:
+ build_child_xml_node(
+ event_node,
+ key.replace("_", "-"),
+ event.get(key),
+ )
+ # subagent
+ if "subagent" in want.keys():
+ subagent = want.get("subagent")
+ sub_node = build_child_xml_node(snmp_node, "subagent")
+ if "tcp" in subagent.keys():
+ tcp = subagent.get("tcp")
+ if tcp.get("set") and "routing_instances_default" not in tcp.keys():
+ build_child_xml_node(sub_node, "tcp")
+ elif tcp.get("routing_instances_default"):
+ tcp_node = build_child_xml_node(sub_node, "tcp")
+ routing_node = build_child_xml_node(
+ tcp_node,
+ "routing-instance",
+ )
+ build_child_xml_node(routing_node, "default")
+
+ # traceoptions
+ if "traceoptions" in want.keys():
+ options = want.get("traceoptions")
+ trace_node = build_child_xml_node(snmp_node, "traceoptions")
+
+ if "file" in options.keys():
+ file = options.get("file")
+ file_node = build_child_xml_node(trace_node, "file")
+ if "match" in file.keys():
+ build_child_xml_node(file_node, "match", file.get("match"))
+ if "files" in file.keys():
+ build_child_xml_node(file_node, "files", file.get("files"))
+ if "no_world_readable" in file.keys():
+ build_child_xml_node(file_node, "no-world-readable")
+ if "world_readable" in file.keys():
+ build_child_xml_node(file_node, "world-readable")
+ if "size" in file.keys():
+ build_child_xml_node(file_node, "size", file.get("size"))
+
+ if "flag" in options.keys():
+ flags = options.get("flag")
+ for key in flags.keys():
+ flag_node = build_child_xml_node(trace_node, "flag")
+ build_child_xml_node(
+ flag_node,
+ "name",
+ key.replace("_", "-"),
+ )
+
+ if "memory_trace" in options.keys():
+ mem = options.get("memory_trace")
+
+ if mem.get("set") and "size" not in mem.keys():
+ build_child_xml_node(trace_node, "memory-trace")
+ elif "size" in mem.keys():
+ mem_node = build_child_xml_node(trace_node, "memory-trace")
+ build_child_xml_node(mem_node, "size", mem.get("size"))
+
+ if "trap_groups" in want.keys():
+ groups = want.get("trap_groups")
+
+ for trap in groups:
+ trap_node = build_child_xml_node(snmp_node, "trap-group")
+ for key in trap.keys():
+ if key == "name":
+ build_child_xml_node(
+ trap_node,
+ "name",
+ trap["name"],
+ )
+ if key == "destination_port":
+ build_child_xml_node(
+ trap_node,
+ "destination-port",
+ trap["destination_port"],
+ )
+ if key == "categories":
+ cat_node = build_child_xml_node(
+ trap_node,
+ "categories",
+ )
+ categories = trap.get("categories")
+ for key in categories:
+ if key == "otn_alarms":
+ alarms = categories.get("otn_alarms")
+ alarm_node = build_child_xml_node(
+ cat_node,
+ "otn-alarms",
+ )
+ for key in alarms:
+ build_child_xml_node(
+ alarm_node,
+ key.replace("_", "-"),
+ )
+ else:
+ build_child_xml_node(
+ cat_node,
+ key.replace("_", "-"),
+ )
+ if key == "routing_instance":
+ build_child_xml_node(
+ trap_node,
+ "routing-instance",
+ trap.get(key),
+ )
+ if key == "version":
+ build_child_xml_node(
+ trap_node,
+ "version",
+ trap.get(key),
+ )
+ if key == "targets":
+ targets = trap.get("targets")
+ for target in targets:
+ tar_node = build_child_xml_node(
+ trap_node,
+ "targets",
+ )
+ build_child_xml_node(tar_node, "name", target)
+
+ # trap_options
+ if "trap_options" in want.keys():
+ options = want.get("trap_options")
+
+ if options.keys() == {"set"}:
+ build_child_xml_node(snmp_node, "trap-options")
+ else:
+ trap_node = build_child_xml_node(snmp_node, "trap-options")
+ if "agent_address" in options.keys():
+ agent = options.get("agent_address")
+ if agent.get("outgoing_interface"):
+ build_child_xml_node(
+ trap_node,
+ "agent-address",
+ "outgoing-interface",
+ )
+ if options.get("context_oid"):
+ build_child_xml_node(trap_node, "context-id")
+ # TODO logical_system
+ if "routing_instance" in options.keys():
+ inst = options.get("routing_instances")
+ inst_node = build_child_xml_node(
+ trap_node,
+ "routing-instance",
+ )
+ build_child_xml_node(inst_node, "name", inst)
+ if "source_address" in options.keys():
+ address = options.get("source_address")
+ source_node = build_child_xml_node(
+ trap_node,
+ "source-address",
+ )
+ if "address" in address.keys():
+ build_child_xml_node(
+ source_node,
+ "address",
+ address.get("address"),
+ )
+ if "lowest_loopback" in address.keys():
+ build_child_xml_node(
+ source_node,
+ "lowest-loopback",
+ )
+ # snmp_v3
+ if "snmp_v3" in want.keys():
+ snmpv3 = want.get("snmp_v3")
+ v3_node = build_child_xml_node(snmp_node, "v3")
+
+ if "notify" in snmpv3.keys():
+ notify = snmpv3.get("notify")
+ for item in notify:
+ not_node = build_child_xml_node(v3_node, "notify")
+ for key in item.keys():
+ build_child_xml_node(not_node, key, item.get(key))
+ if "notify_filter" in snmpv3.keys():
+ filters = snmpv3.get("notify_filter")
+ for filter in filters:
+ fil_node = build_child_xml_node(v3_node, "notify-filter")
+ if "name" in filter.keys():
+ build_child_xml_node(
+ fil_node,
+ "name",
+ filter.get("name"),
+ )
+ if "oids" in filter.keys():
+ oids = filter.get("oids")
+ for oid in oids:
+ oids_node = build_child_xml_node(fil_node, "oid")
+ if "oid" in oid.keys():
+ build_child_xml_node(
+ oids_node,
+ "name",
+ oid["oid"],
+ )
+ if "exclude" in oid.keys():
+ build_child_xml_node(oids_node, "exclude")
+ if "include" in oid.keys():
+ build_child_xml_node(oids_node, "include")
+ if "snmp_community" in snmpv3.keys():
+ snmp_community = snmpv3.get("snmp_community")
+ for snmp in snmp_community:
+ snmp_node = build_child_xml_node(v3_node, "snmp-community")
+ for key in snmp.keys():
+ if key == "community_index":
+ build_child_xml_node(
+ snmp_node,
+ "name",
+ snmp.get(key),
+ )
+ else:
+ build_child_xml_node(
+ snmp_node,
+ key.replace("_", "-"),
+ snmp.get(key),
+ )
+
+ if "target_addresses" in snmpv3.keys():
+ addresses = snmpv3.get("target_addresses")
+ for address in addresses:
+ tar_node = build_child_xml_node(v3_node, "target-address")
+ for key in address:
+ build_child_xml_node(
+ tar_node,
+ key.replace("_", "-"),
+ address.get(key),
+ )
+
+ # target_parameters
+ if "target_parameters" in snmpv3.keys():
+ parameters = snmpv3.get("target_parameters")
+
+ for param in parameters:
+ param_node = build_child_xml_node(
+ v3_node,
+ "target-parameters",
+ )
+
+ if "name" in param:
+ build_child_xml_node(
+ param_node,
+ "name",
+ param.get("name"),
+ )
+ if "notify_filter" in param:
+ build_child_xml_node(
+ param_node,
+ "notify-filter",
+ param.get("notify_filter"),
+ )
+ if "parameters" in param:
+ subnode = build_child_xml_node(
+ param_node,
+ "parameters",
+ )
+ parameter = param.get("parameters")
+ for key in parameter.keys():
+ build_child_xml_node(
+ subnode,
+ key.replace("_", "-"),
+ parameter.get(key),
+ )
+ # usm
+ if "usm" in snmpv3.keys():
+ usm = snmpv3.get("usm")
+
+ usm_node = build_child_xml_node(v3_node, "usm")
+ if "local_engine" in usm.keys():
+ local = usm.get("local_engine")
+
+ local_node = build_child_xml_node(usm_node, "local-engine")
+ if "users" in local.keys():
+ users = local.get("users")
+ for user in users:
+ user_node = build_child_xml_node(
+ local_node,
+ "user",
+ )
+ for key in user.keys():
+ if key == "name":
+ build_child_xml_node(
+ user_node,
+ "name",
+ user["name"],
+ )
+ elif key == "authentication_none":
+ build_child_xml_node(
+ user_node,
+ "authentication-none",
+ )
+ elif key == "privacy_none":
+ build_child_xml_node(
+ user_node,
+ "privacy-none",
+ )
+ else:
+ sub_dict = user.get(key)
+ sub_node = build_child_xml_node(
+ user_node,
+ key.replace("_", "-"),
+ )
+
+ if "authentication" in key:
+ build_child_xml_node(
+ sub_node,
+ "authentication-key",
+ sub_dict["key"],
+ )
+ build_child_xml_node(
+ sub_node,
+ "authentication-password",
+ sub_dict["password"],
+ )
+ else:
+ build_child_xml_node(
+ sub_node,
+ "privacy-key",
+ sub_dict["key"],
+ )
+ build_child_xml_node(
+ sub_node,
+ "privacy-password",
+ sub_dict["password"],
+ )
+ if "remote_engine" in usm.keys():
+ remotes = usm.get("remote_engine")
+
+ for remote in remotes:
+ remote_node = build_child_xml_node(
+ usm_node,
+ "remote-engine",
+ )
+ if "id" in remote:
+ build_child_xml_node(
+ remote_node,
+ "name",
+ remote.get("id"),
+ )
+ if "users" in remote.keys():
+ users = remote.get("users")
+ for user in users:
+ user_node = build_child_xml_node(
+ remote_node,
+ "user",
+ )
+ for key in user.keys():
+ if key == "name":
+ build_child_xml_node(
+ user_node,
+ "name",
+ user["name"],
+ )
+ elif key == "authentication_none":
+ build_child_xml_node(
+ user_node,
+ "authentication-none",
+ )
+ elif key == "privacy_none":
+ build_child_xml_node(
+ user_node,
+ "privacy-none",
+ )
+ else:
+ sub_dict = user.get(key)
+ sub_node = build_child_xml_node(
+ user_node,
+ key.replace("_", "-"),
+ )
+
+ if "authentication" in key:
+ build_child_xml_node(
+ sub_node,
+ "authentication-key",
+ sub_dict["key"],
+ )
+ build_child_xml_node(
+ sub_node,
+ "authentication-password",
+ sub_dict["password"],
+ )
+ else:
+ build_child_xml_node(
+ sub_node,
+ "privacy-key",
+ sub_dict["key"],
+ )
+ build_child_xml_node(
+ sub_node,
+ "privacy-password",
+ sub_dict["password"],
+ )
+ if "views" in want.keys():
+ views = want.get("views")
+ for view in views:
+ view_node = build_child_xml_node(snmp_node, "view")
+
+ if "name" in view.keys():
+ build_child_xml_node(
+ view_node,
+ "name",
+ view.get("name"),
+ )
+ if "oids" in view.keys():
+ oids = view.get("oids")
+ for oid in oids:
+ oids_node = build_child_xml_node(view_node, "oid")
+ if "oid" in oid.keys():
+ build_child_xml_node(
+ oids_node,
+ "name",
+ oid["oid"],
+ )
+ if "exclude" in oid.keys():
+ build_child_xml_node(oids_node, "exclude")
+ if "include" in oid.keys():
+ build_child_xml_node(oids_node, "include")
+
+ 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
+ """
+ delete = {"delete": "delete"}
+ if have is not None:
+ build_child_xml_node(self.root, "snmp", None, delete)
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/static_routes/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/static_routes/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/static_routes/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/static_routes/static_routes.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/static_routes/static_routes.py
new file mode 100644
index 000000000..a7ba49c9f
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/static_routes/static_routes.py
@@ -0,0 +1,324 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+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, data=None):
+ """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,
+ data=data,
+ )
+ 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}
+ state = self._module.params["state"]
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_static_routes_facts = self.get_static_routes_facts()
+ else:
+ existing_static_routes_facts = []
+ if state == "gathered":
+ existing_static_routes_facts = self.get_static_routes_facts()
+ result["gathered"] = existing_static_routes_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_static_routes_facts(
+ data=running_config,
+ )
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_static_routes_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ 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["commands"] = 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"]
+ if state in ("merged", "replaced", "overridden", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ 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 in ("merged", "rendered"):
+ 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
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/vlans/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/vlans/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/vlans/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/vlans/vlans.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/vlans/vlans.py
new file mode 100644
index 000000000..2a8323319
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/config/vlans/vlans.py
@@ -0,0 +1,254 @@
+# 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_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
+ ConfigBase,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ build_child_xml_node,
+ build_root_xml_node,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+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, data=None):
+ """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,
+ data=data,
+ )
+ 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}
+ state = self._module.params["state"]
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_vlans_facts = self.get_vlans_facts()
+ else:
+ existing_vlans_facts = []
+ if state == "gathered":
+ existing_vlans_facts = self.get_vlans_facts()
+ result["gathered"] = existing_vlans_facts
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_vlans_facts(data=running_config)
+ elif self.state == "rendered":
+ config_xmls = self.set_config(existing_vlans_facts)
+ if config_xmls:
+ result["rendered"] = config_xmls[0]
+ else:
+ result["rendered"] = ""
+
+ else:
+ 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, [])
+
+ 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 in ("merged", "replaced", "overridden", "rendered") and not want:
+ self._module.fail_json(
+ msg="value of config parameter must not be empty for state {0}".format(
+ state,
+ ),
+ )
+ if state == "overridden":
+ config_xmls = self._state_overridden(want, have)
+ elif state == "deleted":
+ config_xmls = self._state_deleted(want, have)
+ elif state in ("merged", "rendered"):
+ 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,
+ )
+ if config.get("l3_interface"):
+ build_child_xml_node(
+ vlan_root,
+ "l3-interface",
+ config.get("l3_interface"),
+ )
+
+ 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
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acl_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acl_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acl_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acl_interfaces/acl_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acl_interfaces/acl_interfaces.py
new file mode 100644
index 000000000..ac91f53ba
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acl_interfaces/acl_interfaces.py
@@ -0,0 +1,160 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos acl_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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.acl_interfaces.acl_interfaces import (
+ Acl_interfacesArgs,
+)
+
+
+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 Acl_interfacesFacts(object):
+ """The junos acl_interfaces fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Acl_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 acl_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=missing_required_lib("lxml"))
+
+ 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 = []
+ 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["junos_acl_interfaces"] = []
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ )
+ for cfg in params["config"]:
+ facts["junos_acl_interfaces"].append(utils.remove_empties(cfg))
+
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_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)
+ config["access_groups"] = []
+
+ if "unit" in conf["interface"] and "family" in conf["interface"]["unit"]:
+ for family in conf["interface"]["unit"]["family"].keys():
+ access_groups = {
+ "afi": "ipv6" if family == "inet6" else "ipv4",
+ "acls": [],
+ }
+ if conf["interface"]["unit"]["family"][family] is not None and conf["interface"][
+ "unit"
+ ]["family"][family].get(
+ "filter",
+ ):
+ for direction in ["input-list", "output-list"]:
+ rendered_direction = "in" if direction == "input-list" else "out"
+ if conf["interface"]["unit"]["family"][family]["filter"].get(direction):
+ acl_name = conf["interface"]["unit"]["family"][family]["filter"][
+ direction
+ ]
+ if not isinstance(acl_name, list):
+ acl_name = [acl_name]
+ for filter_name in acl_name:
+ access_groups["acls"].append(
+ {
+ "name": filter_name,
+ "direction": rendered_direction,
+ },
+ )
+ if access_groups["acls"]:
+ config["name"] = conf["interface"]["name"]
+ config["access_groups"].append(access_groups)
+
+ return utils.remove_empties(config)
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acls/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acls/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acls/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acls/acls.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acls/acls.py
new file mode 100644
index 000000000..a48217d64
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/acls/acls.py
@@ -0,0 +1,246 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos acls 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.acls.acls import (
+ AclsArgs,
+)
+
+
+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 AclsFacts(object):
+ """The junos acls fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = AclsArgs.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 acls
+ :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=missing_required_lib("lxml"))
+
+ if not data:
+ config_filter = """
+ <configuration>
+ <firewall/>
+ </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/firewall")
+
+ objs = []
+ for resource in resources:
+ if resource:
+ xml = self._get_xml_dict(resource)
+ for family, sub_dict in xml["firewall"]["family"].items():
+ sub_dict["family"] = family
+ obj = self.render_config(
+ self.generated_spec,
+ dict(firewall=sub_dict),
+ )
+ if obj:
+ objs.append(obj)
+
+ facts = {}
+ if objs:
+ facts["junos_acls"] = []
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ )
+ for cfg in params["config"]:
+ facts["junos_acls"].append(utils.remove_empties(cfg))
+
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_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)
+ config["afi"] = "ipv6" if conf["firewall"].pop("family") == "inet6" else "ipv4"
+ acls = conf.get("firewall").get("filter")
+ if not isinstance(acls, list):
+ acls = [acls]
+ config["acls"] = []
+ for acl in acls:
+ acl_dict = {"name": acl["name"], "aces": []}
+ if acl.get("term"):
+ terms = acl["term"]
+ if not isinstance(terms, list):
+ terms = [terms]
+ for term in terms:
+ ace = {"name": term.get("name")}
+ if term.get("from"):
+ if term["from"].get("source-address"):
+ ace["source"] = ace.get("source", {})
+ source_address = term["from"].get("source-address")
+ if not isinstance(source_address, list):
+ ace["source"]["address"] = source_address["name"]
+ else:
+ ace["source"]["address"] = []
+ for address in source_address:
+ ace["source"]["address"].append(
+ address["name"],
+ )
+ if term["from"].get("source-prefix-list"):
+ ace["source"] = ace.get("source", {})
+ ace["source"]["prefix_list"] = term["from"]["source-prefix-list"]
+ if term["from"].get("source-port"):
+ ace["source"] = ace.get("source", {})
+ ace["source"]["port_protocol"] = dict(
+ eq=term["from"]["source-port"],
+ )
+ if term["from"].get("destination-address"):
+ ace["destination"] = ace.get("destination", {})
+ destination_address = term["from"].get(
+ "destination-address",
+ )
+ if not isinstance(destination_address, list):
+ ace["destination"]["address"] = destination_address["name"]
+ else:
+ ace["destination"]["address"] = []
+ for address in destination_address:
+ ace["destination"]["address"].append(
+ address["name"],
+ )
+ if term["from"].get("destination-prefix-list"):
+ ace["destination"] = ace.get("destination", {})
+ ace["destination"]["prefix_list"] = term["from"][
+ "destination-prefix-list"
+ ]
+ if term["from"].get("destination-port"):
+ ace["destination"] = ace.get("destination", {})
+ ace["destination"]["port_protocol"] = dict(
+ eq=term["from"]["destination-port"],
+ )
+ if term["from"].get("protocol"):
+ ace["protocol"] = term["from"]["protocol"]
+ if term["from"].get("icmp-type"):
+ ace["protocol_options"] = dict(icmp={})
+ icmp_type = term["from"]["icmp-type"]
+ if icmp_type == "echo-reply":
+ ace["protocol_options"]["icmp"]["echo_reply"] = True
+ if icmp_type == "echo-request":
+ ace["protocol_options"]["icmp"]["echo"] = True
+ if icmp_type == "redirect":
+ ace["protocol_options"]["icmp"]["redirect"] = True
+ if icmp_type == "router-advertisement":
+ ace["protocol_options"]["icmp"]["router_advertisement"] = True
+ if icmp_type == "router-solicit":
+ ace["protocol_options"]["icmp"]["router_solicitation"] = True
+ if icmp_type == "time-exceeded":
+ ace["protocol_options"]["icmp"]["time_exceeded"] = True
+ if term["from"].get("icmp-code"):
+ ace["protocol_options"] = dict(icmp={})
+ icmp_code = term["from"]["icmp-code"]
+ if icmp_code == "destination-host-prohibited":
+ ace["protocol_options"]["icmp"]["dod_host_prohibited"] = True
+ if icmp_code == "destination-host-unknown":
+ ace["protocol_options"]["icmp"]["host_unknown"] = True
+ if icmp_code == "destination-network-prohibited":
+ ace["protocol_options"]["icmp"]["dod_net_prohibited"] = True
+ if icmp_code == "destination-network-unknown":
+ ace["protocol_options"]["icmp"]["network_unknown"] = True
+ if icmp_code == "host-unreachable":
+ ace["protocol_options"]["icmp"]["host_unreachable"] = True
+ if icmp_code == "host-unreachable-for-tos":
+ ace["protocol_options"]["icmp"]["host_tos_unreachable"] = True
+ if icmp_code == "port-unreachable":
+ ace["protocol_options"]["icmp"]["port_unreachable"] = True
+ if icmp_code == "protocol-unreachable":
+ ace["protocol_options"]["icmp"]["protocol_unreachable"] = True
+ if icmp_code == "redirect-for-host":
+ ace["protocol_options"]["icmp"]["host_redirect"] = True
+ if icmp_code == "redirect-for-network":
+ ace["protocol_options"]["icmp"]["net_redirect"] = True
+ if icmp_code == "redirect-for-tos-and-host":
+ ace["protocol_options"]["icmp"]["host_tos_redirect"] = True
+ if icmp_code == "redirect-for-tos-and-net":
+ ace["protocol_options"]["icmp"]["net_tos_redirect"] = True
+ if icmp_code == "source-route-failed":
+ ace["protocol_options"]["icmp"]["source_route_failed"] = True
+ if icmp_code == "ttl-eq-zero-during-reassembly":
+ ace["protocol_options"]["icmp"]["reassembly-timeout"] = True
+ if icmp_code == "ttl-eq-zero-during-transit":
+ ace["protocol_options"]["icmp"]["ttl_exceeded"] = True
+ if term.get("then"):
+ if "accept" in term["then"]:
+ ace["grant"] = "permit"
+ if "discard" in term["then"]:
+ ace["grant"] = "deny"
+ acl_dict["aces"].append(ace)
+ config["acls"].append(acl_dict)
+ return utils.remove_empties(config)
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_address_family/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_address_family/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_address_family/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_address_family/bgp_address_family.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_address_family/bgp_address_family.py
new file mode 100644
index 000000000..0a403fa79
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_address_family/bgp_address_family.py
@@ -0,0 +1,741 @@
+#
+# -*- 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 bgp_address_family 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.bgp_address_family.bgp_address_family import (
+ Bgp_address_familyArgs,
+)
+
+
+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 Bgp_address_familyFacts(object):
+ """The junos bgp_address_family fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Bgp_address_familyArgs.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 get_device_data(self, connection, config_filter):
+ """
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filter)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for bgp_address_family
+ :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>
+ <protocols>
+ <bgp>
+ </bgp>
+ </protocols>
+ <routing-options>
+ <autonomous-system/>
+ </routing-options>
+ </configuration>
+ """
+ data = self.get_device_data(connection, config_filter)
+
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+ objs = {}
+ resources = data.xpath("configuration/protocols/bgp")
+ autonomous_system_path = data.xpath(
+ "configuration/routing-options/autonomous-system",
+ )
+ if autonomous_system_path:
+ self.autonomous_system = self._get_xml_dict(
+ autonomous_system_path.pop(),
+ )
+ else:
+ self.autonomous_system = ""
+ for resource in resources:
+ if resource is not None:
+ xml = self._get_xml_dict(resource)
+ objs = self.render_config(self.generated_spec, xml)
+
+ facts = {}
+ if objs:
+ facts["bgp_address_family"] = {}
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ )
+
+ facts["bgp_address_family"] = utils.remove_empties(
+ params["config"],
+ )
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_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
+ """
+ bgp_af_config = {}
+
+ # Parse facts for BGP address-family global node
+ conf = conf.get("bgp")
+ bgp_af_config["address_family"] = self.parse_af_facts(conf)
+
+ # Parse BGP group address-family config node
+ if "group" in conf.keys():
+ groups = conf.get("group")
+ groups_af_lst = []
+ group_af_dict = {}
+ if isinstance(groups, list):
+ for group in groups:
+ af_facts = self.parse_af_facts(group)
+ if af_facts is not None:
+ group_af_dict["address_family"] = af_facts
+ # Parse neighbors af node
+ if "neighbor" in group.keys():
+ neighbors_af_lst = []
+ nh_af_dict = {}
+ neighbors = group.get("neighbor")
+ if isinstance(neighbors, list):
+ for neighbor in neighbors:
+ # nh_af_dict["name"] = neighbor.get("neighbor_address")
+ naf_facts = self.parse_af_facts(neighbor)
+ if naf_facts is not None:
+ nh_af_dict["address_family"] = naf_facts
+ nh_af_dict["neighbor_address"] = neighbor.get("name")
+ if nh_af_dict:
+ neighbors_af_lst.append(nh_af_dict)
+ nh_af_dict = {}
+ else:
+ naf_facts = self.parse_af_facts(neighbors)
+ if naf_facts is not None:
+ nh_af_dict["address_family"] = naf_facts
+ nh_af_dict["neighbor_address"] = neighbors.get(
+ "name",
+ )
+ if nh_af_dict:
+ neighbors_af_lst.append(nh_af_dict)
+ if neighbors_af_lst:
+ group_af_dict["neighbors"] = neighbors_af_lst
+ if group_af_dict:
+ group_af_dict["name"] = group.get("name")
+ groups_af_lst.append(group_af_dict)
+ group_af_dict = {}
+ else:
+ af_facts = self.parse_af_facts(groups)
+ if af_facts is not None:
+ group_af_dict["address_family"] = af_facts
+ # Parse neighbors af node
+ if "neighbor" in groups.keys():
+ neighbors_af_lst = []
+ nh_af_dict = {}
+ neighbors = groups.get("neighbor")
+ if isinstance(neighbors, list):
+ for neighbor in neighbors:
+ # nh_af_dict["name"] = neighbor.get("name")
+ naf_facts = self.parse_af_facts(neighbor)
+ if naf_facts is not None:
+ nh_af_dict["address_family"] = naf_facts
+ nh_af_dict["neighbor_address"] = neighbor.get(
+ "name",
+ )
+ if nh_af_dict:
+ neighbors_af_lst.append(nh_af_dict)
+ nh_af_dict = {}
+ else:
+ naf_facts = self.parse_af_facts(neighbors)
+ if naf_facts is not None:
+ nh_af_dict["address_family"] = naf_facts
+ nh_af_dict["neighbor_address"] = neighbors.get(
+ "name",
+ )
+ if nh_af_dict:
+ neighbors_af_lst.append(nh_af_dict)
+ if neighbors_af_lst:
+ group_af_dict["neighbors"] = neighbors_af_lst
+ if group_af_dict:
+ group_af_dict["name"] = groups.get("name")
+ groups_af_lst.append(group_af_dict)
+ if groups_af_lst is not None:
+ bgp_af_config["groups"] = groups_af_lst
+
+ return utils.remove_empties(bgp_af_config)
+
+ def parse_af_facts(self, conf):
+ """
+
+ :return:
+ """
+ nlri_params = [
+ "evpn",
+ "inet",
+ "inet-mdt",
+ "inet-mvpn",
+ "inet-vpn",
+ "inet6",
+ "inet6-mvpn",
+ "inet6-vpn",
+ "iso-vpn",
+ "l2vpn",
+ "traffic-engineering",
+ ]
+ # TBD wrap route-target'
+ nlri_types = [
+ "any",
+ "flow",
+ "multicast",
+ "labeled-unicast",
+ "segment-routing-te",
+ "unicast",
+ "signaling",
+ ]
+ bgp = conf.get("family")
+ address_family = []
+ # Parse NLRI Parameters
+ for param in nlri_params:
+ af_dict = {}
+ if bgp and param in bgp.keys():
+ af_type = []
+ nlri_param = bgp.get(param)
+ for nlri in nlri_types:
+ af_dict["afi"] = param
+ if nlri in nlri_param.keys():
+ nlri_dict = self.parse_nlri(nlri_param, nlri)
+ if nlri_dict:
+ af_type.append(nlri_dict)
+ if af_type:
+ af_dict["af_type"] = af_type
+ if af_dict:
+ address_family.append(af_dict)
+
+ return address_family
+
+ def parse_nlri(self, cfg, nlri_t):
+ """
+
+ :param cfg:
+ :return:
+ """
+ nlri_dict = {}
+ if cfg and nlri_t in cfg.keys():
+ nlri_dict["type"] = nlri_t
+ nlri = cfg.get(nlri_t)
+
+ if not nlri:
+ nlri_dict["set"] = True
+ return nlri_dict
+ # Parse accepted-prefix-limit
+ if "accepted-prefix-limit" in nlri.keys():
+ apl_dict = self.parse_accepted_prefix_limit(nlri)
+ # populate accepted_prefix_limit
+ if apl_dict:
+ nlri_dict["accepted_prefix_limit"] = apl_dict
+
+ # Parse add-path
+ if "add-path" in nlri.keys():
+ ap_dict = self.parse_add_path(nlri)
+ # populate accepted_prefix_limit
+ if ap_dict:
+ nlri_dict["add_path"] = ap_dict
+
+ # Parse aggregate-label
+ if "aggregate-label" in nlri.keys():
+ al_dict = self.parse_aggregate_label(nlri)
+ # populate aggregate-label
+ if apl_dict:
+ nlri_dict["aggregate_label"] = al_dict
+
+ # Parse aigp
+ if "aigp" in nlri.keys():
+ aigp_dict = self.parse_aigp(nlri)
+ # populate aigp
+ if aigp_dict:
+ nlri_dict["aigp"] = aigp_dict
+
+ # Parse and populate damping
+ if "damping" in nlri.keys():
+ nlri_dict["damping"] = True
+
+ # Parse defer-initial-multipath-build
+ if "defer-initial-multipath-build" in nlri.keys():
+ dimb_dict = self.parse_defer_initial_multipath_build(nlri)
+ # populate defer_initial_multipath_build
+ if dimb_dict:
+ nlri_dict["defer_initial_multipath_build"] = dimb_dict
+
+ # Parse delay-route-advertisements
+ if "delay-route-advertisements" in nlri.keys():
+ dra_dict = self.parse_delay_route_advertisements(nlri)
+ # populate delay_route_advertisements
+ if dra_dict:
+ nlri_dict["delay_route_advertisements"] = dra_dict
+
+ # Parse entropy-label
+ if "entropy-label" in nlri.keys():
+ el_dict = self.parse_entropy_label(nlri)
+ # populate entropy-label
+ if el_dict:
+ nlri_dict["entropy_label"] = el_dict
+
+ # Parse explicit-null
+ if "explicit-null" in nlri.keys():
+ en_dict = self.parse_explicit_null(nlri)
+ # populate explicit-null
+ if en_dict:
+ nlri_dict["explicit_null"] = en_dict
+
+ # Parse extended-nexthop
+ if "extended-nexthop" in nlri.keys():
+ nlri_dict["extended_nexthop"] = True
+
+ # Parse extended-nexthop-color
+ if "extended-nexthop-color" in nlri.keys():
+ nlri_dict["extended_nexthop_color"] = True
+
+ # Parse forwarding-state-bit
+ if "graceful-restart" in nlri.keys():
+ gr = nlri.get("graceful-restart")
+ if "forwarding-state-bit" in gr.keys():
+ fsb = gr.get("forwarding-state-bit")
+ nlri_dict["graceful_restart_forwarding_state_bit"] = fsb
+
+ # Parse legacy-redirect-ip-action
+ if "legacy-redirect-ip-action" in nlri.keys():
+ lria_dict = self.parse_legacy_redirect_ip_action(nlri)
+ # populate legacy_redirect_ip_action
+ if lria_dict:
+ nlri_dict["legacy_redirect_ip_action"] = lria_dict
+
+ # Parse local-ipv4-address
+ if "local-ipv4-address" in nlri.keys():
+ nlri_dict["local_ipv4_address"] = nlri.get(
+ "local-ipv4-address",
+ )
+
+ # Parse loops
+ if "loops" in nlri.keys():
+ loops = nlri.get("loops")
+ nlri_dict["loops"] = loops.get("loops")
+
+ # Parse no-install
+ if "no-install" in nlri.keys():
+ nlri_dict["no_install"] = True
+
+ # Parse no-validate
+ if "no-validate" in nlri.keys():
+ nlri_dict["no_validate"] = nlri.get("no-validate")
+
+ # Parse output-queue-priority
+ if "output-queue-priority" in nlri.keys():
+ oqp = nlri.get("output-queue-priority")
+ if "expedited" in oqp.keys():
+ nlri_dict["output_queue_priority_expedited"] = True
+ if "priority" in oqp.keys():
+ nlri_dict["output_queue_priority_priority"] = oqp.get(
+ "priority",
+ )
+
+ # Parse per-group-label
+ if "per-group-label" in nlri.keys():
+ nlri_dict["per_group_label"] = True
+
+ # Parse per-prefix-label
+ if "per-prefix-label" in nlri.keys():
+ nlri_dict["per_prefix_label"] = True
+
+ # Parse resolve-vpn
+ if "resolve-vpn" in nlri.keys():
+ nlri_dict["resolve_vpn"] = True
+
+ # Parse prefix-limit
+ if "prefix-limit" in nlri.keys():
+ pl_dict = self.parse_accepted_prefix_limit(nlri)
+ # populate delay_route_advertisements
+ if pl_dict:
+ nlri_dict["prefix_limit"] = pl_dict
+
+ # Parse resolve-vpn
+ if "resolve-vpn" in nlri.keys():
+ nlri_dict["resolve_vpn"] = True
+
+ # Parse rib
+ if "rib" in nlri.keys():
+ nlri_dict["rib"] = "inet.3"
+
+ # Parse rib-group
+ if "rib-group" in nlri.keys():
+ nlri_dict["rib_group"] = nlri.get("rib-group")
+
+ # Parse route-refresh-priority
+ if "route-refresh-priority" in nlri.keys():
+ oqp = nlri.get("route-refresh-priority")
+ if "expedited" in oqp.keys():
+ nlri_dict["route_refresh_priority_expedited"] = True
+ if "priority" in oqp.keys():
+ nlri_dict["route_refresh_priority_priority"] = oqp.get(
+ "priority",
+ )
+
+ # Parse secondary-independent-resolution
+ if "secondary-independent-resolution" in nlri.keys():
+ nlri_dict["secondary_independent_resolution"] = True
+
+ # Parse strip-nexthop
+ if "strip-nexthop" in nlri.keys():
+ nlri_dict["strip_nexthop"] = True
+
+ # Parse topology
+ if "topology" in nlri.keys():
+ t_list = self.parse_topology(nlri)
+ # populate topology
+ if t_list:
+ nlri_dict["topology"] = t_list
+
+ # Parse traffic-statistics
+ if "traffic-statistics" in nlri.keys():
+ ts_dict = self.parse_traffic_statistics(nlri)
+ # populate topology
+ if ts_dict:
+ nlri_dict["traffic_statistics"] = ts_dict
+
+ # Parse withdraw-priority
+ if "withdraw-priority" in nlri.keys():
+ oqp = nlri.get("withdraw-priority")
+ if "expedited" in oqp.keys():
+ nlri_dict["withdraw_priority_expedited"] = True
+ if "priority" in oqp.keys():
+ nlri_dict["withdraw_priority_priority"] = oqp.get(
+ "priority",
+ )
+ return nlri_dict
+
+ def parse_accepted_prefix_limit(self, cfg):
+ """
+
+ :param self:
+ :param cfg:
+ :return:
+ """
+ apl_dict = {}
+ if "accepted-prefix-limit" in cfg.keys():
+ apl = cfg.get("accepted-prefix-limit")
+ else:
+ apl = cfg.get("prefix-limit")
+ if "maximum" in apl.keys():
+ apl_dict["maximum"] = apl.get("maximum")
+ if "teardown" in apl.keys():
+ if not apl.get("teardown"):
+ apl_dict["teardown"] = True
+ else:
+ td = apl.get("teardown")
+ if "idle-timeout" in td.keys():
+ if not td.get("idle-timeout"):
+ apl_dict["idle_timeout"] = True
+ elif "forever" in td["idle-timeout"].keys():
+ apl_dict["forever"] = True
+ elif "timeout" in td["idle-timeout"].keys():
+ apl_dict["idle_timeout_value"] = td["idle-timeout"].get("timeout")
+ if "limit-threshold" in td.keys():
+ apl_dict["limit_threshold"] = td.get("limit-threshold")
+ return apl_dict
+
+ def parse_add_path(self, cfg):
+ """
+
+ :param self:
+ :param cfg:
+ :return:
+ """
+ ap_dict = {}
+ ap = cfg.get("add-path")
+ if "receive" in ap.keys():
+ ap_dict["receive"] = True
+ if "send" in ap.keys():
+ send = ap.get("send")
+ s_dict = {}
+ if "include-backup-path" in send.keys():
+ s_dict["include_backup_path"] = send.get("include-backup-path")
+ if "path-count" in send.keys():
+ s_dict["path_count"] = send.get("path-count")
+ if "multipath" in send.keys():
+ s_dict["multipath"] = True
+ if "path-selection-mode" in send.keys():
+ psm = send.get("path-selection-mode")
+ psm_dict = {}
+ if "all-paths" in psm.keys():
+ psm_dict["all_paths"] = True
+ if "equal-cost-paths" in psm.keys():
+ psm_dict["equal_cost_paths"] = True
+ s_dict["path_selection_mode"] = psm_dict
+ if "prefix-policy" in send.keys():
+ s_dict["prefix_policy"] = send.get("prefix-policy")
+ ap_dict["send"] = s_dict
+ return ap_dict
+
+ def parse_aggregate_label(self, cfg):
+ """
+
+ :param self:
+ :param cfg:
+ :return:
+ """
+ al_dict = {}
+ al = cfg.get("aggregate-label")
+ if not al:
+ al_dict["set"] = True
+ else:
+ al_dict["community"] = al.get("community")
+ return al_dict
+
+ def parse_aigp(self, cfg):
+ """
+
+ :param self:
+ :param cfg:
+ :return:
+ """
+ aigp_dict = {}
+ aigp = cfg.get("aigp")
+ if aigp and "disable" in aigp.keys():
+ aigp_dict["disable"] = True
+ else:
+ aigp_dict["set"] = True
+ return aigp_dict
+
+ def parse_defer_initial_multipath_build(self, cfg):
+ """
+
+ :param self:
+ :param cfg:
+ :return:
+ """
+ dimb_dict = {}
+ dimb = cfg.get("defer-initial-multipath-build")
+ if not dimb:
+ dimb_dict["set"] = True
+
+ elif "maximum-delay" in dimb.keys():
+ dimb_dict["maximum_delay"] = dimb.get("maximum-delay")
+ return dimb_dict
+
+ def parse_legacy_redirect_ip_action(self, cfg):
+ """
+
+ :param self:
+ :param cfg:
+ :return:
+ """
+ lria_dict = {}
+ lria = cfg.get("legacy-redirect-ip-action")
+ if not lria:
+ lria_dict["set"] = True
+ else:
+ if "send" in lria.keys():
+ lria_dict["send"] = True
+ if "receive" in lria.keys():
+ lria_dict["receive"] = True
+ return lria_dict
+
+ def parse_delay_route_advertisements(self, cfg):
+ """
+
+ :param self:
+ :param cfg:
+ :return:
+ """
+ dra_dict = {}
+ dra = cfg.get("delay-route-advertisements")
+ if not dra:
+ dra_dict["set"] = True
+ else:
+ if "maximum-delay" in dra.keys():
+ mxd = dra.get("maximum-delay")
+ if "route-age" in mxd.keys():
+ dra_dict["max_delay_route_age"] = mxd.get("route-age")
+ if "routing-uptime" in mxd.keys():
+ dra_dict["max_delay_routing_uptime"] = mxd.get(
+ "routing-uptime",
+ )
+ if "minimum-delay" in dra.keys():
+ mid = dra.get("minimum-delay")
+ if "inbound-convergence" in mid.keys():
+ dra_dict["min_delay_inbound_convergence"] = mid.get(
+ "inbound-convergence",
+ )
+ if "routing-uptime" in mid.keys():
+ dra_dict["min_delay_routing_uptime"] = mid.get(
+ "routing-uptime",
+ )
+ return dra_dict
+
+ def parse_entropy_label(self, cfg):
+ """
+
+ :param self:
+ :param cfg:
+ :return:
+ """
+ el_dict = {}
+ el = cfg.get("entropy-label")
+ if not el:
+ el_dict["set"] = True
+ else:
+ if "import" in el.keys():
+ el_dict["import"] = el.get("import")
+ if "no-next-hop-validation" in el.keys():
+ el_dict["no_next_hop_validation"] = True
+ return el_dict
+
+ def parse_explicit_null(self, cfg):
+ """
+
+ :param self:
+ :param cfg:
+ :return:
+ """
+ en_dict = {}
+ en = cfg.get("explicit-null")
+ if not en:
+ en_dict["set"] = True
+ elif "connected-only" in en.keys():
+ en_dict["connected_only"] = True
+ return en_dict
+
+ def parse_topology(self, cfg):
+ """
+
+ :param self:
+ :param cfg:
+ :return:
+ """
+ top_dict = {}
+ topology_list = []
+ topologies = cfg.get("topology")
+ if isinstance(topologies, list):
+ for topology in topologies:
+ top_dict["name"] = topology["name"]
+ communities = topology.get("community")
+ community_lst = []
+ if isinstance(communities, list):
+ for community in communities:
+ community_lst.append(community)
+ else:
+ community_lst.append(communities)
+ if community_lst is not None:
+ top_dict["community"] = community_lst
+ if top_dict is not None:
+ topology_list.append(top_dict)
+ top_dict = {}
+ else:
+ top_dict["name"] = topologies["name"]
+ communities = topologies.get("community")
+ community_lst = []
+ if isinstance(communities, list):
+ for community in communities:
+ community_lst.append(community)
+ else:
+ community_lst.append(communities)
+ if community_lst is not None:
+ top_dict["community"] = community_lst
+ if top_dict is not None:
+ topology_list.append(top_dict)
+ return topology_list
+
+ def parse_traffic_statistics(self, cfg):
+ """
+
+ :param self:
+ :param cfg:
+ :return:
+ """
+ ts_dict = {}
+ ts = cfg.get("traffic-statistics")
+ if not ts:
+ ts_dict["set"] = True
+ else:
+ if "interval" in ts.keys():
+ ts_dict["interval"] = ts.get("interval")
+ if "labeled-path" in ts.keys():
+ ts_dict["labeled_path"] = True
+ if "file" in ts.keys():
+ file = ts.get("file")
+ file_dict = {}
+ if "files" in file.keys():
+ file_dict["files"] = file.get("files")
+ if "no-world-readable" in file.keys():
+ file_dict["no_world_readable"] = True
+ if "size" in file.keys():
+ file_dict["size"] = file.get("size")
+ if "world-readable" in file.keys():
+ file_dict["world_readable"] = True
+
+ return ts_dict
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_global/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_global/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_global/bgp_global.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_global/bgp_global.py
new file mode 100644
index 000000000..a8cfa99c7
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/bgp_global/bgp_global.py
@@ -0,0 +1,1090 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos bgp_global 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ generate_dict,
+ remove_empties,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.bgp_global.bgp_global import (
+ Bgp_globalArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.utils.utils import (
+ _validate_config,
+)
+
+
+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 Bgp_globalFacts(object):
+ """The junos bgp_global fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Bgp_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 = generate_dict(facts_argument_spec)
+
+ def get_device_data(self, connection, config_filter):
+ """
+
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filter)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for bgp_global
+ :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>
+ <protocols>
+ <bgp>
+ </bgp>
+ </protocols>
+ <routing-options>
+ <autonomous-system/>
+ </routing-options>
+ </configuration>
+ """
+ data = self.get_device_data(connection, config_filter)
+
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+ objs = {}
+ resources = data.xpath("configuration/protocols/bgp")
+ autonomous_system_path = data.xpath(
+ "configuration/routing-options/autonomous-system",
+ )
+ if autonomous_system_path:
+ self.autonomous_system = self._get_xml_dict(
+ autonomous_system_path.pop(),
+ )
+ else:
+ self.autonomous_system = ""
+ for resource in resources:
+ if resource is not None:
+ xml = self._get_xml_dict(resource)
+ objs = self.render_config(self.generated_spec, xml)
+ if not objs:
+ if self.autonomous_system and self.autonomous_system.get(
+ "autonomous-system",
+ ):
+ objs["as_number"] = self.autonomous_system["autonomous-system"].get("as-number")
+ if self.autonomous_system["autonomous-system"].get("loops"):
+ objs["loops"] = self.autonomous_system["autonomous-system"].get("loops")
+ if "asdot-notation" in self.autonomous_system["autonomous-system"]:
+ objs["asdot_notation"] = True
+ facts = {}
+ if objs:
+ facts["bgp_global"] = {}
+ params = _validate_config(
+ self._module,
+ self.argument_spec,
+ {"config": objs},
+ redact=True,
+ )
+ facts["bgp_global"] = remove_empties(params["config"])
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_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
+ """
+ bgp_global = {}
+ bgp = conf.get("bgp")
+ # Set ASN value into facts
+ if self.autonomous_system and self.autonomous_system.get(
+ "autonomous-system",
+ ):
+ bgp_global["as_number"] = self.autonomous_system["autonomous-system"].get("as-number")
+ if self.autonomous_system["autonomous-system"].get("loops"):
+ bgp_global["loops"] = self.autonomous_system["autonomous-system"].get("loops")
+ if "asdot-notation" in self.autonomous_system["autonomous-system"]:
+ bgp_global["asdot_notation"] = True
+
+ self.parse_attrib(bgp_global, bgp)
+
+ # Read group
+ if "group" in bgp.keys():
+ bgp_groups = []
+ bgp_group = {}
+ groups = bgp.get("group")
+ if isinstance(groups, dict):
+ self.parse_attrib(bgp_group, groups)
+ # parse neighbors
+ if "neighbor" in groups.keys():
+ neighbors_lst = []
+ neighbors_dict = {}
+ neighbors = groups.get("neighbor")
+ if isinstance(neighbors, dict):
+ self.parse_attrib(
+ neighbors_dict,
+ neighbors,
+ "neighbor",
+ )
+ if neighbors_dict:
+ neighbors_lst.append(neighbors_dict)
+ else:
+ for neighbor in neighbors:
+ self.parse_attrib(
+ neighbors_dict,
+ neighbor,
+ "neighbor",
+ )
+ if neighbors_dict:
+ neighbors_lst.append(neighbors_dict)
+ neighbors_dict = {}
+ if neighbors_lst:
+ bgp_group["neighbors"] = neighbors_lst
+
+ if bgp_group:
+ bgp_groups.append(bgp_group)
+ else:
+ for group in groups:
+ bgp_group = {}
+ self.parse_attrib(bgp_group, group)
+ # Parse neighbors in the group list
+ if "neighbor" in group.keys():
+ neighbors_lst = []
+ neighbors_dict = {}
+ neighbors = group.get("neighbor")
+ if isinstance(neighbors, dict):
+ self.parse_attrib(
+ neighbors_dict,
+ neighbors,
+ "neighbor",
+ )
+ if neighbors_dict:
+ neighbors_lst.append(neighbors_dict)
+ else:
+ for neighbor in neighbors:
+ self.parse_attrib(
+ neighbors_dict,
+ neighbor,
+ "neighbor",
+ )
+ if neighbors_dict:
+ neighbors_lst.append(neighbors_dict)
+ neighbors_dict = {}
+
+ if neighbors_lst:
+ bgp_group["neighbors"] = neighbors_lst
+
+ if bgp_group:
+ bgp_groups.append(bgp_group)
+ bgp_global["groups"] = bgp_groups
+ remove_empties(bgp_global)
+ return bgp_global
+
+ def parse_attrib(self, cfg_dict, conf, type=None):
+ # Read accept-remote-nexthop value
+ if "accept-remote-nexthop" in conf.keys():
+ cfg_dict["accept_remote_nexthop"] = True
+
+ # Read add-path-display-ipv4-address value
+ if "add-path-display-ipv4-address" in conf.keys():
+ cfg_dict["add_path_display_ipv4_address"] = True
+
+ # Parse advertise-bgp-static dictionary
+ if "advertise-bgp-static" in conf.keys():
+ cfg = {}
+ if conf.get("advertise-bgp-static") and "advertise-bgp-static" in conf.keys():
+ if "policy" in conf["advertise-bgp-static"]:
+ cfg["policy"] = conf["advertise-bgp-static"].get("policy")
+ else:
+ cfg["set"] = True
+ cfg_dict["advertise_bgp_static"] = cfg
+
+ # Parse advertise-external dictionary
+ if "advertise-external" in conf.keys():
+ cfg = {}
+ if (
+ isinstance(conf.get("advertise-external"), dict)
+ and "conditional" in conf["advertise-external"].keys()
+ ):
+ cfg["conditional"] = True
+ else:
+ cfg["set"] = True
+ cfg_dict["advertise_external"] = cfg
+
+ # Read advertise-from-main-vpn-tables value
+ if "advertise-from-main-vpn-tables" in conf.keys():
+ cfg_dict["advertise_from_main_vpn_tables"] = True
+
+ # Read advertise-inactive value
+ if "advertise-inactive" in conf.keys():
+ cfg_dict["advertise_inactive"] = True
+
+ # Read advertise-peer-as value
+ if "advertise-peer-as" in conf.keys():
+ cfg_dict["advertise_peer_as"] = True
+
+ # Read authentication-algorithm value
+ if "authentication-algorithm" in conf.keys():
+ cfg_dict["authentication_algorithm"] = conf["authentication-algorithm"]
+
+ # Read authentication-key value
+ if "authentication-key" in conf.keys():
+ cfg_dict["authentication_key"] = conf["authentication-key"]
+
+ # Read authentication-key-chain value
+ if "authentication-key-chain" in conf.keys():
+ cfg_dict["authentication_key_chain"] = conf["authentication-key-chain"]
+
+ # Parse bfd-liveness-detection dictionary
+ if "bfd-liveness-detection" in conf.keys():
+ cfg = {}
+ bld = conf["bfd-liveness-detection"]
+ # Parse authentication dictionary
+ if "authentication" in bld.keys():
+ a_dict = {}
+ authentication = bld["authentication"]
+ if "algorithm" in authentication.keys():
+ a_dict["algorithm"] = authentication["algorithm"]
+ if "key-chain" in authentication.keys():
+ a_dict["key_chain"] = authentication["key-chain"]
+ if "loose-check" in authentication.keys():
+ a_dict["loose_check"] = True
+ cfg["authentication"] = a_dict
+
+ # Parse detection-time dictionary
+ if "detection-time" in bld.keys():
+ dt_dict = {}
+ d_time = bld["detection-time"]
+ if "threshold" in d_time.keys():
+ dt_dict["threshold"] = d_time["threshold"]
+ cfg["detection_time"] = dt_dict
+ # Parse transmit-interval dictionary
+ if "transmit-interval" in bld.keys():
+ t_dict = {}
+ t_int = bld["transmit-interval"]
+ if "minimum-interval" in t_int.keys():
+ t_dict["minimum_interval"] = t_int["minimum-interval"]
+ cfg["transmit_interval"] = t_dict
+
+ # Read holddown-interval value
+ if "holddown-interval" in bld.keys():
+ cfg["holddown_interval"] = bld["holddown-interval"]
+
+ # Read minimum-receive-interval value
+ if "minimum-receive-interval" in bld.keys():
+ cfg["minimum_receive_interval"] = bld["minimum-receive-interval"]
+
+ # Read minimum-interval value
+ if "minimum-interval" in bld.keys():
+ cfg["minimum_interval"] = bld["minimum-interval"]
+
+ # Read multiplier value
+ if "multiplier" in bld.keys():
+ cfg["multiplier"] = bld["multiplier"]
+
+ # Read no-adaptation value
+ if "no-adaptation" in bld.keys():
+ cfg["no_adaptation"] = True
+
+ # Read session-mode value
+ if "session-mode" in bld.keys():
+ cfg["session_mode"] = bld["session-mode"]
+
+ # Read version value
+ if "version" in bld.keys():
+ cfg["version"] = bld["version"]
+
+ # write the bfd_liveness_detection to bgp global config dictionary
+ cfg_dict["bfd_liveness_detection"] = cfg
+
+ # Parse bgp-error-tolerance dictionary
+ if "bgp-error-tolerance" in conf.keys():
+ cfg = {}
+ bet = conf["bgp-error-tolerance"]
+ # Parse authentication dictionary
+ if "malformed-route-limit" in bet.keys():
+ cfg["malformed_route_limit"] = bet["malformed-route-limit"]
+ if "malformed-update-log-interval" in bet.keys():
+ cfg["malformed_update_log_interval"] = bet["malformed-update-log-interval"]
+ if "no-malformed-route-limit" in bet.keys():
+ cfg["no_malformed_route_limit"] = True
+ # write the bfd_liveness_detection to bgp global config dictionary
+ cfg_dict["bgp_error_tolerance"] = cfg
+
+ # Parse bmp dictionary
+ if "bmp" in conf.keys():
+ cfg = {}
+ bmp = conf["bmp"]
+ # Parse authentication dictionary
+ if "route-monitoring" in bmp.keys():
+ rm_dict = {}
+ r_monitoring = bmp["route-monitoring"]
+
+ # Read none attribute value
+ if "none" in r_monitoring.keys():
+ rm_dict["none"] = True
+
+ # Read post-policy attribute value
+ if "post-policy" in r_monitoring.keys():
+ if r_monitoring["post-policy"].get("exclude-non-eligible"):
+ rm_dict["post_policy_exclude_non_eligible"] = True
+ else:
+ rm_dict["post_policy"] = True
+
+ # Read pre-policy attribute value
+ if "pre-policy" in r_monitoring.keys():
+ if r_monitoring["pre-policy"].get("exclude-non-feasible"):
+ rm_dict["pre_policy_exclude_non_feasible"] = True
+ else:
+ rm_dict["pre_policy"] = True
+ cfg["route_monitoring"] = rm_dict
+ # Read monitor value
+ if "monitor" in bmp.keys():
+ if bmp["monitor"] == "disable":
+ cfg["monitor"] = False
+ else:
+ cfg["monitor"] = True
+
+ # write the bmp to bgp global config dictionary
+ cfg_dict["bmp"] = cfg
+
+ # Read cluster value
+ if "cluster" in conf.keys():
+ cfg_dict["cluster_id"] = conf["cluster"]
+
+ # Read damping value
+ if "damping" in conf.keys():
+ cfg_dict["damping"] = True
+
+ # Read description value
+ if "description" in conf.keys():
+ cfg_dict["description"] = conf["description"]
+
+ # Read disable value
+ if "disable" in conf.keys():
+ cfg_dict["disable"] = True
+
+ # Read egress-te value
+ if "egress-te" in conf.keys():
+ cfg = {}
+ if conf.get("egress-te") and "backup-path" in conf["egress-te"].keys():
+ cfg["backup_path"] = conf["egress-te"].get("backup-path")
+ else:
+ cfg["set"] = True
+ cfg_dict["egress_te"] = cfg
+
+ # Read egress-te-backup-paths
+ if "egress-te-backup-paths" in conf.keys():
+ cfg = {}
+ templates_lst = []
+ template_dict = {}
+ templates = conf["egress-te-backup-paths"].get("template")
+ if isinstance(templates, dict):
+ template_dict["path_name"] = templates["name"]
+ if "remote-nexthop" in templates.keys():
+ template_dict["remote_nexthop"] = templates["remote-nexthop"].get(
+ "remote-nh-addr",
+ )
+ if "peer" in templates.keys():
+ peer_lst = []
+ peers = templates.get("peer")
+ if isinstance(peers, dict):
+ peer_lst.append(peers.get("name"))
+ else:
+ for peer in peers:
+ peer_lst.append(peer.get("name"))
+ template_dict["peers"] = peer_lst
+
+ if "ip-forward" in templates.keys():
+ ipf_dict = {}
+ if templates.get("ip-forward") is None:
+ ipf_dict["set"] = True
+ else:
+ ipf_dict["rti_name"] = templates["ip-forward"].get(
+ "rti-name",
+ )
+ template_dict["ip_forward"] = ipf_dict
+ if template_dict:
+ templates_lst.append(template_dict)
+ else:
+ # We have list of templates
+ for template in templates:
+ template_dict = {}
+ template_dict["path_name"] = template["name"]
+ if "remote-nexthop" in template.keys():
+ template_dict["remote_nexthop"] = template["remote-nexthop"].get(
+ "remote-nh-addr",
+ )
+ if "peer" in template.keys():
+ peer_lst = []
+ peers = template.get("peer")
+ if isinstance(peers, dict):
+ peer_lst.append(peers.get("name"))
+ else:
+ for peer in peers:
+ peer_lst.append(peer.get("name"))
+ template_dict["peers"] = peer_lst
+ if "ip-forward" in template.keys():
+ ipf_dict = {}
+ if template.get("ip-forward") is None:
+ ipf_dict["set"] = True
+ else:
+ ipf_dict["rti_name"] = template["ip-forward"].get(
+ "rti-name",
+ )
+ template_dict["ip_forward"] = ipf_dict
+
+ if template_dict:
+ templates_lst.append(template_dict)
+
+ if templates:
+ cfg["templates"] = templates_lst
+ cfg_dict["egress_te_backup_paths"] = cfg
+
+ # Read egress-te-set-segment
+ if "egress-te-set-segment" in conf.keys():
+ etss_lst = []
+ etss_dict = {}
+ etsss = conf["egress-te-set-segment"]
+ if isinstance(etsss, dict):
+ etss_dict["name"] = etsss.get("name")
+ if "label" in etsss.keys():
+ etss_dict["label"] = etsss["label"].get("label-value")
+ if "egress-te-backup-segment" in etsss.keys():
+ etbs = etsss.get("egress-te-backup-segment")
+ etss_dict["egress_te_backup_segment_label"] = etbs["label"].get("label-value")
+
+ if etss_dict:
+ etss_lst.append(etss_dict)
+ else:
+ for etss in etsss:
+ etss_dict["name"] = etss.get("name")
+ if "label" in etss.keys():
+ etss_dict["label"] = etss["label"].get("label-value")
+ if "egress-te-backup-segment" in etss.keys():
+ etbs = etss.get("egress-te-backup-segment")
+ etss_dict["egress_te_backup_segment_label"] = etbs["label"].get(
+ "label-value",
+ )
+
+ if etss_dict:
+ etss_lst.append(etss_dict)
+ etss_dict = {}
+ cfg_dict["egress_te_set_segment"] = etss_lst
+
+ # Read egress-te-sid-stats value
+ if "egress-te-sid-stats" in conf.keys():
+ cfg_dict["egress_te_sid_stats"] = True
+
+ # Read enforce-first-as value
+ if "enforce-first-as" in conf.keys():
+ cfg_dict["enforce_first_as"] = True
+
+ # Read export value
+ if "export" in conf.keys():
+ cfg_dict["export"] = conf["export"]
+
+ # Read forwarding-context value
+ if "forwarding-context" in conf.keys():
+ cfg_dict["forwarding_context"] = conf["forwarding-context"]
+
+ # Read graceful-restart
+ if "graceful-restart" in conf.keys():
+ cfg = {}
+ gr = conf.get("graceful-restart")
+ if gr is None:
+ cfg["set"] = True
+ else:
+ if "disable" in gr.keys():
+ cfg["disable"] = True
+ if "dont-help-shared-fate-bfd-down" in gr.keys():
+ cfg["dont_help_shared_fate_bfd_down"] = True
+ # read forwarding-state-bit
+ if "forwarding-state-bit" in gr.keys():
+ fsb_dict = {}
+ if "as-rr-client" == gr.get("forwarding-state-bit"):
+ fsb_dict["as_rr_client"] = True
+ if "from-fib" == gr.get("forwarding-state-bit"):
+ fsb_dict["from_fib"] = True
+ cfg["forwarding_state_bit"] = fsb_dict
+ # read long-lived
+ if "long-lived" in gr.keys():
+ ll_dict = {}
+ ll = gr.get("long-lived")
+ # read advertise_to_non_llgr_neighbor
+ if "advertise-to-non-llgr-neighbor" in ll.keys():
+ atnln_dict = {}
+ atnln = ll.get("advertise-to-non-llgr-neighbor")
+ if atnln is None:
+ atnln_dict["set"] = True
+ else:
+ atnln_dict["omit_no_export"] = True
+ ll_dict["advertise_to_non_llgr_neighbor"] = atnln_dict
+ if "receiver" in ll.keys():
+ ll_dict["receiver_disable"] = True
+ cfg["long_lived"] = ll_dict
+ # read restart-time
+ if "restart-time" in gr.keys():
+ cfg["restart_time"] = gr.get("restart-time")
+ # read stale-routes-time
+ if "stale-routes-time" in gr.keys():
+ cfg["stale_routes_time"] = gr.get("stale-routes-time")
+
+ cfg_dict["graceful_restart"] = cfg
+
+ # Read hold-time value
+ if "hold-time" in conf.keys():
+ cfg_dict["hold_time"] = conf["hold-time"]
+
+ # Read holddown-all-stale-labels value
+ if "holddown-all-stale-labels" in conf.keys():
+ cfg_dict["holddown_all_stale_labels"] = True
+
+ # Read idle-after-switch-over
+ if "idle-after-switch-over" in conf.keys():
+ cfg = {}
+ iaso = conf.get("idle-after-switch-over")
+ if "forever" in iaso.keys():
+ cfg["forever"] = True
+ else:
+ cfg["timeout"] = iaso.get("timeout")
+ cfg_dict["idle_after_switch_over"] = cfg
+
+ # Read import value
+ if "import" in conf.keys():
+
+ imports = conf.get("import")
+ import_lst = []
+ if isinstance(imports, dict):
+ import_lst.append(imports)
+ else:
+ for entry in imports:
+ import_lst.append(entry)
+ cfg_dict["import"] = import_lst
+
+ # Read include-mp-next-hop value
+ if "include-mp-next-hop" in conf.keys():
+ cfg_dict["include_mp_next_hop"] = True
+
+ # Read ipsec-sa value
+ if "ipsec-sa" in conf.keys():
+ cfg_dict["ipsec_sa"] = conf["ipsec-sa"]
+
+ # Read keep value
+ if "keep" in conf.keys():
+ cfg_dict["keep"] = conf["keep"]
+
+ # Read local-address value
+ if "local-address" in conf.keys():
+ cfg_dict["local_address"] = conf["local-address"]
+
+ # Read local_as value
+ if "local-as" in conf.keys():
+ cfg = {}
+ la = conf.get("local-as")
+ cfg["as_num"] = la.get("as-number")
+ if "alias" in la.keys():
+ cfg["alias"] = True
+ if "private" in la.keys():
+ cfg["private"] = True
+ if "loops" in la.keys():
+ cfg["loops"] = la.get("loops")
+ if "no-prepend-global-as" in la.keys():
+ cfg["no_prepend_global_as"] = True
+ cfg_dict["local_as"] = cfg
+
+ # Read local-interface value
+ if "local-interface" in conf.keys():
+ cfg_dict["local_interface"] = conf["local-interface"]
+
+ # Read local-preference value
+ if "local-preference" in conf.keys():
+ cfg_dict["local_preference"] = conf["local-preference"]
+
+ # Read log-updown value
+ if "log-updown" in conf.keys():
+ cfg_dict["log_updown"] = True
+
+ # Read metric-out
+ if "metric-out" in conf.keys():
+ cfg = {}
+ mo = conf.get("metric-out")
+ # metric value
+ if "metric-value" in mo.keys():
+ cfg["metric_value"] = mo.get("metric-value")
+ # read igp
+ if "igp" in mo.keys():
+ igp_dict = {}
+ igp = mo.get("igp")
+ if igp is None:
+ igp_dict["set"] = True
+ else:
+ if "metric-offset" in igp.keys():
+ igp_dict["metric_offset"] = igp.get("metric-offset")
+ if "delay-med-update" in igp.keys():
+ igp_dict["delay_med_update"] = True
+ cfg["igp"] = igp_dict
+ # read minimum-igp
+ if "minimum-igp" in mo.keys():
+ minigp_dict = {}
+ minigp = mo.get("minimum-igp")
+ if minigp is None:
+ minigp_dict["set"] = True
+ else:
+ if "metric-offset" in minigp.keys():
+ minigp_dict["metric_offset"] = minigp.get(
+ "metric-offset",
+ )
+ cfg["minimum_igp"] = minigp_dict
+ cfg_dict["metric_out"] = cfg
+
+ # Read mtu-discovery value
+ if "mtu-discovery" in conf.keys():
+ cfg_dict["mtu_discovery"] = True
+
+ # Read multihop value
+ if "multihop" in conf.keys():
+ cfg = {}
+ multihop = conf.get("multihop")
+ if multihop is None:
+ cfg["set"] = True
+ else:
+ if "no-nexthop-change" in multihop.keys():
+ cfg["no_nexthop_change"] = True
+ if "ttl" in multihop.keys():
+ cfg["ttl"] = multihop.get("ttl")
+ cfg_dict["multihop"] = cfg
+
+ # Read multipath
+ if "multipath" in conf.keys():
+ cfg = {}
+ multipath = conf.get("multipath")
+ if multipath is None:
+ cfg["set"] = True
+ else:
+ if "disable" in multipath.keys():
+ cfg["disable"] = True
+ if "multiple-as" in multipath.keys():
+ mas = multipath.get("multiple-as")
+ if mas is None:
+ cfg["multiple_as"] = True
+ else:
+ cfg["multiple_as_disable"] = True
+
+ cfg_dict["multipath"] = cfg
+
+ # Read no-advertise-peer-as value
+ if "no-advertise-peer-as" in conf.keys():
+ cfg_dict["no_advertise_peer_as"] = True
+
+ # Read no-aggregator-id value
+ if "no-aggregator-id" in conf.keys():
+ cfg_dict["no_aggregator_id"] = True
+
+ # Read no-client-reflect value
+ if "no-client-reflect" in conf.keys():
+ cfg_dict["no_client_reflect"] = True
+
+ # Read no-precision-timers value
+ if "no-precision-timers" in conf.keys():
+ cfg_dict["no_precision_timers"] = True
+
+ # Read out-delay value
+ if "out-delay" in conf.keys():
+ cfg_dict["out_delay"] = conf["out-delay"]
+
+ # Read outbound-route-filter
+ if "outbound-route-filter" in conf.keys():
+ cfg = {}
+ orf = conf.get("outbound-route-filter")
+ # read outbound-route-filter
+ if "bgp-orf-cisco-mode" in orf.keys():
+ cfg["bgp_orf_cisco_mode"] = True
+ # read prefix-based
+ if "prefix-based" in orf.keys():
+ pb = orf.get("prefix-based")
+ pb_dict = {}
+ if pb is None:
+ pb_dict["set"] = True
+ else:
+ if "accept" in pb.keys():
+ # read accept node attributes
+ accept = pb.get("accept")
+ accept_dict = {}
+ if accept is None:
+ accept_dict["set"] = True
+ else:
+ if "inet" in accept.keys():
+ accept_dict["inet"] = True
+ if "inet6" in accept.keys():
+ accept_dict["inet6"] = True
+ pb_dict["accept"] = accept_dict
+ cfg["prefix_based"] = pb_dict
+
+ cfg_dict["outbound_route_filter"] = cfg
+
+ # Read output-queue-priority value
+ if "output-queue-priority" in conf.keys():
+ cfg = {}
+ oqp_dict = {}
+ oqp = conf.get("output-queue-priority")
+ # read defaults
+ if "defaults" in oqp.keys():
+ defaults = oqp.get("defaults")
+ defaults_dict = {}
+ # read high
+ if "high" in defaults.keys():
+ high_dict = {}
+ high = defaults.get("high")
+ if "expedited" in high:
+ high_dict["expedited"] = True
+
+ defaults_dict["high"] = high_dict
+ # read low
+ if "low" in defaults.keys():
+ low_dict = {}
+ low = defaults.get("low")
+ if "expedited" in low:
+ low_dict["expedited"] = True
+ # read medium
+ if "medium" in defaults.keys():
+ medium_dict = {}
+ medium = defaults.get("medium")
+ if "expedited" in medium:
+ medium_dict["expedited"] = True
+ oqp_dict["defaults"] = defaults_dict
+
+ # read expedited
+ if "expedited" in oqp.keys():
+ expedited = oqp.get("expedited")
+ if "update-tokens" in expedited:
+ oqp_dict["expedited_update_tokens"] = expedited.get(
+ "update-tokens",
+ )
+
+ # read priority
+ if "priority" in oqp.keys():
+ priority_lst = []
+ priority_dict = {}
+ priority = oqp.get("priority")
+ if isinstance(priority, dict):
+ priority_dict["priority"] = priority.get("name")
+ priority_dict["update_tokens"] = priority.get(
+ "update-tokens",
+ )
+ priority_lst.append(priority_dict)
+ else:
+ for element in priority:
+ priority_dict["priority"] = element.get("name")
+ priority_dict["update_tokens"] = element.get(
+ "update-tokens",
+ )
+ priority_lst.append(priority_dict)
+ priority_dict = {}
+
+ oqp_dict["priority_update_tokens"] = priority_lst
+
+ cfg_dict["output_queue_priority"] = oqp_dict
+
+ # Read passive value
+ if "passive" in conf.keys():
+ cfg_dict["passive"] = True
+
+ # Read path-selection value
+ if "path-selection" in conf.keys():
+ ps_dict = {}
+ ps = conf.get("path-selection")
+ if "always-compare-med" in ps.keys():
+ ps_dict["always_compare_med"] = True
+ if "as-path-ignore" in ps.keys():
+ ps_dict["as_path_ignore"] = True
+ if "external-router-id" in ps.keys():
+ ps_dict["external_router_id"] = True
+ if "cisco-non-deterministic" in ps.keys():
+ ps_dict["cisco_non_deterministic"] = True
+ if "l2vpn-use-bgp-rules" in ps.keys():
+ ps_dict["l2vpn_use_bgp_rules"] = True
+ # read med-plus-igp
+ if "med-plus-igp" in ps.keys():
+ mpi_dict = {}
+ mpi = ps.get("med-plus-igp")
+ if mpi is None:
+ mpi_dict["set"] = True
+ else:
+ if "igp-multiplier" in mpi.keys():
+ mpi_dict["igp_multiplier"] = mpi.get("igp-multiplier")
+ if "med-multiplier" in mpi.keys():
+ mpi_dict["med_multiplier"] = mpi.get("med-multiplier")
+ ps_dict["med_plus_igp"] = mpi_dict
+
+ cfg_dict["path_selection"] = ps_dict
+
+ # Read peer-as value
+ if "peer-as" in conf.keys():
+ cfg_dict["peer_as"] = conf["peer-as"]
+
+ # Read precision-timers value
+ if "precision-timers" in conf.keys():
+ cfg_dict["precision_timers"] = True
+
+ # Read preference value
+ if "preference" in conf.keys():
+ cfg_dict["preference"] = conf["preference"]
+
+ # Read remove-private value
+ if "remove-private" in conf.keys():
+ rp_dict = {}
+ rp = conf.get("remove-private")
+ if rp is None:
+ rp_dict["set"] = True
+ else:
+ if "all" in rp.keys():
+ all = rp.get("all")
+ if all is None:
+ rp_dict["all"] = True
+ else:
+ if "replace" in all.keys():
+ replace = all.get("replace")
+ if replace is None:
+ rp_dict["all_replace"] = True
+ else:
+ rp_dict["all_replace_nearest"] = True
+
+ cfg_dict["remove_private"] = rp_dict
+
+ # Read rfc6514-compliant-safi129 value
+ if "rfc6514-compliant-safi129" in conf.keys():
+ cfg_dict["rfc6514_compliant_safi129"] = True
+
+ # Read route-server-client value
+ if "route-server-client" in conf.keys():
+ cfg_dict["route_server_client"] = True
+
+ # Read send-addpath-optimization value
+ if "send-addpath-optimization" in conf.keys():
+ cfg_dict["send_addpath_optimization"] = True
+
+ # Read snmp-options value
+ if "snmp-options" in conf.keys():
+ cfg = {}
+ so = conf.get("snmp-options")
+ if "backward-traps-only-from-established" in so:
+ cfg["backward_traps_only_from_established"] = True
+ if "emit-inet-address-length-in-oid" in so:
+ cfg["emit_inet_address_length_in_oid"] = True
+ cfg_dict["snmp_options"] = cfg
+
+ # Read sr-preference-override value
+ if "sr-preference-override" in conf.keys():
+ cfg_dict["sr_preference_override"] = conf["sr-preference-override"]
+
+ # Read stale-labels-holddown-period value
+ if "stale-labels-holddown-period" in conf.keys():
+ cfg_dict["stale_labels_holddown_period"] = conf["stale-labels-holddown-period"]
+
+ # Read tcp-aggressive-transmission value
+ if "tcp-aggressive-transmission" in conf.keys():
+ cfg_dict["tcp_aggressive_transmission"] = True
+
+ # Read tcp-mss value
+ if "tcp-mss" in conf.keys():
+ cfg_dict["tcp_mss"] = conf["tcp-mss"]
+
+ # Read traceoptions value
+ if "traceoptions" in conf.keys():
+ to_dict = {}
+ to = conf.get("traceoptions")
+ # read file
+ if "file" in to.keys():
+ file_dict = {}
+ file = to.get("file")
+ if "filename" in file.keys():
+ file_dict["filename"] = file.get("filename")
+ if "files" in file.keys():
+ file_dict["files"] = file.get("files")
+ if "no-world-readable" in file.keys():
+ file_dict["no_world_readable"] = True
+ if "world-readable" in file.keys():
+ file_dict["world_readable"] = True
+ if "size" in file.keys():
+ file_dict["size"] = file.get("size")
+ to_dict["file"] = file_dict
+ # read flag
+ if "flag" in to.keys():
+ flag_lst = []
+ flag = to.get("flag")
+ for event in flag:
+ flag_dict = {}
+ if event is not None:
+ if "detail" in event.keys():
+ flag_dict["detail"] = True
+ if "disable" in event.keys():
+ flag_dict["disable"] = True
+ if "receive" in event.keys():
+ flag_dict["receive"] = True
+ if "send" in event.keys():
+ flag_dict["send"] = True
+ if "filter" in event.keys():
+ filter_dict = {}
+ filter = event.get("filter")
+ if filter is None:
+ filter_dict["set"] = True
+ else:
+ if "match-on" in filter.keys():
+ filter_dict["match_on_prefix"] = True
+ if "policy" in filter.keys():
+ filter_dict["policy"] = filter.get(
+ "policy",
+ )
+ flag_dict["filter"] = filter_dict
+ flag_dict["name"] = event.get("name")
+ flag_lst.append(flag_dict)
+
+ to_dict["flag"] = flag_lst
+ cfg_dict["traceoptions"] = to_dict
+ # Read traffic-statistics-labeled-path
+ if "traffic-statistics-labeled-path" in conf.keys():
+ tslp_dict = {}
+ tslp = conf.get("traffic-statistics-labeled-path")
+ # read file
+ if "file" in tslp.keys():
+ file_dict = {}
+ file = tslp.get("file")
+ if "filename" in file.keys():
+ file_dict["filename"] = file.get("filename")
+ if "files" in file.keys():
+ file_dict["files"] = file.get("files")
+ if "no-world-readable" in file.keys():
+ file_dict["no_world_readable"] = True
+ if "world-readable" in file.keys():
+ file_dict["world_readable"] = True
+ if "size" in file.keys():
+ file_dict["size"] = file.get("size")
+ tslp_dict["file"] = file_dict
+ # read interval
+ if "interval" in tslp.keys():
+ tslp_dict["interval"] = tslp.get("interval")
+
+ cfg_dict["traffic_statistics_labeled_path"] = tslp_dict
+ # Read ttl value
+ if "ttl" in conf.keys():
+ cfg_dict["ttl"] = conf["ttl"]
+
+ # Read unconfigured-peer-graceful-restart value
+ if "unconfigured-peer-graceful-restart" in conf.keys():
+ cfg_dict["unconfigured_peer_graceful_restart"] = True
+
+ # Read vpn-apply-export value
+ if "vpn-apply-export" in conf.keys():
+ cfg_dict["vpn_apply_export"] = True
+
+ # Read group name value
+ if "name" in conf.keys():
+ if type == "neighbor":
+ cfg_dict["neighbor_address"] = conf["name"]
+ else:
+ cfg_dict["name"] = conf["name"]
+
+ # Read as-override value
+ if "as-override" in conf.keys():
+ cfg_dict["as_override"] = True
+
+ # Read allow
+ if "allow" in conf.keys():
+ allow_lst = []
+ allow = conf["allow"]
+ if isinstance(allow, list):
+ for item in allow:
+ allow_lst.append(item)
+ else:
+ allow_lst.append(allow)
+ if allow_lst:
+ cfg_dict["allow"] = allow_lst
+
+ # Read optimal-route-reflection
+ if "optimal-route-reflection" in conf.keys():
+ orr_dict = {}
+ orr = conf["optimal-route-reflection"]
+
+ if "igp-backup" in orr.keys():
+ orr_dict["igp_backup"] = orr.get("igp-backup")
+
+ if "igp-primary" in orr.keys():
+ orr_dict["igp_primary"] = orr.get("igp-primary")
+ cfg_dict["optimal_route_reflection"] = orr_dict
+
+ # Read group type value
+ if "type" in conf.keys():
+ cfg_dict["type"] = conf["type"]
+
+ # Read unconfigured-peer-graceful-restart value
+ if "unconfigured-peer-graceful-restart" in conf.keys():
+ cfg_dict["unconfigured_peer_graceful_restart"] = True
+
+ # Read vpn-apply-export value
+ if "vpn-apply-export" in conf.keys():
+ cfg_dict["vpn_apply_export"] = True
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/facts.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/facts.py
new file mode 100644
index 000000000..bf596dcc4
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/facts.py
@@ -0,0 +1,203 @@
+#
+# -*- 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 __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts import (
+ FactsBase,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.acl_interfaces.acl_interfaces import (
+ Acl_interfacesFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.acls.acls import (
+ AclsFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.bgp_address_family.bgp_address_family import (
+ Bgp_address_familyFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.bgp_global.bgp_global import (
+ Bgp_globalFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.hostname.hostname import (
+ HostnameFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.interfaces.interfaces import (
+ InterfacesFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.l2_interfaces.l2_interfaces import (
+ L2_interfacesFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.l3_interfaces.l3_interfaces import (
+ L3_interfacesFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.lacp.lacp import (
+ LacpFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.lacp_interfaces.lacp_interfaces import (
+ Lacp_interfacesFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.lag_interfaces.lag_interfaces import (
+ Lag_interfacesFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.legacy.base import (
+ Config,
+ Default,
+ Hardware,
+ Interfaces,
+ OFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.lldp_global.lldp_global import (
+ Lldp_globalFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.lldp_interfaces.lldp_interfaces import (
+ Lldp_interfacesFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.logging_global.logging_global import (
+ Logging_globalFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.ntp_global.ntp_global import (
+ Ntp_globalFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.ospf_interfaces.ospf_interfaces import (
+ Ospf_interfacesFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.ospfv2.ospfv2 import (
+ Ospfv2Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.ospfv3.ospfv3 import (
+ Ospfv3Facts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.prefix_lists.prefix_lists import (
+ Prefix_listsFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.routing_instances.routing_instances import (
+ Routing_instancesFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.routing_options.routing_options import (
+ Routing_optionsFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.security_policies.security_policies import (
+ Security_policiesFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.security_policies_global.security_policies_global import (
+ Security_policies_globalFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.security_zones.security_zones import (
+ Security_zonesFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.snmp_server.snmp_server import (
+ Snmp_serverFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.static_routes.static_routes import (
+ Static_routesFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.vlans.vlans import (
+ VlansFacts,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ HAS_PYEZ,
+)
+
+
+FACT_LEGACY_SUBSETS = dict(
+ default=Default,
+ hardware=Hardware,
+ config=Config,
+ interfaces=Interfaces,
+)
+FACT_RESOURCE_SUBSETS = dict(
+ acls=AclsFacts,
+ acl_interfaces=Acl_interfacesFacts,
+ 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,
+ ospf=Ospfv2Facts,
+ ospfv3=Ospfv3Facts,
+ ospf_interfaces=Ospf_interfacesFacts,
+ vlans=VlansFacts,
+ static_routes=Static_routesFacts,
+ bgp_global=Bgp_globalFacts,
+ bgp_address_family=Bgp_address_familyFacts,
+ routing_instances=Routing_instancesFacts,
+ prefix_lists=Prefix_listsFacts,
+ logging_global=Logging_globalFacts,
+ ntp_global=Ntp_globalFacts,
+ security_policies=Security_policiesFacts,
+ security_policies_global=Security_policies_globalFacts,
+ security_zones=Security_zonesFacts,
+ snmp_server=Snmp_serverFacts,
+ routing_options=Routing_optionsFacts,
+ hostname=HostnameFacts,
+)
+
+
+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
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/hostname/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/hostname/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/hostname/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/hostname/hostname.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/hostname/hostname.py
new file mode 100644
index 000000000..9078ff456
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/hostname/hostname.py
@@ -0,0 +1,137 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos hostname 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.hostname.hostname import (
+ HostnameArgs,
+)
+
+
+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 HostnameFacts(object):
+ """The junos hostname fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = HostnameArgs.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 get_device_data(self, connection, config_filter):
+ """
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filter)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for ntp_gloabl
+ :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>
+ <system>
+ </system>
+ </configuration>
+ """
+ data = self.get_device_data(connection, config_filter)
+
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+ objs = {}
+ resources = data.xpath("configuration/system/host-name")
+ for resource in resources:
+ if resource is not None:
+ xml = self._get_xml_dict(resource)
+ objs = self.render_config(self.generated_spec, xml)
+
+ facts = {}
+ if objs:
+ facts["hostname"] = {}
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ )
+
+ facts["hostname"] = utils.remove_empties(params["config"])
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_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
+ """
+ hostname_config = {}
+
+ # Parse facts for hostname node
+
+ if "host-name" in conf.keys():
+ hostname_config["hostname"] = conf.get("host-name")
+ return utils.remove_empties(hostname_config)
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/interfaces/interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/interfaces/interfaces.py
new file mode 100644
index 000000000..e83265603
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/interfaces/interfaces.py
@@ -0,0 +1,179 @@
+#
+# -*- 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.interfaces.interfaces import (
+ InterfacesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.utils.utils import (
+ get_resource_config,
+)
+
+
+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 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 get_config(self, connection, config_filter):
+ """
+
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return get_resource_config(connection, config_filter=config_filter)
+
+ 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 = self.get_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 _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_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 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
+ cfg = self._get_xml_dict(conf)
+ unit_cfg = cfg.get("interface")
+ if "unit" in unit_cfg.keys():
+ units = unit_cfg.get("unit")
+ unit_lst = []
+ unit_dict = {}
+ if isinstance(units, dict):
+ if "description" in units.keys():
+ unit_dict["name"] = units["name"]
+ unit_dict["description"] = units["description"]
+ unit_lst.append(unit_dict)
+ else:
+ for unit in units:
+ if "description" in unit.keys():
+ unit_dict["name"] = unit["name"]
+ unit_dict["description"] = unit["description"]
+ unit_lst.append(unit_dict)
+ unit_dict = {}
+ config["units"] = unit_lst
+
+ return utils.remove_empties(config)
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l2_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l2_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l2_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l2_interfaces/l2_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l2_interfaces/l2_interfaces.py
new file mode 100644
index 000000000..19d85e0d0
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l2_interfaces/l2_interfaces.py
@@ -0,0 +1,162 @@
+#
+# -*- 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.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.l2_interfaces.l2_interfaces import (
+ L2_interfacesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.utils.utils import (
+ get_resource_config,
+)
+
+
+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 get_config(self, connection, config_filter):
+ """
+
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return get_resource_config(connection, config_filter=config_filter)
+
+ 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 = self.get_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)
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l3_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l3_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l3_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l3_interfaces/l3_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l3_interfaces/l3_interfaces.py
new file mode 100644
index 000000000..010c3d77c
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/l3_interfaces/l3_interfaces.py
@@ -0,0 +1,180 @@
+#
+# -*- 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.basic import missing_required_lib
+from ansible.module_utils.six import iteritems, string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.l3_interfaces.l3_interfaces import (
+ L3_interfacesArgs,
+)
+
+
+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 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 get_config(self, connection, config_filter):
+ """
+
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filter)
+
+ def _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_dict
+
+ 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 = self.get_config(connection, config_filter)
+
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+ resources = data.xpath("configuration/interfaces/interface")
+ config = []
+ if resources:
+ config = self.parse_l3_if_resources(resources)
+ 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:
+ int_have = self._get_xml_dict(iface)
+ int_dict = int_have["interface"]
+ if "unit" in int_dict.keys() and int_dict.get("unit") is not None:
+ unit_list = int_dict["unit"]
+ if isinstance(unit_list, list):
+ for item in unit_list:
+ fact_dict = self._render_l3_intf(item, int_dict)
+ if fact_dict:
+ l3_ifaces.append(fact_dict)
+ else:
+ fact_dict = self._render_l3_intf(unit_list, int_dict)
+ if fact_dict:
+ l3_ifaces.append(fact_dict)
+ return l3_ifaces
+
+ def _render_l3_intf(self, unit, int_dict):
+ """
+
+ :param item:
+ :param int_dict:
+ :return:
+ """
+ interface = {}
+ ipv4 = []
+ ipv6 = []
+ if "family" in unit.keys():
+ if "inet" in unit["family"].keys():
+ interface["name"] = int_dict["name"]
+ interface["unit"] = unit["name"]
+ inet = unit["family"].get("inet")
+ if inet is not None and "address" in inet.keys():
+ if isinstance(inet["address"], dict):
+ for key, value in iteritems(inet["address"]):
+ addr = {}
+ addr["address"] = value
+ ipv4.append(addr)
+ else:
+ for ip in inet["address"]:
+ addr = {}
+ addr["address"] = ip["name"]
+ ipv4.append(addr)
+ if "inet" in unit["family"].keys():
+ interface["name"] = int_dict["name"]
+ interface["unit"] = unit["name"]
+ inet = unit["family"].get("inet")
+ if inet is not None and "dhcp" in inet.keys():
+ addr = {}
+ addr["address"] = "dhcp"
+ ipv4.append(addr)
+ if "inet6" in unit["family"].keys():
+ interface["name"] = int_dict["name"]
+ interface["unit"] = unit["name"]
+ inet6 = unit["family"].get("inet6")
+ if inet6 is not None and "address" in inet6.keys():
+ if isinstance(inet6["address"], dict):
+ for key, value in iteritems(inet6["address"]):
+ addr = {}
+ addr["address"] = value
+ ipv6.append(addr)
+ else:
+ for ip in inet6["address"]:
+ addr = {}
+ addr["address"] = ip["name"]
+ ipv4.append(addr)
+ interface["ipv4"] = ipv4
+ interface["ipv6"] = ipv6
+ return utils.remove_empties(interface)
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp/lacp.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp/lacp.py
new file mode 100644
index 000000000..6c3ecd904
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp/lacp.py
@@ -0,0 +1,119 @@
+#
+# -*- 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.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.lacp.lacp import (
+ LacpArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.utils.utils import (
+ get_resource_config,
+)
+
+
+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
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp_interfaces/lacp_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp_interfaces/lacp_interfaces.py
new file mode 100644
index 000000000..52b776a53
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lacp_interfaces/lacp_interfaces.py
@@ -0,0 +1,146 @@
+#
+# -*- 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.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.lacp_interfaces.lacp_interfaces import (
+ Lacp_interfacesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.utils.utils import (
+ get_resource_config,
+)
+
+
+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
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lag_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lag_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lag_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lag_interfaces/lag_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lag_interfaces/lag_interfaces.py
new file mode 100644
index 000000000..5066cac9f
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lag_interfaces/lag_interfaces.py
@@ -0,0 +1,160 @@
+#
+# -*- 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.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.lag_interfaces.lag_interfaces import (
+ Lag_interfacesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.utils.utils import (
+ get_resource_config,
+)
+
+
+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
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/legacy/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/legacy/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/legacy/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/legacy/base.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/legacy/base.py
new file mode 100644
index 000000000..11f6544aa
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/legacy/base.py
@@ -0,0 +1,232 @@
+# -*- 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
+
+import platform
+
+
+try:
+ import xmltodict
+
+ HAS_XMLTODICT = True
+except ImportError:
+ HAS_XMLTODICT = False
+
+from ansible.module_utils._text import to_text
+from ansible.module_utils.basic import missing_required_lib
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ exec_rpc,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ get_capabilities,
+ get_configuration,
+ get_device,
+ tostring,
+)
+
+
+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 _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+ xml_dict = xmltodict.parse(
+ tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_dict
+
+ 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})
+ if "chassis-sub-module" in child.tag:
+ mod["chassis_sub_module"] = self._get_xml_dict(obj)["chassis-module"][
+ "chassis-sub-module"
+ ]
+ 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
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_global/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_global/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_global/lldp_global.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_global/lldp_global.py
new file mode 100644
index 000000000..df82a2695
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_global/lldp_global.py
@@ -0,0 +1,115 @@
+#
+# -*- 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.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.lldp_global.lldp_global import (
+ Lldp_globalArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.utils.utils import (
+ get_resource_config,
+)
+
+
+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
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_interfaces/lldp_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_interfaces/lldp_interfaces.py
new file mode 100644
index 000000000..a5d1af467
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/lldp_interfaces/lldp_interfaces.py
@@ -0,0 +1,115 @@
+#
+# -*- 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.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.lldp_interfaces.lldp_interfaces import (
+ Lldp_interfacesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.utils.utils import (
+ get_resource_config,
+)
+
+
+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/>
+ </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)
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/logging_global/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/logging_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/logging_global/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/logging_global/logging_global.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/logging_global/logging_global.py
new file mode 100644
index 000000000..2affbde19
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/logging_global/logging_global.py
@@ -0,0 +1,428 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos logging_global 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.logging_global.logging_global import (
+ Logging_globalArgs,
+)
+
+
+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 Logging_globalFacts(object):
+ """The junos logging_global fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Logging_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 get_device_data(self, connection, config_filter):
+ """
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filter)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for logging_gloabl
+ :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>
+ <system>
+ <syslog>
+ </syslog>
+ </system>
+ </configuration>
+ """
+ data = self.get_device_data(connection, config_filter)
+
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+ objs = {}
+ resources = data.xpath("configuration/system/syslog")
+ for resource in resources:
+ if resource is not None:
+ xml = self._get_xml_dict(resource)
+ objs = self.render_config(self.generated_spec, xml)
+
+ facts = {}
+ if objs:
+ facts["logging_global"] = {}
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ )
+
+ facts["logging_global"] = utils.remove_empties(params["config"])
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_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
+ """
+ logging_gloabl_config = {}
+
+ # Parse facts for BGP address-family global node
+ conf = conf.get("syslog")
+
+ # Read allow-duplicates node
+ if "allow-duplicates" in conf.keys():
+ logging_gloabl_config["allow_duplicates"] = True
+
+ # Read archive node
+ if "archive" in conf.keys():
+ archive_dict = self.parse_archive_node(conf.get("archive"))
+ logging_gloabl_config["archive"] = archive_dict
+
+ # Read console node
+ if "console" in conf.keys():
+ console_dict = self.parse_console_node(conf.get("console"))
+ logging_gloabl_config["console"] = console_dict
+
+ # Read file node
+ if "file" in conf.keys():
+ files_list = self.parse_file_node(conf.get("file"))
+ logging_gloabl_config["files"] = files_list
+
+ # Read host node
+ if "host" in conf.keys():
+ hosts_list = self.parse_host_node(conf.get("host"))
+ logging_gloabl_config["hosts"] = hosts_list
+
+ # Read log-rotate-frequency node
+ if "log-rotate-frequency" in conf.keys():
+ logging_gloabl_config["log_rotate_frequency"] = conf.get(
+ "log-rotate-frequency",
+ )
+
+ # Read routing-instance node
+ if "routing-instance" in conf.keys():
+ logging_gloabl_config["routing_instance"] = conf.get(
+ "routing-instance",
+ )
+
+ # Read source-address node
+ if "source-address" in conf.keys():
+ logging_gloabl_config["source_address"] = conf.get(
+ "source-address",
+ )
+
+ # Read user node
+ if "user" in conf.keys():
+ users_list = self.parse_user_node(conf.get("user"))
+ logging_gloabl_config["users"] = users_list
+
+ # Read time-format
+ if "time-format" in conf.keys():
+ time_format_dict = {}
+ time_format = conf.get("time-format")
+ if time_format is None:
+ time_format_dict["set"] = True
+ else:
+ if "millisecond" in time_format.keys():
+ time_format_dict["millisecond"] = True
+ if "year" in time_format.keys():
+ time_format_dict["year"] = True
+ logging_gloabl_config["time_format"] = time_format_dict
+
+ return utils.remove_empties(logging_gloabl_config)
+
+ def parse_archive_node(self, conf):
+ archive_dict = {}
+ if conf is not None:
+ # Read child attributes
+ if "binary-data" in conf.keys():
+ archive_dict["binary_data"] = True
+ if "files" in conf.keys():
+ archive_dict["files"] = conf.get("files")
+ if "no-binary-data" in conf.keys():
+ archive_dict["no_binary_data"] = True
+ if "no-world-readable" in conf.keys():
+ archive_dict["no_world_readable"] = True
+ if "size" in conf.keys():
+ archive_dict["file_size"] = conf.get("size")
+ if "world-readable" in conf.keys():
+ archive_dict["world_readable"] = True
+ if "archive-sites" in conf.keys():
+ archive_sites_list = []
+ archive_sites = conf.get("archive-sites")
+ if isinstance(archive_sites, list):
+ for item in archive_sites:
+ archive_sites_list.append(item["name"])
+ else:
+ archive_sites_list.append(archive_sites["name"])
+ archive_dict["archive_sites"] = archive_sites_list
+ else:
+ archive_dict["set"] = True
+
+ return archive_dict
+
+ def parse_console_node(self, conf, console_dict=None):
+ console_loggings = [
+ "any",
+ "authorization",
+ "change-log",
+ "conflict-log",
+ "daemon",
+ "dfc",
+ "external",
+ "firewall",
+ "ftp",
+ "interactive-commands",
+ "kernel",
+ "ntp",
+ "pfe",
+ "security",
+ "user",
+ ]
+ if console_dict is None:
+ console_dict = {}
+ # Read any node
+ if isinstance(conf, dict):
+ for item in console_loggings:
+ if item in conf.get("name"):
+ any_dict = {}
+ for k, v in conf.items():
+ if k != "name":
+ any_dict["level"] = k
+ console_dict[item.replace("-", "_")] = any_dict
+ else:
+ for console in conf:
+ for item in console_loggings:
+ if item in console.get("name"):
+ any_dict = {}
+ for k, v in console.items():
+ if k != "name":
+ any_dict["level"] = k
+ console_dict[item.replace("-", "_")] = any_dict
+
+ return console_dict
+
+ def parse_file_node(self, conf):
+ files_list = []
+ files = []
+ if isinstance(conf, dict):
+ files.append(conf)
+ else:
+ files = conf
+ for file in files:
+ file_dict = {}
+ # Read file name node
+ file_dict["name"] = file.get("name")
+ # Read allow-duplicates node
+ if "allow-duplicates" in file:
+ file_dict["allow_duplicates"] = True
+ # Read contents
+ if "contents" in file.keys():
+ contents = file.get("contents")
+ if isinstance(contents, list):
+ for content in contents:
+ file_dict = self.parse_console_node(content, file_dict)
+ else:
+ file_dict = self.parse_console_node(contents, file_dict)
+ # Read archives
+ if "archive" in file.keys():
+ archive_dict = self.parse_archive_node(file.get("archive"))
+ file_dict["archive"] = archive_dict
+ # Read explicit priority
+ if "explicit-priority" in file.keys():
+ file_dict["explicit_priority"] = True
+ # Read match
+ if "match" in file.keys():
+ file_dict["match"] = file.get("match")
+ # Read match-strings
+ if "match-strings" in file.keys():
+ match_strings = file.get("match-strings")
+ match_strings_list = []
+ if isinstance(match_strings, list):
+ for item in match_strings:
+ match_strings_list.append(item)
+ else:
+ match_strings_list.append(match_strings)
+ file_dict["match_strings"] = match_strings_list
+ # Read srtructured-data
+ if "structured-data" in file.keys():
+ structured_data_dict = {}
+ if file.get("structured-data"):
+ structured_data_dict["brief"] = True
+ else:
+ structured_data_dict["set"] = True
+ file_dict["structured_data"] = structured_data_dict
+ files_list.append(file_dict)
+ return files_list
+
+ def parse_host_node(self, conf):
+ hosts_list = []
+ hosts = []
+ if isinstance(conf, dict):
+ hosts.append(conf)
+ else:
+ hosts = conf
+ for host in hosts:
+ host_dict = {}
+ # Read file name node
+ host_dict["name"] = host.get("name")
+ # Read allow-duplicates node
+ if "allow-duplicates" in host:
+ host_dict["allow_duplicates"] = True
+ # Read contents
+ if "contents" in host.keys():
+ contents = host.get("contents")
+ if isinstance(contents, list):
+ for content in contents:
+ host_dict = self.parse_console_node(content, host_dict)
+ else:
+ host_dict = self.parse_console_node(contents, host_dict)
+ # Read exclude-hostname node
+ if "exclude-hostname" in host.keys():
+ host_dict["exclude_hostname"] = True
+ # Read facility-override node
+ if "facility-override" in host.keys():
+ host_dict["facility_override"] = host.get("facility-override")
+ # Read log-prefix node
+ if "log-prefix" in host.keys():
+ host_dict["log_prefix"] = host.get("log-prefix")
+ # Read match
+ if "match" in host.keys():
+ host_dict["match"] = host.get("match")
+ # Read match-strings
+ if "match-strings" in host.keys():
+ match_strings = host.get("match-strings")
+ match_strings_list = []
+ if isinstance(match_strings, list):
+ for item in match_strings:
+ match_strings_list.append(item)
+ else:
+ match_strings_list.append(match_strings)
+ host_dict["match_strings"] = match_strings_list
+ # Read port node
+ if "port" in host.keys():
+ host_dict["port"] = host.get("port")
+ # Read routing-instance node
+ if "routing-instance" in host.keys():
+ host_dict["routing_instance"] = host.get("routing-instance")
+ # Read source-address node
+ if "source-address" in host.keys():
+ host_dict["source_address"] = host.get("source-address")
+ # Read srtructured-data
+ if "structured-data" in host.keys():
+ structured_data_dict = {}
+ if host.get("structured-data"):
+ structured_data_dict["brief"] = True
+ else:
+ structured_data_dict["set"] = True
+ host_dict["structured_data"] = structured_data_dict
+
+ hosts_list.append(host_dict)
+
+ return hosts_list
+
+ def parse_user_node(self, conf):
+ users_list = []
+ users = []
+ if isinstance(conf, dict):
+ users.append(conf)
+ else:
+ users = conf
+ for user in users:
+ user_dict = {}
+ # Read file name node
+ user_dict["name"] = user.get("name")
+ # Read allow-duplicates node
+ if "allow-duplicates" in user:
+ user_dict["allow_duplicates"] = True
+ # Read contents
+ if "contents" in user.keys():
+ contents = user.get("contents")
+ if isinstance(contents, list):
+ for content in contents:
+ user_dict = self.parse_console_node(content, user_dict)
+ else:
+ user_dict = self.parse_console_node(contents, user_dict)
+ # Read match
+ if "match" in user.keys():
+ user_dict["match"] = user.get("match")
+ # Read match-strings
+ if "match-strings" in user.keys():
+ match_strings = user.get("match-strings")
+ match_strings_list = []
+ if isinstance(match_strings, list):
+ for item in match_strings:
+ match_strings_list.append(item)
+ else:
+ match_strings_list.append(match_strings)
+ user_dict["match_strings"] = match_strings_list
+
+ users_list.append(user_dict)
+
+ return users_list
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ntp_global/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ntp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ntp_global/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ntp_global/ntp_global.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ntp_global/ntp_global.py
new file mode 100644
index 000000000..a7dc37b57
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ntp_global/ntp_global.py
@@ -0,0 +1,320 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos ntp_global 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.ntp_global.ntp_global import (
+ Ntp_globalArgs,
+)
+
+
+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 Ntp_globalFacts(object):
+ """The junos ntp_global fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Ntp_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 get_device_data(self, connection, config_filter):
+ """
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filter)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for ntp_gloabl
+ :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>
+ <system>
+ <ntp>
+ </ntp>
+ </system>
+ </configuration>
+ """
+ data = self.get_device_data(connection, config_filter)
+
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+ objs = {}
+ resources = data.xpath("configuration/system/ntp")
+ for resource in resources:
+ if resource is not None:
+ xml = self._get_xml_dict(resource)
+ objs = self.render_config(self.generated_spec, xml)
+
+ facts = {}
+ if objs:
+ facts["ntp_global"] = {}
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ )
+
+ facts["ntp_global"] = utils.remove_empties(params["config"])
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_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
+ """
+ ntp_global_config = {}
+
+ # Parse facts for BGP address-family global node
+ conf = conf.get("ntp")
+
+ # Read allow-duplicates node
+ if "authentication-key" in conf.keys():
+ auth_key_lst = []
+ auth_keys = conf.get("authentication-key")
+ auth_key_dict = {}
+ if isinstance(auth_keys, dict):
+ auth_key_dict["id"] = auth_keys["name"]
+ auth_key_dict["algorithm"] = auth_keys["type"]
+ auth_key_dict["key"] = auth_keys["value"]
+ auth_key_lst.append(auth_key_dict)
+
+ else:
+ for auth_key in auth_keys:
+ auth_key_dict["id"] = auth_key["name"]
+ auth_key_dict["algorithm"] = auth_key["type"]
+ auth_key_dict["key"] = auth_key["value"]
+ auth_key_lst.append(auth_key_dict)
+ auth_key_dict = {}
+ if auth_key_lst:
+ ntp_global_config["authentication_keys"] = auth_key_lst
+
+ # Read boot-server node
+ if "boot-server" in conf.keys():
+ ntp_global_config["boot_server"] = conf.get("boot-server")
+
+ # Read broadcast node
+ if "broadcast" in conf.keys():
+ broadcast_lst = []
+ broadcasts = conf.get("broadcast")
+ broadcast_dict = {}
+ if isinstance(broadcasts, dict):
+ broadcast_dict["address"] = broadcasts["name"]
+ if "key" in broadcasts.keys():
+ broadcast_dict["key"] = broadcasts["key"]
+ if "ttl" in broadcasts.keys():
+ broadcast_dict["ttl"] = broadcasts["ttl"]
+ if "version" in broadcasts.keys():
+ broadcast_dict["version"] = broadcasts["version"]
+ if "routing-instance-name" in broadcasts.keys():
+ broadcast_dict["routing_instance_name"] = broadcasts["routing-instance-name"]
+ broadcast_lst.append(broadcast_dict)
+
+ else:
+ for broadcast in broadcasts:
+ broadcast_dict["address"] = broadcast["name"]
+ if "key" in broadcast.keys():
+ broadcast_dict["key"] = broadcast["key"]
+ if "ttl" in broadcast.keys():
+ broadcast_dict["ttl"] = broadcast["ttl"]
+ if "version" in broadcast.keys():
+ broadcast_dict["version"] = broadcast["version"]
+ if "routing-instance-name" in broadcast.keys():
+ broadcast_dict["routing_instance_name"] = broadcast["routing-instance-name"]
+ broadcast_lst.append(broadcast_dict)
+ broadcast_dict = {}
+ if broadcast_lst:
+ ntp_global_config["broadcasts"] = broadcast_lst
+
+ # Read broadcast-client node
+ if "broadcast-client" in conf.keys():
+ ntp_global_config["broadcast_client"] = True
+
+ # Read interval-range node
+ if "interval-range" in conf.keys():
+ ntp_global_config["interval_range"] = conf["interval-range"].get(
+ "value",
+ )
+
+ # Read multicast-client node
+ if "multicast-client" in conf.keys():
+ ntp_global_config["multicast_client"] = conf["multicast-client"].get("address")
+
+ # Read peer node
+ if "peer" in conf.keys():
+ peer_lst = []
+ peers = conf.get("peer")
+ peer_dict = {}
+ if isinstance(peers, dict):
+ peer_dict["peer"] = peers["name"]
+ if "key" in peers.keys():
+ peer_dict["key_id"] = peers["key"]
+ if "prefer" in peers.keys():
+ peer_dict["prefer"] = True
+ if "version" in peers.keys():
+ peer_dict["version"] = peers["version"]
+ peer_lst.append(peer_dict)
+
+ else:
+ for peer in peers:
+ peer_dict["peer"] = peer["name"]
+ if "key" in peer.keys():
+ peer_dict["key_id"] = peer["key"]
+ if "prefer" in peer.keys():
+ peer_dict["prefer"] = True
+ if "version" in peer.keys():
+ peer_dict["version"] = peer["version"]
+ peer_lst.append(peer_dict)
+ peer_dict = {}
+ if peer_lst:
+ ntp_global_config["peers"] = peer_lst
+
+ # Read server node
+ if "server" in conf.keys():
+ server_lst = []
+ servers = conf.get("server")
+ server_dict = {}
+ if isinstance(servers, dict):
+ server_dict["server"] = servers["name"]
+ if "key" in servers.keys():
+ server_dict["key_id"] = servers["key"]
+ if "prefer" in servers.keys():
+ server_dict["prefer"] = True
+ if "version" in servers.keys():
+ server_dict["version"] = servers["version"]
+ if "routing-instance" in servers.keys():
+ server_dict["routing-instance"] = servers["routing-instance"]
+ server_lst.append(server_dict)
+
+ else:
+ for server in servers:
+ server_dict["server"] = server["name"]
+ if "key" in server.keys():
+ server_dict["key_id"] = server["key"]
+ if "prefer" in server.keys():
+ server_dict["prefer"] = True
+ if "version" in server.keys():
+ server_dict["version"] = server["version"]
+ if "routing-instance" in server.keys():
+ server_dict["routing_instance"] = server["routing-instance"]
+ server_lst.append(server_dict)
+ server_dict = {}
+ if server_lst:
+ ntp_global_config["servers"] = server_lst
+
+ # Read source-address node
+ if "source-address" in conf.keys():
+ source_address_lst = []
+ source_addresses = conf.get("source-address")
+ source_address_dict = {}
+ if isinstance(source_addresses, dict):
+ source_address_dict["source_address"] = source_addresses["name"]
+ if "routing-instance" in source_addresses.keys():
+ source_address_dict["routing_instance"] = source_addresses["routing-instance"]
+ source_address_lst.append(source_address_dict)
+
+ else:
+ for source_address in source_addresses:
+ source_address_dict["source_address"] = source_address["name"]
+ if "routing-instance" in source_address.keys():
+ source_address_dict["routing_instance"] = source_address["routing-instance"]
+ source_address_lst.append(source_address_dict)
+ source_address_dict = {}
+ if source_address_lst:
+ ntp_global_config["source_addresses"] = source_address_lst
+
+ # Read threshold node
+ if "threshold" in conf.keys():
+ threshold = conf.get("threshold")
+ threshold_dict = {}
+ if "value" in threshold.keys():
+ threshold_dict["value"] = threshold.get("value")
+ if "action" in threshold.keys():
+ threshold_dict["action"] = threshold.get("action")
+ if threshold_dict:
+ ntp_global_config["threshold"] = threshold_dict
+
+ # read trusted-keys node
+ if "trusted-key" in conf.keys():
+ trusted_keys = conf.get("trusted-key")
+ trusted_keys_lst = []
+ trusted_keys_dict = {}
+ if isinstance(trusted_keys, list):
+ trusted_keys.sort(key=int)
+ for key in trusted_keys:
+ trusted_keys_dict["key_id"] = key
+ trusted_keys_lst.append(trusted_keys_dict)
+ trusted_keys_dict = {}
+ ntp_global_config["trusted_keys"] = trusted_keys_lst
+ else:
+ trusted_keys_dict["key_id"] = trusted_keys
+ trusted_keys_lst.append(trusted_keys_dict)
+ ntp_global_config["trusted_keys"] = trusted_keys_lst
+ return utils.remove_empties(ntp_global_config)
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospf_interfaces/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospf_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospf_interfaces/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospf_interfaces/ospf_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospf_interfaces/ospf_interfaces.py
new file mode 100644
index 000000000..15319fa32
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospf_interfaces/ospf_interfaces.py
@@ -0,0 +1,267 @@
+#
+# -*- 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 ospf_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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ generate_dict,
+ remove_empties,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.ospf_interfaces.ospf_interfaces import (
+ Ospf_interfacesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.utils.utils import (
+ _validate_config,
+)
+
+
+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 Ospf_interfacesFacts(object):
+ """The junos ospf_interfaces fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Ospf_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 = generate_dict(facts_argument_spec)
+ self.router_id = ""
+
+ def get_connection(self, connection, config_filter):
+ """
+
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filter)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for ospf_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>
+ <protocols>
+ <ospf/>
+ </protocols>
+ <routing-options>
+ <router-id/>
+ </routing-options>
+ </configuration>
+ """
+ data = self.get_connection(connection, config_filter)
+
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+
+ resources = data.xpath("configuration/protocols/ospf")
+ router_id_path = data.xpath("configuration/routing-options/router-id")
+
+ if router_id_path:
+ self.router_id = self._get_xml_dict(router_id_path.pop())
+ else:
+ self.router_id = ""
+
+ objs = []
+ for resource in resources:
+ if resource:
+ xml = self._get_xml_dict(resource)
+ objs = self.render_config(self.generated_spec, xml)
+
+ facts = {}
+ if objs:
+ facts["junos_ospf_interfaces"] = []
+ params = _validate_config(
+ self._module,
+ self.argument_spec,
+ {"config": objs},
+ redact=True,
+ )
+
+ for cfg in params["config"]:
+ facts["junos_ospf_interfaces"].append(remove_empties(cfg))
+
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_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
+ """
+ ospf_interfaces_config = []
+ ospf = conf.get("ospf")
+
+ if ospf.get("area"):
+ areas = ospf.get("area")
+
+ if not isinstance(areas, list):
+ areas = [areas]
+
+ for area in areas:
+ rendered_area = {}
+ rendered_area["area_id"] = area.get("name")
+ rendered_area["interfaces"] = []
+
+ interfaces = area["interface"]
+ if not isinstance(interfaces, list):
+ interfaces = [interfaces]
+ for interface in interfaces:
+ interface_dict = {}
+ interface_dict["priority"] = interface.get("priority")
+ interface_dict["metric"] = interface.get("metric")
+ interface_dict["mtu"] = interface.get("mtu")
+ interface_dict["te_metric"] = interface.get("te-metric")
+ interface_dict["ipsec_sa"] = interface.get("ipsec-sa")
+ interface_dict["hello_interval"] = interface.get(
+ "hello-interval",
+ )
+ interface_dict["dead_interval"] = interface.get(
+ "dead-interval",
+ )
+ interface_dict["retransmit_interval"] = interface.get(
+ "retransmit-interval",
+ )
+ interface_dict["transit_delay"] = interface.get(
+ "transit-delay",
+ )
+ interface_dict["poll_interval"] = interface.get(
+ "poll-interval",
+ )
+ if "passive" in interface.keys():
+ interface_dict["passive"] = True
+ if "flood-reduction" in interface.keys():
+ interface_dict["flood_reduction"] = True
+ if "demand-circuit" in interface.keys():
+ interface_dict["demand_circuit"] = True
+ if "no-advertise-adjacency-segment" in interface.keys():
+ interface_dict["no_advertise_adjacency_segment"] = True
+ if "no-eligible-backup" in interface.keys():
+ interface_dict["no_eligible_backup"] = True
+ if "no-eligible-remote-backup" in interface.keys():
+ interface_dict["no_eligible_remote_backup"] = True
+ if "no-interface-state-traps" in interface.keys():
+ interface_dict["no_interface_state_traps"] = True
+ if "no-neighbor-down-notification" in interface.keys():
+ interface_dict["no_neighbor_down_notification"] = True
+ if "node-link-protection" in interface.keys():
+ interface_dict["node_link_protection"] = True
+ if "bandwidth-based-metrics" in interface.keys():
+ bandwidth_metrics = interface["bandwidth-based-metrics"].get("bandwidth")
+ if not isinstance(bandwidth_metrics, list):
+ bandwidth_metrics = [bandwidth_metrics]
+ interface_dict["bandwidth_based_metrics"] = []
+
+ for metric in bandwidth_metrics:
+ interface_dict["bandwidth_based_metrics"].append(
+ {
+ "metric": metric.get("metric"),
+ "bandwidth": metric.get("name"),
+ },
+ )
+
+ if "authentication" in interface.keys():
+ auth = interface["authentication"]
+ auth_dict = {}
+ if auth.get("simple-password"):
+ auth_dict["simple_password"] = auth.get(
+ "simple-password",
+ )
+ elif auth.get("md5"):
+ auth_dict["type"] = {"md5": []}
+ md5_list = auth.get("md5")
+
+ if not isinstance(md5_list, list):
+ md5_list = [md5_list]
+
+ for md5_auth in md5_list:
+ auth_dict["type"]["md5"].append(
+ {
+ "key_id": md5_auth.get("name"),
+ "key": md5_auth.get("key"),
+ },
+ )
+ interface_dict["authentication"] = auth_dict
+
+ rendered_area["interfaces"].append(interface_dict)
+
+ af = {}
+ conf = {}
+ areas = {}
+ address_family = []
+ af["afi"] = "ipv4"
+ areas["area_id"] = rendered_area["area_id"]
+ interface_dict["area"] = areas
+ af["processes"] = interface_dict
+ address_family.append(af)
+ conf["address_family"] = address_family
+ conf["name"] = interface.get("name")
+ if self.router_id:
+ conf["router_id"] = self.router_id["router-id"]
+ remove_empties(conf)
+ ospf_interfaces_config.append(conf)
+
+ return ospf_interfaces_config
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv2/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv2/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv2/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv2/ospfv2.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv2/ospfv2.py
new file mode 100644
index 000000000..24c8fa86d
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv2/ospfv2.py
@@ -0,0 +1,286 @@
+# Copyright (C) 2020 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_ospfv2 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.ospfv2.ospfv2 import (
+ Ospfv2Args,
+)
+
+
+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 Ospfv2Facts(object):
+ """The junos ospf fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Ospfv2Args.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)
+ self.router_id = ""
+
+ def get_connection(self, connection, config_filter):
+ """
+
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filter)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for ospf
+ :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>
+ <protocols>
+ <ospf/>
+ </protocols>
+ <routing-options>
+ <router-id/>
+ </routing-options>
+ </configuration>
+ """
+ data = self.get_connection(connection, config_filter)
+
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+
+ resources = data.xpath("configuration/protocols/ospf")
+ router_id_path = data.xpath("configuration/routing-options/router-id")
+ if router_id_path:
+ self.router_id = self._get_xml_dict(router_id_path.pop())
+ else:
+ self.router_id = ""
+ objs = []
+ for resource in resources:
+ if resource:
+ xml = self._get_xml_dict(resource)
+ obj = self.render_config(self.generated_spec, xml)
+ if obj:
+ objs.append(obj)
+
+ facts = {}
+ if objs:
+ facts["ospfv2"] = []
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ )
+
+ for cfg in params["config"]:
+ facts["ospfv2"].append(utils.remove_empties(cfg))
+
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_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)
+ ospf = conf.get("ospf")
+
+ if ospf.get("area"):
+ rendered_areas = []
+ areas = ospf.get("area")
+
+ if not isinstance(areas, list):
+ areas = [areas]
+
+ for area in areas:
+ rendered_area = {}
+ rendered_area["area_id"] = area.get("name")
+ rendered_area["interfaces"] = []
+
+ interfaces = area["interface"]
+ if not isinstance(interfaces, list):
+ interfaces = [interfaces]
+
+ for interface in interfaces:
+ interface_dict = {}
+ interface_dict["name"] = interface.get("name")
+ interface_dict["priority"] = interface.get("priority")
+ interface_dict["metric"] = interface.get("metric")
+ interface_dict["timers"] = {}
+ interface_dict["timers"]["hello_interval"] = interface.get(
+ "hello-interval",
+ )
+ interface_dict["timers"]["dead_interval"] = interface.get(
+ "dead-interval",
+ )
+ interface_dict["timers"]["retransmit_interval"] = interface.get(
+ "retransmit-interval",
+ )
+ interface_dict["timers"]["transit_delay"] = interface.get(
+ "transit-delay",
+ )
+ interface_dict["timers"]["poll_interval"] = interface.get(
+ "poll-interval",
+ )
+ if "passive" in interface.keys():
+ interface_dict["passive"] = True
+ if "flood-reduction" in interface.keys():
+ interface_dict["flood_reduction"] = True
+ if "bandwidth-based-metrics" in interface.keys():
+ bandwidth_metrics = interface["bandwidth-based-metrics"].get("bandwidth")
+ if not isinstance(bandwidth_metrics, list):
+ bandwidth_metrics = [bandwidth_metrics]
+ interface_dict["bandwidth_based_metrics"] = []
+
+ for metric in bandwidth_metrics:
+ interface_dict["bandwidth_based_metrics"].append(
+ {
+ "metric": metric.get("metric"),
+ "bandwidth": metric.get("name"),
+ },
+ )
+
+ if "authentication" in interface.keys():
+ auth = interface["authentication"]
+ auth_dict = {}
+ if auth.get("simple-password"):
+ auth_dict["type"] = "simple_password"
+ auth_dict["password"] = auth.get("simple-password")
+ elif auth.get("md5"):
+ auth_dict["type"] = {"md5": []}
+ md5_list = auth.get("md5")
+
+ if not isinstance(md5_list, list):
+ md5_list = [md5_list]
+
+ for md5_auth in md5_list:
+ auth_dict["type"]["md5"].append(
+ {
+ "key_id": md5_auth.get("name"),
+ "key": md5_auth.get("key"),
+ },
+ )
+ interface_dict["authentication"] = auth_dict
+
+ rendered_area["interfaces"].append(interface_dict)
+
+ if area.get("area-range"):
+ area_range = area["area-range"]
+ if not isinstance(area_range, list):
+ area_range = [area_range]
+ rendered_area["area_range"] = []
+ for a_range in area_range:
+ rendered_area["area_range"].append(a_range["name"])
+
+ if area.get("stub"):
+ rendered_area["stub"] = {"set": True}
+ if "no-summaries" in area.get("stub").keys():
+ rendered_area["stub"]["no_summary"] = True
+ if "default-metric" in area.get("stub").keys():
+ rendered_area["stub"]["default_metric"] = area["stub"].get("default-metric")
+ if area.get("nssa"):
+ rendered_area["nssa"] = {"set": True}
+ if "no-summaries" in area.get("nssa").keys():
+ rendered_area["nssa"]["no_summary"] = True
+ elif "summaries" in area.get("nssa").keys():
+ rendered_area["nssa"]["no_summary"] = False
+ if "default-lsa" in area.get("nssa").keys():
+ rendered_area["nssa"]["default-lsa"] = True
+ rendered_areas.append(rendered_area)
+
+ if "no-rfc-1583" in ospf.keys():
+ config["rfc1583compatibility"] = False
+ if ospf.get("spf-options"):
+ config["spf_options"] = {}
+ config["spf_options"]["delay"] = ospf["spf-options"].get(
+ "delay",
+ )
+ config["spf_options"]["holddown"] = ospf["spf-options"].get(
+ "holddown",
+ )
+ config["spf_options"]["rapid_runs"] = ospf["spf-options"].get(
+ "rapid-runs",
+ )
+ config["overload"] = ospf.get("overload")
+ config["preference"] = ospf.get("preference")
+ config["external_preference"] = ospf.get("external-preference")
+ config["prefix_export_limit"] = ospf.get("prefix-export-limit")
+ config["reference_bandwidth"] = ospf.get("reference-bandwidth")
+ config["areas"] = rendered_areas
+ if self.router_id != "":
+ config["router_id"] = self.router_id["router-id"]
+ return utils.remove_empties(config)
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv3/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv3/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv3/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv3/ospfv3.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv3/ospfv3.py
new file mode 100644
index 000000000..2f95e0e8d
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/ospfv3/ospfv3.py
@@ -0,0 +1,285 @@
+# Copyright (C) 2020 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_ospfv3 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.ospfv3.ospfv3 import (
+ Ospfv3Args,
+)
+
+
+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 Ospfv3Facts(object):
+ """The junos ospfv3 fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Ospfv3Args.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)
+ self.router_id = ""
+
+ def get_connection(self, connection, config_filter):
+ """
+
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filter)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for ospfv3
+ :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>
+ <protocols>
+ <ospf3/>
+ </protocols>
+ <routing-options>
+ <router-id/>
+ </routing-options>
+ </configuration>
+ """
+ data = self.get_connection(connection, config_filter)
+
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+
+ resources = data.xpath("configuration/protocols/ospf3")
+ router_id_path = data.xpath("configuration/routing-options/router-id")
+ if router_id_path:
+ self.router_id = self._get_xml_dict(router_id_path.pop())
+ else:
+ self.router_id = ""
+
+ objs = []
+ for resource in resources:
+ if resource:
+ xml = self._get_xml_dict(resource)
+ obj = self.render_config(self.generated_spec, xml)
+ if obj:
+ objs.append(obj)
+
+ facts = {}
+ if objs:
+ facts["junos_ospfv3"] = []
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ )
+
+ for cfg in params["config"]:
+ facts["junos_ospfv3"].append(utils.remove_empties(cfg))
+
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_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)
+ ospfv3 = conf.get("ospf3")
+
+ if ospfv3.get("area"):
+ rendered_areas = []
+ areas = ospfv3.get("area")
+
+ if not isinstance(areas, list):
+ areas = [areas]
+
+ for area in areas:
+ rendered_area = {}
+ rendered_area["area_id"] = area.get("name")
+ rendered_area["interfaces"] = []
+
+ interfaces = area["interface"]
+ if not isinstance(interfaces, list):
+ interfaces = [interfaces]
+
+ for interface in interfaces:
+ interface_dict = {}
+ interface_dict["name"] = interface.get("name")
+ interface_dict["priority"] = interface.get("priority")
+ interface_dict["metric"] = interface.get("metric")
+ interface_dict["timers"] = {}
+ interface_dict["timers"]["hello_interval"] = interface.get(
+ "hello-interval",
+ )
+ interface_dict["timers"]["dead_interval"] = interface.get(
+ "dead-interval",
+ )
+ interface_dict["timers"]["retransmit_interval"] = interface.get(
+ "retransmit-interval",
+ )
+ interface_dict["timers"]["transit_delay"] = interface.get(
+ "transit-delay",
+ )
+ interface_dict["timers"]["poll_interval"] = interface.get(
+ "poll-interval",
+ )
+ if "passive" in interface.keys():
+ interface_dict["passive"] = True
+ if "flood-reduction" in interface.keys():
+ interface_dict["flood_reduction"] = True
+ if "bandwidth-based-metrics" in interface.keys():
+ bandwidth_metrics = interface["bandwidth-based-metrics"].get("bandwidth")
+ if not isinstance(bandwidth_metrics, list):
+ bandwidth_metrics = [bandwidth_metrics]
+ interface_dict["bandwidth_based_metrics"] = []
+
+ for metric in bandwidth_metrics:
+ interface_dict["bandwidth_based_metrics"].append(
+ {
+ "metric": metric.get("metric"),
+ "bandwidth": metric.get("name"),
+ },
+ )
+
+ if "authentication" in interface.keys():
+ auth = interface["authentication"]
+ auth_dict = {}
+ if auth.get("simple-password"):
+ auth_dict["type"] = "simple_password"
+ auth_dict["password"] = auth.get("simple-password")
+ elif auth.get("md5"):
+ auth_dict["type"] = {"md5": []}
+ md5_list = auth.get("md5")
+
+ if not isinstance(md5_list, list):
+ md5_list = [md5_list]
+
+ for md5_auth in md5_list:
+ auth_dict["type"]["md5"].append(
+ {
+ "key_id": md5_auth.get("name"),
+ "key": md5_auth.get("key"),
+ },
+ )
+ interface_dict["authentication"] = auth_dict
+
+ rendered_area["interfaces"].append(interface_dict)
+
+ if area.get("area-range"):
+ area_range = area["area-range"]
+ if not isinstance(area_range, list):
+ area_range = [area_range]
+ rendered_area["area_range"] = []
+ for a_range in area_range:
+ rendered_area["area_range"].append(a_range["name"])
+
+ if area.get("stub"):
+ rendered_area["stub"] = {"set": True}
+ if "no-summaries" in area.get("stub").keys():
+ rendered_area["stub"]["no_summary"] = True
+ if "default-metric" in area.get("stub").keys():
+ rendered_area["stub"]["default_metric"] = area["stub"].get("default-metric")
+ if area.get("nssa"):
+ rendered_area["nssa"] = {"set": True}
+ if "no-summaries" in area.get("nssa").keys():
+ rendered_area["nssa"]["no_summary"] = True
+ elif "summaries" in area.get("nssa").keys():
+ rendered_area["nssa"]["no_summary"] = False
+ if "default-lsa" in area.get("nssa").keys():
+ rendered_area["nssa"]["default-lsa"] = True
+ rendered_areas.append(rendered_area)
+
+ if "no-rfc-1583" in ospfv3.keys():
+ config["rfc1583compatibility"] = False
+ if ospfv3.get("spf-options"):
+ config["spf_options"] = {}
+ config["spf_options"]["delay"] = ospfv3["spf-options"].get(
+ "delay",
+ )
+ config["spf_options"]["holddown"] = ospfv3["spf-options"].get(
+ "holddown",
+ )
+ config["spf_options"]["rapid_runs"] = ospfv3["spf-options"].get("rapid-runs")
+ config["overload"] = ospfv3.get("overload")
+ config["preference"] = ospfv3.get("preference")
+ config["external_preference"] = ospfv3.get("external-preference")
+ config["prefix_export_limit"] = ospfv3.get("prefix-export-limit")
+ config["reference_bandwidth"] = ospfv3.get("reference-bandwidth")
+ config["areas"] = rendered_areas
+ if self.router_id:
+ config["router_id"] = self.router_id["router-id"]
+ return utils.remove_empties(config)
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/prefix_lists/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/prefix_lists/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/prefix_lists/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/prefix_lists/prefix_lists.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/prefix_lists/prefix_lists.py
new file mode 100644
index 000000000..4d3ec81c0
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/prefix_lists/prefix_lists.py
@@ -0,0 +1,168 @@
+#
+# -*- 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 prefix_lists 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.prefix_lists.prefix_lists import (
+ Prefix_listsArgs,
+)
+
+
+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 Prefix_listsFacts(object):
+ """The junos prefix_lists fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Prefix_listsArgs.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 get_device_data(self, connection, config_filter):
+ """
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filter)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for bgp_address_family
+ :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>
+ <policy-options>
+ <prefix-list>
+ </prefix-list>
+ </policy-options>
+ </configuration>
+ """
+ data = self.get_device_data(connection, config_filter)
+
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+ objs = {}
+ resources = data.xpath("configuration/policy-options")
+
+ for resource in resources:
+ if resource is not None:
+ xml = self._get_xml_dict(resource)
+ objs = self.render_config(self.generated_spec, xml)
+
+ facts = {}
+ if objs:
+ facts["prefix_lists"] = []
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ )
+
+ for cfg in params["config"]:
+ facts["prefix_lists"].append(utils.remove_empties(cfg))
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_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
+ """
+ prefix_lists_config = []
+ pl_dict = {}
+ pl_cfg = []
+ # Parse facts for routing instances node
+ prefix_lists = conf["policy-options"].get("prefix-list")
+ if isinstance(prefix_lists, dict):
+ pl_cfg.append(prefix_lists)
+ else:
+ pl_cfg = prefix_lists
+ for cfg in pl_cfg:
+ # Parse attribute name
+ if cfg.get("name"):
+ pl_dict["name"] = cfg.get("name")
+
+ # Parse attribute dynamic-db
+ if "dynamic-db" in cfg.keys():
+ pl_dict["dynamic_db"] = True
+
+ # Parse attribute address-prefix
+ if cfg.get("prefix-list-item"):
+ addr_prefix = cfg.get("prefix-list-item")
+ addr_pre_list = []
+ if isinstance(addr_prefix, dict):
+ addr_pre_list.append(addr_prefix["name"])
+ else:
+ for prefix in addr_prefix:
+ addr_pre_list.append(prefix["name"])
+ pl_dict["address_prefixes"] = addr_pre_list
+
+ if pl_dict:
+ prefix_lists_config.append(pl_dict)
+ pl_dict = {}
+
+ return prefix_lists_config
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_instances/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_instances/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_instances/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_instances/routing_instances.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_instances/routing_instances.py
new file mode 100644
index 000000000..d571e4e53
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_instances/routing_instances.py
@@ -0,0 +1,248 @@
+#
+# -*- 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 routing_instances 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.routing_instances.routing_instances import (
+ Routing_instancesArgs,
+)
+
+
+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 Routing_instancesFacts(object):
+ """The junos routing_instances fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Routing_instancesArgs.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 get_device_data(self, connection, config_filter):
+ """
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filter)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for bgp_address_family
+ :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/>
+ </configuration>
+ """
+ data = self.get_device_data(connection, config_filter)
+
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+ objs = {}
+ resources = data.xpath("configuration/routing-instances")
+ for resource in resources:
+ if resource is not None:
+ xml = self._get_xml_dict(resource)
+ objs = self.render_config(self.generated_spec, xml)
+
+ facts = {}
+ if objs:
+ facts["routing_instances"] = []
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ )
+
+ for cfg in params["config"]:
+ facts["routing_instances"].append(utils.remove_empties(cfg))
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_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
+ """
+ routing_instances_config = []
+
+ # Parse facts for routing instances node
+ conf = conf.get("routing-instances")
+
+ # Parse routing instances
+ routing_instances = conf.get("instance")
+ if isinstance(routing_instances, list):
+ for instance in routing_instances:
+ instance_dict = self.parse_instance(instance)
+ routing_instances_config.append(instance_dict)
+ else:
+ instance_dict = self.parse_instance(routing_instances)
+ routing_instances_config.append(instance_dict)
+
+ return routing_instances_config
+
+ def parse_instance(self, instance):
+ """
+
+ :param instance:
+ :return:
+ """
+ instance_dict = {}
+ # read instance name
+ instance_dict["name"] = instance["name"]
+
+ # read connection-id-advertise
+ if "connector-id-advertise" in instance.keys():
+ instance_dict["connector_id_advertise"] = True
+
+ # read description
+ if instance.get("description"):
+ instance_dict["description"] = instance["description"]
+
+ # read instance role
+ if instance.get("instance-role"):
+ instance_dict["instance_role"] = instance["instance-role"]
+
+ # read instance type
+ if instance.get("instance-type"):
+ instance_dict["type"] = instance["instance-type"]
+
+ # read interfaces
+ if instance.get("interface"):
+ interfaces = instance.get("interface")
+ interfaces_list = []
+ if isinstance(interfaces, list):
+ for interface in interfaces:
+ interfaces_list.append(self.parse_interface(interface))
+ else:
+ interfaces_list.append(self.parse_interface(interfaces))
+ instance_dict["interfaces"] = interfaces_list
+
+ # read l2vpn-id
+ if instance.get("l2vpn-id"):
+ instance_dict["l2vpn_id"] = instance["l2vpn-id"].get("community")
+
+ # read no-irb-layer2-copy
+ if "no-irb-layer2-copy" in instance.keys():
+ instance_dict["no_irb_layer_2_copy"] = True
+
+ # read no_local_switching
+ if "no-local-switching" in instance.keys():
+ instance_dict["no_local_switching"] = True
+
+ # read no-vrf-advertise
+ if "no-vrf-advertise" in instance.keys():
+ instance_dict["no_vrf_advertise"] = True
+
+ # read no_vrf_propagate_ttl
+ if "no-vrf-propagate-ttl" in instance.keys():
+ instance_dict["no_vrf_propagate_ttl"] = True
+
+ # read qualified_bum_pruning_mode
+ if instance.get("qualified-bum-pruning-mode"):
+ instance_dict["qualified_bum_pruning_mode"] = True
+
+ # read route-distinguisher
+ if instance.get("route-distinguisher"):
+ instance_dict["route_distinguisher"] = instance["route-distinguisher"].get("rd-type")
+
+ # read vrf imports
+ if instance.get("vrf-import"):
+ vrf_imp_lst = []
+ vrf_imp = instance.get("vrf-import")
+
+ if isinstance(vrf_imp, list):
+ vrf_imp_lst = vrf_imp
+ else:
+ vrf_imp_lst.append(vrf_imp)
+ instance_dict["vrf_imports"] = vrf_imp_lst
+
+ # read vrf exports
+ if instance.get("vrf-export"):
+ vrf_exp_lst = []
+ vrf_exp = instance.get("vrf-export")
+ if isinstance(vrf_exp, list):
+ vrf_exp_lst = vrf_exp
+ else:
+ vrf_exp_lst.append(vrf_exp)
+ instance_dict["vrf_exports"] = vrf_exp_lst
+
+ return utils.remove_empties(instance_dict)
+
+ def parse_interface(self, interface):
+ """
+
+ :param instance:
+ :return:
+ """
+ cfg_dict = {}
+ cfg_dict["name"] = interface["name"]
+ if interface.get("protect-interface"):
+ cfg_dict["protect_interface"] = interface.get("protect-interface")
+
+ return cfg_dict
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_options/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_options/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_options/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_options/routing_options.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_options/routing_options.py
new file mode 100644
index 000000000..78664fea8
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/routing_options/routing_options.py
@@ -0,0 +1,150 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos routing_options 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.routing_options.routing_options import (
+ Routing_optionsArgs,
+)
+
+
+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 Routing_optionsFacts(object):
+ """The junos routing_options fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Routing_optionsArgs.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 get_device_data(self, connection, config_filter):
+ """
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filter)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for routing_options
+ :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>
+ <routing-options>
+ </routing-options>
+ </configuration>
+ """
+ data = self.get_device_data(connection, config_filter)
+
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+ objs = {}
+ resources = data.xpath("configuration/routing-options")
+ for resource in resources:
+ if resource is not None:
+ xml = self._get_xml_dict(resource)
+ objs = self.render_config(self.generated_spec, xml)
+
+ facts = {}
+ if objs:
+ facts["routing_options"] = {}
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ )
+
+ facts["routing_options"] = utils.remove_empties(params["config"])
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_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
+ """
+ routing_config = {}
+ conf = conf.get("routing-options")
+
+ # Read autonomous-system
+ if "autonomous-system" in conf.keys():
+ as_num = conf.get("autonomous-system")
+ as_dict = {}
+ if "as-number" in as_num.keys():
+ as_dict["as_number"] = as_num.get("as-number")
+ if as_num.get("loops"):
+ as_dict["loops"] = as_num.get("loops")
+ if "asdot-notation" in as_num.keys():
+ as_dict["asdot_notation"] = True
+ routing_config["autonomous_system"] = as_dict
+
+ # Read router-id
+ if "router-id" in conf.keys():
+ routing_config["router_id"] = conf.get("router-id")
+
+ return utils.remove_empties(routing_config)
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies/security_policies.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies/security_policies.py
new file mode 100644
index 000000000..dc6a20878
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies/security_policies.py
@@ -0,0 +1,529 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2022 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos security_policies 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.security_policies.security_policies import (
+ Security_policiesArgs,
+)
+
+
+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 Security_policiesFacts(object):
+ """The junos security_policies fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Security_policiesArgs.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 _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_dict
+
+ def _get_device_data(self, connection, config_filters):
+ """
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filters)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for security_polices
+ :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>
+ <security>
+ <policies>
+ </policies>
+ </security>
+ </configuration>
+ """
+ data = self._get_device_data(connection, config_filter)
+
+ # split the config into instances of the resource
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+ objs = {}
+ resources = data.xpath("configuration/security/policies")
+ for resource in resources:
+ if resource is not None:
+ xml = self._get_xml_dict(resource)
+ objs = self.render_config(self.generated_spec, xml)
+
+ facts = {}
+ if objs:
+ facts["security_policies"] = {}
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ )
+
+ facts["security_policies"] = utils.remove_empties(params["config"])
+
+ 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
+ """
+ security_policies_config = {}
+
+ # Parse facts for security policies
+ conf = conf.get("policies") or {}
+
+ if "policy" in conf:
+ security_policies_config["from_zones"] = []
+ from_zone_dict = {}
+ zone_pairs = conf.get("policy")
+ if isinstance(zone_pairs, dict):
+ temp = zone_pairs
+ zone_pairs = []
+ zone_pairs.append(temp)
+ for zone_pair_policies in zone_pairs:
+
+ if zone_pair_policies["from-zone-name"] not in from_zone_dict:
+ from_zone_dict[zone_pair_policies["from-zone-name"]] = {}
+ from_zone_dict[zone_pair_policies["from-zone-name"]][
+ "name"
+ ] = zone_pair_policies["from-zone-name"]
+ from_zone_dict[zone_pair_policies["from-zone-name"]]["to_zones"] = {}
+
+ from_zone = from_zone_dict[zone_pair_policies["from-zone-name"]]
+
+ from_zone["to_zones"][zone_pair_policies["to-zone-name"]] = {}
+ to_zone = from_zone["to_zones"][zone_pair_policies["to-zone-name"]]
+
+ to_zone["name"] = zone_pair_policies["to-zone-name"]
+ to_zone["policies"] = self.parse_policies(
+ zone_pair_policies["policy"],
+ )
+
+ for from_zone in from_zone_dict.values():
+ from_zone["to_zones"] = list(from_zone["to_zones"].values())
+ security_policies_config["from_zones"].append(from_zone)
+
+ if "global" in conf:
+ global_policies = conf.get("global")
+ global_policies = global_policies.get("policy")
+ security_policies_config["global"] = {}
+ security_policies_config["global"]["policies"] = self.parse_policies(global_policies)
+
+ return security_policies_config
+
+ def parse_policies(self, policies):
+ policy_list = []
+
+ if isinstance(policies, dict):
+ temp = policies
+ policies = []
+ policies.append(temp)
+
+ for policy in policies:
+ tmp_policy = {}
+
+ # parse name of policy
+ tmp_policy["name"] = policy["name"]
+
+ # parse match criteria of security policy
+ tmp_policy["match"] = {}
+
+ match = tmp_policy["match"]
+ policy_match = policy["match"]
+
+ match["source_address"] = {}
+ if isinstance(policy_match["source-address"], string_types):
+ policy_match["source-address"] = [
+ policy_match["source-address"],
+ ]
+ for source_address in policy_match["source-address"]:
+ if source_address == "any-ipv6":
+ match["source_address"]["any_ipv6"] = True
+ elif source_address == "any-ipv4":
+ match["source_address"]["any_ipv4"] = True
+ elif source_address == "any":
+ match["source_address"]["any"] = True
+ else:
+ if "addresses" not in match["source_address"]:
+ match["source_address"]["addresses"] = []
+ match["source_address"]["addresses"].append(source_address)
+
+ if "source-address-excluded" in policy_match:
+ match["source_address_excluded"] = True
+
+ match["destination_address"] = {}
+ if isinstance(policy_match["destination-address"], string_types):
+ policy_match["destination-address"] = [
+ policy_match["destination-address"],
+ ]
+ for destination_address in policy_match["destination-address"]:
+ if destination_address == "any-ipv6":
+ match["destination_address"]["any_ipv6"] = True
+ elif destination_address == "any-ipv4":
+ match["destination_address"]["any_ipv4"] = True
+ elif destination_address == "any":
+ match["destination_address"]["any"] = True
+ else:
+ if "addresses" not in match["destination_address"]:
+ match["destination_address"]["addresses"] = []
+ match["destination_address"]["addresses"].append(
+ destination_address,
+ )
+
+ if "destination-address-excluded" in policy_match:
+ match["destination_address_excluded"] = True
+
+ match["application"] = {}
+ if policy_match["application"] == "any":
+ match["application"]["any"] = True
+ else:
+ if isinstance(policy_match["application"], string_types):
+ policy_match["application"] = [policy_match["application"]]
+ match["application"]["names"] = policy_match["application"]
+
+ if "source-end-user-profile" in policy_match:
+ match["source_end_user_profile"] = policy_match["source-end-user-profile"][
+ "source-end-user-profile-name"
+ ]
+
+ if "source-identity" in policy_match:
+ if isinstance(policy_match["source-identity"], string_types):
+ policy_match["source-identity"] = [
+ policy_match["source-identity"],
+ ]
+ match["source_identity"] = {}
+ for source_identity in policy_match["source-identity"]:
+ if source_identity == "any":
+ match["source_identity"]["any"] = True
+ elif "authenticated-user" == source_identity:
+ match["source_identity"]["authenticated_user"] = True
+ elif "unauthenticated-user" == source_identity:
+ match["source_identity"]["unauthenticated_user"] = True
+ elif "unknown-user" == source_identity:
+ match["source_identity"]["unknown_user"] = True
+ else:
+ if "names" not in match["source_identity"]:
+ match["source_identity"]["names"] = []
+ match["source_identity"]["names"].append(
+ source_identity,
+ )
+
+ if "url-category" in policy_match:
+ if isinstance(policy_match["url-category"], string_types):
+ policy_match["url-category"] = [
+ policy_match["url-category"],
+ ]
+ match["url_category"] = {}
+ for url_category in policy_match["url-category"]:
+ if url_category == "any":
+ match["url_category"]["any"] = True
+ elif url_category == "none":
+ match["url_category"]["none"] = True
+ else:
+ if "names" not in match["url_category"]:
+ match["url_category"]["names"] = []
+ match["url_category"]["names"].append(url_category)
+
+ if "dynamic-application" in policy_match:
+ if isinstance(
+ policy_match["dynamic-application"],
+ string_types,
+ ):
+ policy_match["dynamic-application"] = [
+ policy_match["dynamic-application"],
+ ]
+ match["dynamic_application"] = {}
+ for dynamic_application in policy_match["dynamic-application"]:
+ if dynamic_application == "any":
+ match["dynamic_application"]["any"] = True
+ elif dynamic_application == "none":
+ match["dynamic_application"]["none"] = True
+ else:
+ if "names" not in match["dynamic_application"]:
+ match["dynamic_application"]["names"] = []
+ match["dynamic_application"]["names"].append(
+ dynamic_application,
+ )
+ # end of match criteria parsing
+
+ # parse match action of security policy
+ tmp_policy["then"] = {}
+ action = tmp_policy["then"]
+ policy_action = policy["then"]
+
+ if "count" in policy_action:
+ action["count"] = True
+
+ if "log" in policy_action:
+ action["log"] = {}
+ if "session-close" in policy_action["log"]:
+ action["log"]["session_close"] = True
+ if "session-init" in policy_action["log"]:
+ action["log"]["session_init"] = True
+
+ if "deny" in policy_action:
+ action["deny"] = True
+
+ if "reject" in policy_action:
+ action["reject"] = {}
+ reject = action["reject"]
+ policy_reject = policy_action["reject"] or {}
+ reject["enable"] = True
+
+ if "profile" in policy_reject:
+ reject["profile"] = policy_reject["profile"]
+ if "ssl-proxy" in policy_reject:
+ policy_reject["ssl-proxy"] = policy_reject["ssl-proxy"] or {}
+ reject["ssl_proxy"] = {}
+ reject["ssl_proxy"]["enable"] = True
+ if "profile-name" in policy_reject["ssl-proxy"]:
+ reject["ssl_proxy"]["profile_name"] = policy_reject["ssl-proxy"][
+ "profile-name"
+ ]
+
+ if "permit" in policy_action:
+ action["permit"] = {}
+ permit = action["permit"]
+ policy_permit = policy_action["permit"] or {}
+
+ if "application-services" in policy_permit:
+ permit["application_services"] = {}
+ application_services = permit["application_services"]
+ policy_application_services = policy_permit["application-services"] or {}
+
+ if "advanced-anti-malware-policy" in policy_application_services:
+ application_services[
+ "advanced_anti_malware_policy"
+ ] = policy_application_services["advanced-anti-malware-policy"]
+ if "application-traffic-control" in policy_application_services:
+ application_services[
+ "application_traffic_control_rule_set"
+ ] = policy_application_services["application-traffic-control"]["rule-set"]
+ if "gprs-gtp-profile" in policy_application_services:
+ application_services["gprs_gtp_profile"] = policy_application_services[
+ "gprs-gtp-profile"
+ ]
+ if "gprs-sctp-profile" in policy_application_services:
+ application_services["gprs_sctp_profile"] = policy_application_services[
+ "gprs-sctp-profile"
+ ]
+ if "icap-redirect" in policy_application_services:
+ application_services["icap_redirect"] = policy_application_services[
+ "icap-redirect"
+ ]
+ if "idp" in policy_application_services:
+ application_services["idp"] = True
+ if "idp-policy" in policy_application_services:
+ application_services["idp_policy"] = policy_application_services[
+ "idp-policy"
+ ]
+ if "redirect-wx" in policy_application_services:
+ application_services["redirect_wx"] = True
+ if "reverse-redirect-wx" in policy_application_services:
+ application_services["reverse_redirect_wx"] = True
+ if "security-intelligence-policy" in policy_application_services:
+ application_services[
+ "security_intelligence_policy"
+ ] = policy_application_services["security-intelligence-policy"]
+ if "ssl-proxy" in policy_application_services:
+ application_services["ssl_proxy"] = {}
+ application_services["ssl_proxy"]["enable"] = True
+ if (
+ policy_application_services["ssl-proxy"]
+ and "profile-name" in policy_application_services["ssl-proxy"]
+ ):
+ application_services["ssl_proxy"][
+ "profile_name"
+ ] = policy_application_services["ssl-proxy"]["profile-name"]
+ if "uac-policy" in policy_application_services:
+ application_services["uac_policy"] = {}
+ application_services["uac_policy"]["enable"] = True
+ if (
+ policy_application_services["uac-policy"]
+ and "captive-portal" in policy_application_services["uac-policy"]
+ ):
+ application_services["uac_policy"][
+ "captive_portal"
+ ] = policy_application_services["uac-policy"]["captive-portal"]
+ if "utm-policy" in policy_application_services:
+ application_services["utm_policy"] = policy_application_services[
+ "utm-policy"
+ ]
+
+ if "destination-address" in policy_permit:
+ permit["destination_address"] = policy_permit["destination-address"]
+
+ if "firewall-authentication" in policy_permit:
+ permit["firewall_authentication"] = {}
+ f_a = permit["firewall_authentication"]
+ policy_f_a = policy_permit["firewall-authentication"] or {}
+
+ if "pass-through" in policy_f_a:
+ f_a["pass_through"] = {}
+ if "access-profile" in policy_f_a["pass-through"]:
+ f_a["pass_through"]["access_profile"] = policy_f_a["pass-through"][
+ "access-profile"
+ ]
+ if "auth-only-browser" in policy_f_a["pass-through"]:
+ f_a["pass_through"]["auth_only_browser"] = True
+ if "auth-user-agent" in policy_f_a["pass-through"]:
+ f_a["pass_through"]["auth_user_agent"] = policy_f_a["pass-through"][
+ "auth-user-agent"
+ ]
+ if "client-match" in policy_f_a["pass-through"]:
+ f_a["pass_through"]["client_match"] = policy_f_a["pass-through"][
+ "client-match"
+ ]
+ if "ssl-termination-profile" in policy_f_a["pass-through"]:
+ f_a["pass_through"]["ssl_termination_profile"] = policy_f_a[
+ "pass-through"
+ ]["ssl-termination-profile"]
+ if "web-redirect" in policy_f_a["pass-through"]:
+ f_a["pass_through"]["web_redirect"] = True
+ if "web-redirect-to-https" in policy_f_a["pass-through"]:
+ f_a["pass_through"]["web_redirect_to_https"] = True
+
+ if "push-to-identity-management" in policy_f_a:
+ f_a["push_to_identity_management"] = True
+
+ if "user-firewall" in policy_f_a:
+ f_a["user_firewall"] = {}
+ if "access-profile" in policy_f_a["user-firewall"]:
+ f_a["user_firewall"]["access_profile"] = policy_f_a["user-firewall"][
+ "access-profile"
+ ]
+ if "auth-only-browser" in policy_f_a["user-firewall"]:
+ f_a["user_firewall"]["auth_only_browser"] = True
+ if "auth-user-agent" in policy_f_a["user-firewall"]:
+ f_a["user_firewall"]["auth_user_agent"] = policy_f_a["user-firewall"][
+ "auth-user-agent"
+ ]
+ if "domain" in policy_f_a["user-firewall"]:
+ f_a["user_firewall"]["domain"] = policy_f_a["user-firewall"]["domain"]
+ if "ssl-termination-profile" in policy_f_a["user-firewall"]:
+ f_a["user_firewall"]["ssl_termination_profile"] = policy_f_a[
+ "user-firewall"
+ ]["ssl-termination-profile"]
+ if "web-redirect" in policy_f_a["user-firewall"]:
+ f_a["user_firewall"]["web_redirect"] = True
+ if "web-redirect-to-https" in policy_f_a["user-firewall"]:
+ f_a["user_firewall"]["web_redirect_to_https"] = True
+
+ if "web-authentication" in policy_f_a:
+ f_a["web_authentication"] = []
+ if isinstance(
+ policy_f_a["web-authentication"]["client-match"],
+ str,
+ ):
+ temp = policy_f_a["web-authentication"]["client-match"]
+ policy_f_a["web-authentication"]["client-match"] = []
+ policy_f_a["web-authentication"]["client-match"].append(temp)
+ f_a["web_authentication"] = policy_f_a["web-authentication"]["client-match"]
+
+ if "tcp-options" in policy_permit:
+ permit["tcp_options"] = {}
+ tcp_options = permit["tcp_options"]
+ policy_tcp_options = policy_permit["tcp-options"] or {}
+
+ if "initial-tcp-mss" in policy_tcp_options:
+ tcp_options["initial_tcp_mss"] = policy_permit["tcp-options"][
+ "initial-tcp-mss"
+ ]
+ if "reverse-tcp-mss" in policy_tcp_options:
+ tcp_options["reverse_tcp_mss"] = policy_permit["tcp-options"][
+ "reverse-tcp-mss"
+ ]
+ if "sequence-check-required" in policy_tcp_options:
+ tcp_options["sequence_check_required"] = True
+ if "syn-check-required" in policy_tcp_options:
+ tcp_options["syn_check_required"] = True
+ if "window-scale" in policy_tcp_options:
+ tcp_options["window_scale"] = True
+
+ if "tunnel" in policy_permit:
+ permit["tunnel"] = {}
+ policy_permit["tunnel"] = policy_permit["tunnel"] or {}
+ if "ipsec-vpn" in policy_permit["tunnel"]:
+ permit["tunnel"]["ipsec_vpn"] = policy_permit["tunnel"]["ipsec-vpn"]
+ if "pair-policy" in policy_permit["tunnel"]:
+ permit["tunnel"]["pair_policy"] = policy_permit["tunnel"]["pair-policy"]
+
+ # end of match action parsing
+
+ # parse description of security policy
+ if "description" in policy:
+ tmp_policy["description"] = policy["description"]
+
+ # parse scheduler name of security policy
+ if "scheduler-name" in policy:
+ tmp_policy["scheduler_name"] = policy["scheduler-name"]
+
+ test = utils.remove_empties(tmp_policy)
+ policy_list.append(test)
+
+ return policy_list
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies_global/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies_global/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies_global/security_policies_global.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies_global/security_policies_global.py
new file mode 100644
index 000000000..692a07b60
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_policies_global/security_policies_global.py
@@ -0,0 +1,245 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2022 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos security_policies_global 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.security_policies_global.security_policies_global import (
+ Security_policies_globalArgs,
+)
+
+
+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 Security_policies_globalFacts(object):
+ """The junos security_policies_global fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Security_policies_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 _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_dict
+
+ def _get_device_data(self, connection, config_filters):
+ """
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filters)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for security_polices
+ :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>
+ <security>
+ <policies>
+ </policies>
+ </security>
+ </configuration>
+ """
+ data = self._get_device_data(connection, config_filter)
+
+ # split the config into instances of the resource
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+ objs = {}
+ resources = data.xpath("configuration/security/policies")
+ for resource in resources:
+ if resource is not None:
+ xml = self._get_xml_dict(resource)
+ objs = self.render_config(self.generated_spec, xml)
+
+ facts = {}
+ if objs:
+ facts["security_policies_global"] = {}
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ )
+
+ facts["security_policies_global"] = utils.remove_empties(
+ params["config"],
+ )
+
+ 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
+ """
+ security_policies_global_config = {}
+
+ # Parse facts for security policies global settings
+ global_policies = conf.get("policies") or {}
+
+ if "default-policy" in global_policies:
+ if "deny-all" in global_policies["default-policy"]:
+ security_policies_global_config["default_policy"] = "deny-all"
+ elif "permit-all" in global_policies["default-policy"]:
+ security_policies_global_config["default_policy"] = "permit-all"
+
+ if "policy-rematch" in global_policies:
+ security_policies_global_config["policy_rematch"] = {}
+ security_policies_global_config["policy_rematch"]["enable"] = True
+
+ global_policies["policy-rematch"] = global_policies["policy-rematch"] or {}
+ if "extensive" in global_policies["policy-rematch"]:
+ security_policies_global_config["policy_rematch"]["extensive"] = True
+
+ if "policy-stats" in global_policies:
+ security_policies_global_config["policy_stats"] = {}
+ security_policies_global_config["policy_stats"]["enable"] = True
+
+ global_policies["policy-stats"] = global_policies["policy-stats"] or {}
+ if "system-wide" in global_policies["policy-stats"]:
+ if global_policies["policy-stats"]["system-wide"] == "enable":
+ security_policies_global_config["policy_stats"]["system_wide"] = True
+ elif global_policies["policy-stats"]["system-wide"] == "disable":
+ security_policies_global_config["policy_stats"]["system_wide"] = False
+
+ if "pre-id-default-policy" in global_policies:
+ security_policies_global_config["pre_id_default_policy_action"] = {}
+ pre_id_action = security_policies_global_config["pre_id_default_policy_action"]
+ policy_pre_id_action = global_policies["pre-id-default-policy"]["then"]
+
+ if "log" in policy_pre_id_action:
+ pre_id_action["log"] = {}
+ if "session-close" in policy_pre_id_action["log"]:
+ pre_id_action["log"]["session_close"] = True
+ if "session-init" in policy_pre_id_action["log"]:
+ pre_id_action["log"]["session_init"] = True
+
+ if "session-timeout" in policy_pre_id_action:
+ pre_id_action["session_timeout"] = {}
+ if "icmp" in policy_pre_id_action["session-timeout"]:
+ pre_id_action["session_timeout"]["icmp"] = policy_pre_id_action[
+ "session-timeout"
+ ]["icmp"]
+ if "icmp6" in policy_pre_id_action["session-timeout"]:
+ pre_id_action["session_timeout"]["icmp6"] = policy_pre_id_action[
+ "session-timeout"
+ ]["icmp6"]
+ if "ospf" in policy_pre_id_action["session-timeout"]:
+ pre_id_action["session_timeout"]["ospf"] = policy_pre_id_action[
+ "session-timeout"
+ ]["ospf"]
+ if "others" in policy_pre_id_action["session-timeout"]:
+ pre_id_action["session_timeout"]["others"] = policy_pre_id_action[
+ "session-timeout"
+ ]["others"]
+ if "tcp" in policy_pre_id_action["session-timeout"]:
+ pre_id_action["session_timeout"]["tcp"] = policy_pre_id_action[
+ "session-timeout"
+ ]["tcp"]
+ if "udp" in policy_pre_id_action["session-timeout"]:
+ pre_id_action["session_timeout"]["udp"] = policy_pre_id_action[
+ "session-timeout"
+ ]["udp"]
+
+ if "traceoptions" in global_policies:
+ security_policies_global_config["traceoptions"] = {}
+ traceoptions = security_policies_global_config["traceoptions"]
+ policy_traceoptions = global_policies["traceoptions"]
+
+ if "file" in policy_traceoptions:
+ traceoptions["file"] = {}
+ if "files" in policy_traceoptions["file"]:
+ traceoptions["file"]["files"] = policy_traceoptions["file"]["files"]
+ if "match" in policy_traceoptions["file"]:
+ traceoptions["file"]["match"] = policy_traceoptions["file"]["match"]
+ if "size" in policy_traceoptions["file"]:
+ traceoptions["file"]["size"] = policy_traceoptions["file"]["size"]
+ if "world-readable" in policy_traceoptions["file"]:
+ traceoptions["file"]["world_readable"] = True
+ if "no-world-readable" in policy_traceoptions["file"]:
+ traceoptions["file"]["no_world_readable"] = True
+
+ if "flag" in policy_traceoptions:
+ traceoptions["flag"] = {}
+
+ if policy_traceoptions["flag"]["name"] == "all":
+ traceoptions["flag"] = "all"
+ elif policy_traceoptions["flag"]["name"] == "configuration":
+ traceoptions["flag"] = "configuration"
+ elif policy_traceoptions["flag"]["name"] == "compilation":
+ traceoptions["flag"] = "compilation"
+ elif policy_traceoptions["flag"]["name"] == "ipc":
+ traceoptions["flag"] = "ipc"
+ elif policy_traceoptions["flag"]["name"] == "lookup":
+ traceoptions["flag"] = "lookup"
+ elif policy_traceoptions["flag"]["name"] == "routing-socket":
+ traceoptions["flag"] = "routing-socket"
+ elif policy_traceoptions["flag"]["name"] == "rules":
+ traceoptions["flag"] = "rules"
+
+ if "no-remote-trace" in policy_traceoptions:
+ traceoptions["no_remote_trace"] = True
+
+ return security_policies_global_config
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_zones/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_zones/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_zones/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_zones/security_zones.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_zones/security_zones.py
new file mode 100644
index 000000000..5368bf77f
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/security_zones/security_zones.py
@@ -0,0 +1,337 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2022 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos security_zones 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.security_zones.security_zones import (
+ Security_zonesArgs,
+)
+
+
+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 Security_zonesFacts(object):
+ """The junos security_zones fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Security_zonesArgs.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 _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_dict
+
+ def _get_device_data(self, connection, config_filters):
+ """
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filters)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for security_polices
+ :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>
+ <security>
+ <zones>
+ </zones>
+ </security>
+ </configuration>
+ """
+ data = self._get_device_data(connection, config_filter)
+
+ # split the config into instances of the resource
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+ objs = {}
+ resources = data.xpath("configuration/security/zones")
+ for resource in resources:
+ if resource is not None:
+ xml = self._get_xml_dict(resource)
+ objs = self.render_config(self.generated_spec, xml)
+
+ facts = {}
+ if objs:
+ facts["security_zones"] = {}
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ )
+
+ facts["security_zones"] = utils.remove_empties(params["config"])
+
+ 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
+ """
+ security_zones_config = {}
+
+ # Parse facts for security zones
+ conf = conf.get("zones")
+
+ if "functional-zone" in conf:
+ security_zones_config["functional_zone_management"] = {}
+ functional_zone_management = conf.get("functional-zone").get("management") or {}
+
+ if "description" in functional_zone_management:
+ security_zones_config["functional_zone_management"][
+ "description"
+ ] = functional_zone_management["description"]
+
+ if "host-inbound-traffic" in functional_zone_management:
+ security_zones_config["functional_zone_management"][
+ "host_inbound_traffic"
+ ] = self.parse_host_inbound_traffic(
+ functional_zone_management["host-inbound-traffic"],
+ )
+
+ if "interfaces" in functional_zone_management:
+ if isinstance(functional_zone_management["interfaces"], dict):
+ functional_zone_management["interfaces"] = [
+ functional_zone_management["interfaces"],
+ ]
+ security_zones_config["functional_zone_management"]["interfaces"] = [
+ interface["name"] for interface in functional_zone_management["interfaces"]
+ ]
+
+ if "screen" in functional_zone_management:
+ security_zones_config["functional_zone_management"][
+ "screen"
+ ] = functional_zone_management["screen"]
+
+ if "security-zone" in conf:
+ security_zones_list = conf.get("security-zone")
+ if isinstance(security_zones_list, dict):
+ security_zones_list = [security_zones_list]
+ security_zones_config["zones"] = []
+
+ for security_zone in security_zones_list:
+ temp_sec_zone = {}
+ temp_sec_zone["name"] = security_zone["name"]
+
+ if "address-book" in security_zone:
+ temp_sec_zone["address_book"] = {}
+
+ if "address" in security_zone["address-book"]:
+ temp_sec_zone["address_book"]["addresses"] = []
+ if isinstance(
+ security_zone["address-book"]["address"],
+ dict,
+ ):
+ security_zone["address-book"]["address"] = [
+ security_zone["address-book"]["address"],
+ ]
+
+ for address in security_zone["address-book"]["address"]:
+ temp_address = {}
+
+ temp_address["name"] = address["name"]
+ if "ip-prefix" in address:
+ temp_address["ip_prefix"] = address["ip-prefix"]
+ elif "dns-name" in address:
+ temp_address["dns_name"] = {}
+ temp_address["dns_name"]["name"] = address["dns-name"]["name"]
+ if "ipv4-only" in address["dns-name"]:
+ temp_address["dns_name"]["ipv4_only"] = True
+ if "ipv6-only" in address["dns-name"]:
+ temp_address["dns_name"]["ipv6_only"] = True
+ elif "range-address" in address:
+ temp_address["range_address"] = {}
+ temp_address["range_address"]["from"] = address["range-address"][
+ "name"
+ ]
+ temp_address["range_address"]["to"] = address["range-address"][
+ "to"
+ ]["range-high"]
+ elif "wildcard-address" in address:
+ temp_address["wildcard_address"] = address["wildcard-address"][
+ "name"
+ ]
+ if "description" in address:
+ temp_address["description"] = address["description"]
+
+ temp_sec_zone["address_book"]["addresses"].append(
+ temp_address,
+ )
+
+ if "address-set" in security_zone["address-book"]:
+ temp_sec_zone["address_book"]["address_sets"] = []
+
+ for address_set in security_zone["address-book"]["address-set"]:
+
+ temp_address_set = {}
+
+ temp_address_set["name"] = address_set["name"]
+ if "address" in address_set:
+ if isinstance(address_set["address"], dict):
+ address_set["address"] = [
+ address_set["address"],
+ ]
+ temp_address_set["addresses"] = [
+ address["name"] for address in address_set["address"]
+ ]
+ if "address-set" in address_set:
+ if isinstance(
+ address_set["address-set"],
+ dict,
+ ):
+ address_set["address-set"] = [
+ address_set["address-set"],
+ ]
+ temp_address_set["address_sets"] = [
+ addr_set["name"] for addr_set in address_set["address-set"]
+ ]
+ if "description" in address_set:
+ temp_address_set["description"] = address_set["description"]
+
+ temp_sec_zone["address_book"]["address_sets"].append(temp_address_set)
+
+ if "advance-policy-based-routing-profile" in security_zone:
+ temp_sec_zone["advance_policy_based_routing_profile"] = security_zone[
+ "advance-policy-based-routing-profile"
+ ]["profile"]
+ if "advanced-connection-tracking" in security_zone:
+ temp_sec_zone["advanced_connection_tracking"] = {}
+ temp_act = temp_sec_zone["advanced_connection_tracking"]
+ if "mode" in security_zone["advanced-connection-tracking"]:
+ temp_act["mode"] = security_zone["advanced-connection-tracking"]["mode"]
+ if "timeout" in security_zone["advanced-connection-tracking"]:
+ temp_act["timeout"] = security_zone["advanced-connection-tracking"][
+ "timeout"
+ ]
+ if (
+ "track-all-policies-to-this-zone"
+ in security_zone["advanced-connection-tracking"]
+ ):
+ temp_act["track_all_policies_to_this_zone"] = True
+ if "application-tracking" in security_zone:
+ temp_sec_zone["application_tracking"] = True
+ if "description" in security_zone:
+ temp_sec_zone["description"] = security_zone["description"]
+ if "enable-reverse-reroute" in security_zone:
+ temp_sec_zone["enable_reverse_reroute"] = True
+ if "host-inbound-traffic" in security_zone:
+ temp_sec_zone["host_inbound_traffic"] = self.parse_host_inbound_traffic(
+ security_zone["host-inbound-traffic"],
+ )
+ if "interfaces" in security_zone:
+ if isinstance(security_zone["interfaces"], string_types):
+ security_zone["interfaces"] = [
+ security_zone["interfaces"],
+ ]
+ temp_sec_zone["interfaces"] = [
+ interface["name"] for interface in security_zone["interfaces"]
+ ]
+ if "screen" in security_zone:
+ temp_sec_zone["screen"] = security_zone["screen"]
+ if "source-identity-log" in security_zone:
+ temp_sec_zone["source_identity_log"] = True
+ if "tcp-rst" in security_zone:
+ temp_sec_zone["tcp_rst"] = True
+ if "unidirectional-session-refreshing" in security_zone:
+ temp_sec_zone["unidirectional_session_refreshing"] = True
+
+ security_zones_config["zones"].append(temp_sec_zone)
+
+ return security_zones_config
+
+ def parse_host_inbound_traffic(self, host_inbound_traffic):
+ temp_hit = {}
+
+ if "protocols" in host_inbound_traffic:
+ temp_hit["protocols"] = []
+ if isinstance(host_inbound_traffic["protocols"], dict):
+ host_inbound_traffic["protocols"] = [
+ host_inbound_traffic["protocols"],
+ ]
+ for protocol in host_inbound_traffic["protocols"]:
+ temp_protocol = {}
+ temp_protocol["name"] = protocol["name"]
+ if "except" in protocol:
+ temp_protocol["except"] = True
+
+ temp_hit["protocols"].append(temp_protocol)
+
+ if "system-services" in host_inbound_traffic:
+ temp_hit["system_services"] = []
+ if isinstance(host_inbound_traffic["system-services"], dict):
+ host_inbound_traffic["system-services"] = [
+ host_inbound_traffic["system-services"],
+ ]
+ for system_services in host_inbound_traffic["system-services"]:
+ temp_system_services = {}
+ temp_system_services["name"] = system_services["name"]
+ if "except" in system_services:
+ temp_system_services["except"] = True
+
+ temp_hit["system_services"].append(temp_system_services)
+
+ return temp_hit
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/snmp_server/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/snmp_server/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/snmp_server/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/snmp_server/snmp_server.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/snmp_server/snmp_server.py
new file mode 100644
index 000000000..b3c35bfec
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/snmp_server/snmp_server.py
@@ -0,0 +1,851 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The junos snmp_server 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.basic import missing_required_lib
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.snmp_server.snmp_server import (
+ Snmp_serverArgs,
+)
+
+
+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 Snmp_serverFacts(object):
+ """The junos snmp_server fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Snmp_serverArgs.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 get_device_data(self, connection, config_filter):
+ """
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return connection.get_configuration(filter=config_filter)
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for ntp_gloabl
+ :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>
+ <snmp>
+ </snmp>
+ </configuration>
+ """
+ data = self.get_device_data(connection, config_filter)
+
+ if isinstance(data, string_types):
+ data = etree.fromstring(
+ to_bytes(data, errors="surrogate_then_replace"),
+ )
+ objs = {}
+ resources = data.xpath("configuration/snmp")
+ for resource in resources:
+ if resource is not None:
+ xml = self._get_xml_dict(resource)
+ objs = self.render_config(self.generated_spec, xml)
+
+ facts = {}
+ if objs:
+ facts["snmp_server"] = {}
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ )
+
+ facts["snmp_server"] = utils.remove_empties(params["config"])
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def _get_xml_dict(self, xml_root):
+ if not HAS_XMLTODICT:
+ self._module.fail_json(msg=missing_required_lib("xmltodict"))
+ xml_dict = xmltodict.parse(
+ etree.tostring(xml_root),
+ dict_constructor=dict,
+ )
+ return xml_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
+ """
+ snmp_server_config = {}
+
+ # Parse facts for BGP address-family global node
+ conf = conf.get("snmp")
+
+ # Read arp node
+ if "arp" in conf.keys():
+ arp = conf.get("arp")
+ arp_dict = {}
+ if arp is None:
+ arp_dict["set"] = True
+ elif "host-name-resolution" in arp.keys():
+ arp_dict["host_name_resolution"] = True
+ snmp_server_config["arp"] = arp_dict
+
+ # Read client_lists node
+ if "client-list" in conf.keys():
+ snmp_server_config["client_lists"] = self.get_client_list(
+ conf.get("client-list"),
+ )
+
+ # Read communities node
+ if "community" in conf.keys():
+ comm_lst = []
+ comm_lists = conf.get("community")
+
+ if isinstance(comm_lists, dict):
+ comm_lst.append(self.get_community(comm_lists))
+ else:
+ for item in comm_lists:
+ comm_lst.append(self.get_community(item))
+ if comm_lst:
+ snmp_server_config["communities"] = comm_lst
+
+ # Read routing-instance-access
+ if "routing-instance-access" in conf.keys():
+ rinst_access = conf.get("routing-instance-access")
+ rints_dict = {}
+ access_lst = []
+ if rinst_access is None:
+ rints_dict["set"] = True
+ else:
+ access_lists = rinst_access.get("access-list")
+ if isinstance(access_lists, dict):
+ access_lst.append(access_lists["name"])
+ else:
+ for item in access_lists:
+ access_lst.append(item["name"])
+ rints_dict["access_lists"] = access_lst
+ snmp_server_config["routing_instance_access"] = rints_dict
+
+ # Read contact
+ if "contact" in conf.keys():
+ snmp_server_config["contact"] = conf.get("contact")
+
+ # Read description
+ if "description" in conf.keys():
+ snmp_server_config["description"] = conf.get("description")
+
+ # Read customization
+ if "customization" in conf.keys():
+ custom_dict = {}
+ if "ether-stats-ifd-only" in conf["customization"].keys():
+ custom_dict["ether_stats_ifd_only"] = True
+ snmp_server_config["customization"] = custom_dict
+
+ # Read engine-id
+ if "engine-id" in conf.keys():
+ engine_id = conf.get("engine-id")
+ engine_id_dict = {}
+ if "local" in engine_id.keys():
+ engine_id_dict["local"] = engine_id["local"]
+ elif "use-default-ip-address" in engine_id.keys():
+ engine_id_dict["use_default_ip_address"] = True
+ else:
+ engine_id_dict["use_mac_address"] = True
+
+ snmp_server_config["engine_id"] = engine_id_dict
+
+ # Read filter-duplicates
+ if "filter-duplicates" in conf.keys():
+ snmp_server_config["filter_duplicates"] = True
+
+ # Read filter-interfaces
+ if "filter-interfaces" in conf.keys():
+ filter_dict = {}
+ filter_interfaces = conf.get("filter-interfaces")
+
+ if filter_interfaces is None:
+ filter_dict["set"] = True
+ else:
+ if "all-internal-interfaces" in filter_interfaces.keys():
+ filter_dict["all_internal_interfaces"] = True
+ if "interfaces" in filter_interfaces.keys():
+ int_lst = []
+ interfaces = filter_interfaces.get("interfaces")
+ if isinstance(interfaces, dict):
+ int_lst.append(interfaces["name"])
+ else:
+ for item in interfaces:
+ int_lst.append(item["name"])
+ filter_dict["interfaces"] = int_lst
+
+ snmp_server_config["filter_interfaces"] = filter_dict
+
+ # Read health_monitor
+ if "health-monitor" in conf.keys():
+ health_dict = {}
+ health_monitor = conf.get("health-monitor")
+
+ if health_monitor is None:
+ health_dict["set"] = True
+ else:
+ if "idp" in health_monitor.keys():
+ health_dict["idp"] = True
+ if "falling-threshold" in health_monitor.keys():
+ health_dict["falling_threshold"] = health_monitor["falling-threshold"]
+ if "rising-threshold" in health_monitor.keys():
+ health_dict["rising_threshold"] = health_monitor["rising-threshold"]
+ if "interval" in health_monitor.keys():
+ health_dict["interval"] = health_monitor["interval"]
+ snmp_server_config["health_monitor"] = health_dict
+
+ # Read if-count-with-filter-interfaces
+ if "if-count-with-filter-interfaces" in conf.keys():
+ snmp_server_config["if_count_with_filter_interfaces"] = True
+
+ # Read interfaces
+ if "interfaces" in conf.keys():
+ int_lst = []
+ interfaces = conf.get("interfaces")
+ if isinstance(interfaces, dict):
+ int_lst.append(interfaces["name"])
+ else:
+ for item in interfaces:
+ int_lst.append(item["name"])
+
+ snmp_server_config["interfaces"] = int_lst
+
+ # Read location
+ if "location" in conf.keys():
+ snmp_server_config["location"] = conf.get("location")
+
+ # Read logical-system-trap-filter
+ if "logical-system-trap-filter" in conf.keys():
+ snmp_server_config["logical_system_trap_filter"] = True
+
+ # Read name
+ if "system-name" in conf.keys():
+ snmp_server_config["name"] = conf.get("system-name")
+
+ # Read nonvolatile
+ if "nonvolatile" in conf.keys():
+ cfg_dict = {}
+ cfg_dict["commit_delay"] = conf["nonvolatile"].get("commit-delay")
+ snmp_server_config["nonvolatile"] = cfg_dict
+
+ # Read rmon
+ if "rmon" in conf.keys():
+ cfg_dict = {}
+ events = []
+ alarms = []
+ rmon = conf.get("rmon")
+
+ if rmon is None:
+ cfg_dict["set"] = True
+ else:
+ if "event" in rmon.keys():
+ event = rmon.get("event")
+ if isinstance(event, dict):
+ events.append(self.get_events(event))
+ else:
+ for item in event:
+ events.append(self.get_events(item))
+ cfg_dict["events"] = events
+ if "alarm" in rmon.keys():
+ alarm = rmon.get("alarm")
+ if isinstance(alarm, dict):
+ alarms.append(self.get_alarms(alarm))
+ else:
+ for item in alarm:
+ alarms.append(self.get_alarms(item))
+ cfg_dict["alarms"] = alarms
+
+ snmp_server_config["rmon"] = cfg_dict
+
+ # Read subagent node
+ if "subagent" in conf.keys():
+ cfg_dict = {}
+ subagent = conf.get("subagent")
+
+ if "tcp" in subagent.keys():
+ tcp = subagent.get("tcp")
+ tcp_dict = {}
+ if tcp is None:
+ tcp_dict["set"] = True
+ else:
+ tcp_dict["routing_instances_default"] = True
+ cfg_dict["tcp"] = tcp_dict
+ snmp_server_config["subagent"] = cfg_dict
+
+ # Read traceoptions node
+ if "traceoptions" in conf.keys():
+ cfg_dict = {}
+ trace_options = conf.get("traceoptions")
+
+ if "file" in trace_options.keys():
+ cfg_dict["file"] = self.get_trace_file(
+ trace_options.get("file"),
+ )
+ if "flag" in trace_options.keys():
+ cfg_dict["flag"] = self.get_trace_flag(
+ trace_options.get("flag"),
+ )
+ if "memory-trace" in trace_options.keys():
+ mtrace = trace_options.get("memory-trace")
+ trace_dict = {}
+ if mtrace is None:
+ trace_dict["set"] = True
+ else:
+ trace_dict["size"] = mtrace.get("size")
+ cfg_dict["memory_trace"] = trace_dict
+ if "no-remote-trace" in conf.keys():
+ cfg_dict["no_remote_trace"] = True
+
+ snmp_server_config["traceoptions"] = cfg_dict
+
+ # Read trap-group node
+ if "trap-group" in conf.keys():
+ cfg_lst = []
+ trap_groups = conf.get("trap-group")
+
+ if isinstance(trap_groups, dict):
+ cfg_lst.append(self.get_trap_group(trap_groups))
+ else:
+ for item in trap_groups:
+ cfg_lst.append(self.get_trap_group(item))
+
+ snmp_server_config["trap_groups"] = cfg_lst
+
+ # Read trap-options node
+ if "trap-options" in conf.keys():
+ cfg_dict = {}
+ trap_options = conf.get("trap-options")
+ if trap_options is None:
+ cfg_dict["set"] = True
+ else:
+ if "agent-address" in trap_options.keys():
+ agent_dict = {}
+ agent_dict["outgoing_interface"] = True
+ cfg_dict["agent_address"] = agent_dict
+ if "context-oid" in trap_options.keys():
+ cfg_dict["context_oid"] = True
+ if "enterprise-oid" in trap_options.keys():
+ cfg_dict["enterprise_oid"] = True
+ if "source-address" in trap_options.keys():
+ source_address = trap_options.get("source-address")
+ source_dict = {}
+ if "address" in source_address.keys():
+ source_dict["address"] = source_address["address"]
+ if "lowest-loopback" in source_address.keys():
+ source_dict["lowest_loopback"] = True
+ cfg_dict["source_address"] = source_dict
+ if "routing-instance" in trap_options.keys():
+ cfg_dict["routing_instance"] = trap_options.get(
+ "routing-instance",
+ )
+
+ snmp_server_config["trap_options"] = cfg_dict
+
+ # Read snmp-v3
+ if "v3" in conf.keys():
+ cfg_dict = {}
+ snmp_v3 = conf.get("v3")
+
+ if "notify" in snmp_v3.keys():
+ notify_lst = []
+ notify = snmp_v3.get("notify")
+ if isinstance(notify, dict):
+ notify_lst.append(self.get_notify(notify))
+ else:
+ for item in notify:
+ notify_lst.append(self.get_notify(item))
+ cfg_dict["notify"] = notify_lst
+ if "notify-filter" in snmp_v3.keys():
+ notify_filter = snmp_v3.get("notify-filter")
+ notify_lst = []
+ if isinstance(notify_filter, dict):
+ notify_lst.append(self.get_notify_filter(notify_filter))
+ else:
+ for item in notify_filter:
+ notify_lst.append(self.get_notify_filter(item))
+ cfg_dict["notify_filter"] = notify_lst
+
+ if "snmp-community" in snmp_v3.keys():
+ comm_lst = []
+ communities = snmp_v3.get("snmp-community")
+ if isinstance(communities, dict):
+ comm_lst.append(self.get_snmpv3_comm(communities))
+ else:
+ for item in communities:
+ comm_lst.append(self.get_snmpv3_comm(item))
+ cfg_dict["snmp_community"] = comm_lst
+
+ if "target-address" in snmp_v3.keys():
+ tar_addr_lst = []
+ tar_addr = snmp_v3.get("target-address")
+ if isinstance(tar_addr, dict):
+ tar_addr_lst.append(self.get_snmpv3_target(tar_addr))
+ else:
+ for item in tar_addr:
+ tar_addr_lst.append(self.get_snmpv3_target(item))
+ cfg_dict["target_addresses"] = tar_addr_lst
+
+ if "target-parameters" in snmp_v3.keys():
+ tar_param_lst = []
+ tar_params = snmp_v3.get("target-parameters")
+ if isinstance(tar_params, dict):
+ tar_param_lst.append(self.get_snmpv3_param(tar_params))
+ else:
+ for item in tar_params:
+ tar_param_lst.append(self.get_snmpv3_param(item))
+ cfg_dict["target_parameters"] = tar_param_lst
+
+ if "usm" in snmp_v3.keys():
+ usm_dict = {}
+ usm = snmp_v3.get("usm")
+ if "local-engine" in usm.keys():
+ local_dict = {}
+ local_engine = usm.get("local-engine")
+ if "user" in local_engine.keys():
+ user_lst = []
+ users = local_engine.get("user")
+ if isinstance(users, dict):
+ user_lst.append(self.get_user(users))
+ else:
+ for item in users:
+ user_lst.append(self.get_user(item))
+ local_dict["users"] = user_lst
+
+ usm_dict["local_engine"] = local_dict
+
+ if "remote-engine" in usm.keys():
+ remote_lst = []
+ remote_dict = {}
+ remote_engine = usm.get("remote-engine")
+ if isinstance(remote_engine, dict):
+ remote_dict["id"] = remote_engine["name"]
+ if "user" in remote_engine.keys():
+ user_lst = []
+ users = remote_engine.get("user")
+ if isinstance(users, dict):
+ user_lst.append(self.get_user(users))
+ else:
+ for item in users:
+ user_lst.append(self.get_user(item))
+ remote_dict["users"] = user_lst
+ remote_lst.append(remote_dict)
+ else:
+ for remote_eng in remote_engine:
+ remote_dict["id"] = remote_eng["name"]
+ if "user" in remote_eng.keys():
+ user_lst = []
+ users = remote_eng.get("user")
+ if isinstance(users, dict):
+ user_lst.append(self.get_user(users))
+ else:
+ for item in users:
+ user_lst.append(self.get_user(item))
+ remote_dict["users"] = user_lst
+ remote_lst.append(remote_dict)
+ remote_dict = {}
+ usm_dict["remote_engine"] = remote_lst
+ cfg_dict["usm"] = usm_dict
+
+ snmp_server_config["snmp_v3"] = cfg_dict
+
+ # Read view
+ if "view" in conf.keys():
+ cfg_lst = []
+ views = conf.get("view")
+ if isinstance(views, dict):
+ cfg_lst.append(self.get_view(views))
+ else:
+ for item in views:
+ cfg_lst.append(self.get_view(item))
+
+ snmp_server_config["views"] = cfg_lst
+ return utils.remove_empties(snmp_server_config)
+
+ def get_view(self, cfg):
+ cfg_dict = {}
+ cfg_dict["name"] = cfg["name"]
+ if "oid" in cfg.keys():
+ oid_lst = []
+ oid_dict = {}
+ oids = cfg.get("oid")
+ if isinstance(oids, list):
+ for item in oids:
+ oid_dict["oid"] = item["name"]
+ if "exclude" in item.keys():
+ oid_dict["exclude"] = True
+ if "include" in item.keys():
+ oid_dict["include"] = True
+ oid_lst.append(oid_dict)
+ oid_dict = {}
+ else:
+ oid_dict["oid"] = oids["name"]
+ if "exclude" in oids.keys():
+ oid_dict["exclude"] = True
+ if "include" in oids.keys():
+ oid_dict["include"] = True
+ oid_lst.append(oid_dict)
+ cfg_dict["oids"] = oid_lst
+
+ return cfg_dict
+
+ def get_user(self, cfg):
+ cfg_dict = {}
+ cfg_dict["name"] = cfg.get("name")
+ if "authentication-md5" in cfg.keys():
+ auth_dict = {}
+ auth_md5 = cfg.get("authentication-md5")
+ auth_dict["key"] = auth_md5["authentication-key"]
+ if "authentication-password" in auth_md5.keys():
+ auth_dict["password"] = auth_md5["authentication-password"]
+ cfg_dict["authentication_md5"] = auth_dict
+ if "authentication-none" in cfg.keys():
+ cfg_dict["authentication_none"] = True
+ if "authentication-sha" in cfg.keys():
+ auth_dict = {}
+ auth_sha = cfg.get("authentication-sha")
+ auth_dict["key"] = auth_sha["authentication-key"]
+ if "authentication-password" in auth_sha.keys():
+ auth_dict["password"] = auth_sha["authentication-password"]
+ cfg_dict["authentication_sha"] = auth_dict
+ if "privacy-3des" in cfg.keys():
+ pri_dict = {}
+ pri_3des = cfg.get("privacy-3des")
+ pri_dict["key"] = pri_3des["privacy-key"]
+ if "privacy-password" in pri_3des.keys():
+ pri_dict["password"] = pri_3des["privacy-password"]
+ cfg_dict["privacy_3des"] = pri_dict
+ if "privacy-aes128" in cfg.keys():
+ pri_dict = {}
+ pri_aes = cfg.get("privacy-aes128")
+ pri_dict["key"] = pri_aes["privacy-key"]
+ if "privacy-password" in pri_aes.keys():
+ pri_dict["password"] = pri_aes["privacy-password"]
+ cfg_dict["privacy_aes128"] = pri_dict
+ if "privacy-none" in cfg.keys():
+ cfg_dict["privacy_none"] = True
+ return cfg_dict
+
+ def get_snmpv3_param(self, cfg):
+ cfg_dict = {}
+ cfg_dict["name"] = cfg.get("name")
+ if "notify-filter" in cfg.keys():
+ cfg_dict["notify_filter"] = cfg.get("notify-filter")
+ if "parameters" in cfg.keys():
+ param_dict = {}
+ parameters = cfg.get("parameters")
+ for key in parameters.keys():
+ param_dict[key.replace("-", "_")] = parameters.get(key)
+ cfg_dict["parameters"] = param_dict
+ return cfg_dict
+
+ def get_snmpv3_target(self, cfg):
+ cfg_dict = {}
+ for key in cfg.keys():
+ cfg_dict[key.replace("-", "_")] = cfg.get(key)
+ return cfg_dict
+
+ def get_snmpv3_comm(self, cfg):
+ cfg_dict = {}
+ cfg_dict["community_index"] = cfg["name"]
+ if "context" in cfg.keys():
+ cfg_dict["context"] = cfg.get("context")
+ if "tag" in cfg.keys():
+ cfg_dict["tag"] = cfg.get("tag")
+ if "security-name" in cfg.keys():
+ cfg_dict["security_name"] = cfg.get("security-name")
+ if "community-name" in cfg.keys():
+ cfg_dict["community_name"] = cfg.get("community-name")
+ return cfg_dict
+
+ def get_notify_filter(self, cfg):
+ cfg_dict = {}
+ cfg_dict["name"] = cfg["name"]
+ if "oid" in cfg.keys():
+ oid_lst = []
+ oid_dict = {}
+ oids = cfg.get("oid")
+ if isinstance(oids, list):
+ for item in oids:
+ oid_dict["oid"] = item["name"]
+ if "exclude" in item.keys():
+ oid_dict["exclude"] = True
+ if "include" in item.keys():
+ oid_dict["include"] = True
+ oid_lst.append(oid_dict)
+ oid_dict = {}
+ else:
+ oid_dict["oid"] = oids["name"]
+ if "exclude" in oids.keys():
+ oid_dict["exclude"] = True
+ if "include" in oids.keys():
+ oid_dict["include"] = True
+ oid_lst.append(oid_dict)
+ cfg_dict["oids"] = oid_lst
+ return cfg_dict
+
+ def get_notify(self, cfg):
+ cfg_dict = {}
+ cfg_dict["name"] = cfg["name"]
+ if "type" in cfg.keys():
+ cfg_dict["type"] = cfg.get("type")
+ if "tag" in cfg.keys():
+ cfg_dict["tag"] = cfg.get("tag")
+
+ return cfg_dict
+
+ def get_trap_group(self, cfg):
+ cfg_dict = {}
+ cfg_dict["name"] = cfg.get("name")
+ if "categories" in cfg.keys():
+ categories_dict = {}
+ categories = cfg.get("categories")
+ for item in categories.keys():
+ if item == "otn-alarms":
+ otn_dict = {}
+ otn_alarms = categories.get("otn-alarms")
+ for key in otn_alarms.keys():
+ otn_dict[key.replace("-", "_")] = True
+ categories_dict["otn_alarms"] = otn_dict
+ else:
+ categories_dict[item.replace("-", "_")] = True
+ cfg_dict["categories"] = categories_dict
+ if "destination-port" in cfg.keys():
+ cfg_dict["destination_port"] = cfg.get("destination-port")
+ if "routing-instance" in cfg.keys():
+ cfg_dict["routing_instance"] = cfg.get("routing-instance")
+ if "version" in cfg.keys():
+ cfg_dict["version"] = cfg.get("version")
+ if "targets" in cfg.keys():
+ targets_lst = []
+ targets = cfg.get("targets")
+ if isinstance(targets, dict):
+ targets_lst.append(targets["name"])
+ else:
+ for item in targets:
+ targets_lst.append(item["name"])
+ cfg_dict["targets"] = targets_lst
+
+ return cfg_dict
+
+ def get_trace_flag(self, cfg):
+ cfg_dict = {}
+ if isinstance(cfg, dict):
+ cfg_dict[cfg["name"].replace("-", "_")] = True
+ else:
+ for item in cfg:
+ cfg_dict[item["name"].replace("-", "_")] = True
+
+ return cfg_dict
+
+ def get_trace_file(self, cfg):
+ cfg_dict = {}
+ if "match" in cfg.keys():
+ cfg_dict["match"] = cfg.get("match")
+ if "files" in cfg.keys():
+ cfg_dict["files"] = cfg.get("files")
+ if "no-world-readable" in cfg.keys():
+ cfg_dict["no_world_readable"] = True
+ if "world-readable" in cfg.keys():
+ cfg_dict["world_readable"] = True
+ if "size" in cfg.keys():
+ cfg_dict["size"] = cfg.get("size")
+
+ return cfg_dict
+
+ def get_events(self, cfg):
+ cfg_dict = {}
+ cfg_dict["id"] = cfg["name"]
+ if "community" in cfg.keys():
+ cfg_dict["community"] = cfg.get("community")
+ if "description" in cfg.keys():
+ cfg_dict["description"] = cfg.get("description")
+ if "type" in cfg.keys():
+ cfg_dict["type"] = cfg.get("type")
+ return cfg_dict
+
+ def get_alarms(self, cfg):
+ cfg_dict = {}
+ cfg_dict["id"] = cfg["name"]
+ if "description" in cfg.keys():
+ cfg_dict["description"] = cfg.get("description")
+ if "falling-event-index" in cfg.keys():
+ cfg_dict["falling_event_index"] = cfg.get("falling-event-index")
+ if "falling-threshold" in cfg.keys():
+ cfg_dict["falling_threshold"] = cfg.get("falling-threshold")
+ if "falling-threshold-interval" in cfg.keys():
+ cfg_dict["falling_threshold_interval"] = cfg.get(
+ "falling-threshold-interval",
+ )
+ if "interval" in cfg.keys():
+ cfg_dict["interval"] = cfg.get("interval")
+ if "request-type" in cfg.keys():
+ cfg_dict["request_type"] = cfg.get("request-type")
+ if "rising-event-index" in cfg.keys():
+ cfg_dict["rising_event_index"] = cfg.get("rising-event-index")
+ if "rising-threshold" in cfg.keys():
+ cfg_dict["rising_threshold"] = cfg.get("rising-threshold")
+ if "sample-type" in cfg.keys():
+ cfg_dict["sample_type"] = cfg.get("sample-type")
+ if "startup-alarm" in cfg.keys():
+ cfg_dict["startup_alarm"] = cfg.get("startup-alarm")
+ if "syslog-subtag" in cfg.keys():
+ cfg_dict["syslog_subtag"] = cfg.get("syslog-subtag")
+ if "variable" in cfg.keys():
+ cfg_dict["variable"] = cfg.get("variable")
+
+ return cfg_dict
+
+ def get_routing_instance(self, cfg):
+ cfg_dict = {}
+ cfg_dict["name"] = cfg["name"]
+ if "client-list-name" in cfg.keys():
+ cfg_dict["client_list_name"] = cfg.get("client-list-name")
+ if "clients" in cfg.keys():
+ client_lst = []
+ if isinstance(cfg.get("clients"), dict):
+ client_lst.append(self.get_client_address(cfg.get("clients")))
+ else:
+ clients = cfg.get("clients")
+ for item in clients:
+ client_lst.append(self.get_client_address(item))
+ cfg_dict["clients"] = client_lst
+ return cfg_dict
+
+ def get_community(self, cfg):
+ cfg_dict = {}
+ cfg_dict["name"] = cfg["name"]
+ if "authorization" in cfg.keys():
+ cfg_dict["authorization"] = cfg.get("authorization")
+ if "client-list-name" in cfg.keys():
+ cfg_dict["client_list_name"] = cfg.get("client-list-name")
+ if "clients" in cfg.keys():
+ client_lst = []
+ if isinstance(cfg.get("clients"), dict):
+ client_lst.append(self.get_client_address(cfg.get("clients")))
+ else:
+ clients = cfg.get("clients")
+ for item in clients:
+ client_lst.append(self.get_client_address(item))
+ cfg_dict["clients"] = client_lst
+ if "routing-instance" in cfg.keys():
+ rinst_lst = []
+ rinst_lists = cfg.get("routing-instance")
+
+ if isinstance(rinst_lists, dict):
+ rinst_lst.append(self.get_routing_instance(rinst_lists))
+ else:
+ for item in rinst_lists:
+ rinst_lst.append(self.get_routing_instance(item))
+ if rinst_lst:
+ cfg_dict["routing_instances"] = rinst_lst
+ if "view" in cfg.keys():
+ cfg_dict["view"] = cfg.get("view")
+
+ return cfg_dict
+
+ def get_client_address(self, cfg):
+ cfg_dict = {}
+ cfg_dict["address"] = cfg["name"]
+ if "restrict" in cfg.keys():
+ cfg_dict["restrict"] = True
+ return cfg_dict
+
+ def get_client_list(self, cfg):
+ client_lst = []
+ client_lists = cfg
+ client_dict = {}
+ if isinstance(client_lists, dict):
+ client_dict["name"] = client_lists["name"]
+ if "client-address-list" in client_lists.keys():
+ client_addresses = client_lists["client-address-list"]
+ client_address_lst = []
+ if isinstance(client_addresses, dict):
+ client_address_lst.append(
+ self.get_client_address(client_addresses),
+ )
+ else:
+ for address in client_addresses:
+ client_address_lst.append(
+ self.get_client_address(address),
+ )
+ if client_address_lst:
+ client_dict["addresses"] = client_address_lst
+ client_lst.append(client_dict)
+
+ else:
+ for client in client_lists:
+ client_dict["name"] = client["name"]
+ if "client-address-list" in client.keys():
+ client_addresses = client["client-address-list"]
+ client_address_lst = []
+ if isinstance(client_addresses, dict):
+ client_address_lst.append(
+ self.get_client_address(client_addresses),
+ )
+ else:
+ for address in client_addresses:
+ client_address_lst.append(
+ self.get_client_address(address),
+ )
+ if client_address_lst:
+ client_dict["addresses"] = client_address_lst
+ client_lst.append(client_dict)
+ client_dict = {}
+ return client_lst
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/static_routes/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/static_routes/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/static_routes/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/static_routes/static_routes.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/static_routes/static_routes.py
new file mode 100644
index 000000000..0be6f032d
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/static_routes/static_routes.py
@@ -0,0 +1,180 @@
+#
+# -*- 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.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.static_routes.static_routes import (
+ Static_routesArgs,
+)
+
+
+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)
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/vlans/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/vlans/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/vlans/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/vlans/vlans.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/vlans/vlans.py
new file mode 100644
index 000000000..f4d35e635
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/facts/vlans/vlans.py
@@ -0,0 +1,124 @@
+#
+# -*- 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.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.vlans.vlans import (
+ VlansArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.utils.utils import (
+ get_resource_config,
+)
+
+
+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 get_device_data(self, connection, config_filter):
+ """
+ :param connection:
+ :param config_filter:
+ :return:
+ """
+ return get_resource_config(connection, config_filter=config_filter)
+
+ 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 = self.get_device_data(connection, 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")
+ config["l3_interface"] = utils.get_xml_conf_arg(conf, "l3-interface")
+ return utils.remove_empties(config)
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/junos.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/junos.py
new file mode 100644
index 000000000..36452b123
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/junos.py
@@ -0,0 +1,509 @@
+#
+# (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
+import collections
+import json
+
+from contextlib import contextmanager
+from copy import deepcopy
+
+from ansible.module_utils._text import to_text
+from ansible.module_utils.connection import Connection, ConnectionError
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ NetconfConnection,
+)
+
+
+try:
+ from lxml.etree import Element, SubElement
+ from lxml.etree import tostring as xml_to_string
+
+ HAS_LXML = True
+except ImportError:
+ from xml.etree.ElementTree import Element, SubElement
+ from xml.etree.ElementTree import 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"])
+
+
+def tostring(element, encoding="UTF-8", pretty_print=False):
+ if HAS_LXML:
+ return xml_to_string(
+ element,
+ encoding="unicode",
+ pretty_print=pretty_print,
+ )
+ else:
+ return to_text(
+ xml_to_string(element, encoding),
+ encoding=encoding,
+ )
+
+
+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]
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/utils/__init__.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/utils/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/utils/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/utils/utils.py b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/utils/utils.py
new file mode 100644
index 000000000..1f1250a34
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/module_utils/network/junos/utils/utils.py
@@ -0,0 +1,52 @@
+#
+# -*- 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_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ validate_config,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ tostring,
+)
+
+
+try:
+ from ncclient.xml_ import new_ele, to_ele
+
+ HAS_NCCLIENT = True
+except ImportError:
+ HAS_NCCLIENT = False
+
+try:
+ from ansible.module_utils.common.parameters import _list_no_log_values as list_no_log_values
+except ImportError:
+ # TODO: Remove this import when we no longer support ansible < 2.11
+ from ansible.module_utils.common.parameters import list_no_log_values
+
+
+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))
+
+
+def _validate_config(_module, spec, data, redact=False):
+ validated_data = validate_config(spec, data)
+ if redact:
+ _module.no_log_values.update(list_no_log_values(spec, validated_data))
+ return validated_data
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/__init__.py b/ansible_collections/junipernetworks/junos/plugins/modules/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_acl_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_acl_interfaces.py
new file mode 100644
index 000000000..ccc604a11
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_acl_interfaces.py
@@ -0,0 +1,366 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2020 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_acl_interfaces
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: junos_acl_interfaces
+short_description: ACL interfaces resource module
+description:
+- This module manages adding and removing Access Control Lists (ACLs) from interfaces
+ on devices running Juniper JUNOS.
+version_added: 1.0.0
+author: Daniel Mellado (@dmellado)
+requirements:
+- ncclient (>=v0.6.4)
+- xmltodict (>=0.12.0)
+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 ACL options for interfaces.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Name/Identifier for the interface.
+ type: str
+ access_groups:
+ type: list
+ elements: dict
+ description:
+ - Specifies ACLs attached to the interface.
+ suboptions:
+ afi:
+ description:
+ - Specifies the AFI for the ACL(s) to be configured on this interface.
+ type: str
+ choices: [ipv4, ipv6]
+ acls:
+ type: list
+ description:
+ - Specifies the ACLs for the provided AFI.
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Specifies the name of the IPv4/IPv4 ACL for the interface.
+ type: str
+ direction:
+ description:
+ - Specifies the direction of packets that the ACL will be applied
+ on.
+ type: str
+ choices: [in, out]
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show interfaces).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ default: merged
+"""
+EXAMPLES = """
+# Using deleted
+
+# Before state:
+# -------------
+#
+# admin# show interfaces
+# ge-1/0/0 {
+# description "L3 interface with filter";
+# unit 0 {
+# family inet {
+# filter {
+# input inbound_acl;
+# output outbound_acl;
+# }
+# address 100.64.0.1/10;
+# address 100.64.0.2/10;
+# }
+# family inet6;
+# }
+
+- name: Delete JUNOS L3 interface filter
+ junipernetworks.junos.junos_acl_interfaces:
+ config:
+ - name: ge-1/0/0
+ access_groups:
+ - afi: ipv4
+ acls:
+ - name: inbound_acl
+ direction: in
+ - name: outbound_acl
+ direction: out
+ state: deleted
+
+# After state:
+# -------------
+#
+# admin# show interfaces
+# ge-1/0/0 {
+# description "L3 interface with filter";
+# unit 0 {
+# family inet {
+# address 100.64.0.1/10;
+# address 100.64.0.2/10;
+# }
+# family inet6;
+# }
+
+
+# Using merged
+
+# Before state:
+# -------------
+#
+# admin# show interfaces
+# ge-1/0/0 {
+# description "L3 interface without filter";
+# unit 0 {
+# family inet {
+# address 100.64.0.1/10;
+# address 100.64.0.2/10;
+# }
+# family inet6;
+# }
+
+- name: Merge JUNOS L3 interface filter
+ junipernetworks.junos.junos_acl_interfaces:
+ config:
+ - name: ge-1/0/0
+ access_groups:
+ - afi: ipv4
+ acls:
+ - name: inbound_acl
+ direction: in
+ - name: outbound_acl
+ direction: out
+ state: merged
+
+# After state:
+# -------------
+#
+# admin# show interfaces
+# ge-1/0/0 {
+# description "L3 interface with filter";
+# unit 0 {
+# family inet {
+# filter {
+# input inbound_acl;
+# output outbound_acl;
+# }
+# address 100.64.0.1/10;
+# address 100.64.0.2/10;
+# }
+# family inet6;
+# }
+
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# admin# show interfaces
+# ge-1/0/0 {
+# description "L3 interface without filter";
+# unit 0 {
+# family inet {
+# filter {
+# input foo_acl;
+# }
+# address 100.64.0.1/10;
+# address 100.64.0.2/10;
+# }
+# family inet6;
+# }
+
+- name: Override JUNOS L3 interface filter
+ junipernetworks.junos.junos_acl_interfaces:
+ config:
+ - name: ge-1/0/0
+ access_groups:
+ - afi: ipv4
+ acls:
+ - name: inbound_acl
+ direction: in
+ - name: outbound_acl
+ direction: out
+ state: overridden
+
+# After state:
+# -------------
+#
+# admin# show interfaces
+# ge-1/0/0 {
+# description "L3 interface with filter";
+# unit 0 {
+# family inet {
+# filter {
+# input inbound_acl;
+# output outbound_acl;
+# }
+# address 100.64.0.1/10;
+# address 100.64.0.2/10;
+# }
+# family inet6;
+# }
+
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# admin# show interfaces
+# ge-1/0/0 {
+# description "L3 interface without filter";
+# unit 0 {
+# family inet {
+# filter {
+# input foo_acl;
+# output outbound_acl;
+# }
+# address 100.64.0.1/10;
+# address 100.64.0.2/10;
+# }
+# family inet6;
+# }
+
+- name: Replace JUNOS L3 interface filter
+ junipernetworks.junos.junos_acl_interfaces:
+ config:
+ - name: ge-1/0/0
+ access_groups:
+ - afi: ipv4
+ acls:
+ - name: inbound_acl
+ direction: in
+ state: replaced
+
+# After state:
+# -------------
+#
+# admin# show interfaces
+# ge-1/0/0 {
+# description "L3 interface with filter";
+# unit 0 {
+# family inet {
+# filter {
+# input inbound_acl;
+# output outbound_acl;
+# }
+# address 100.64.0.1/10;
+# address 100.64.0.2/10;
+# }
+# family inet6;
+# }
+
+
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ type: dict
+ 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: 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: ['command 1', 'command 2', 'command 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.acl_interfaces.acl_interfaces import (
+ Acl_interfacesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.acl_interfaces.acl_interfaces import (
+ Acl_interfaces,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ module = AnsibleModule(
+ argument_spec=Acl_interfacesArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+ result = Acl_interfaces(module).execute_module()
+
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_acls.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_acls.py
new file mode 100644
index 000000000..2b1bafc7a
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_acls.py
@@ -0,0 +1,364 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2020 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_acls
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: junos_acls
+short_description: ACLs resource module
+description: This module provides declarative management of acls/filters on Juniper
+ JUNOS devices
+version_added: 1.0.0
+author: Daniel Mellado (@dmellado)
+requirements:
+- ncclient (>=v0.6.4)
+- xmltodict (>=0.12.0)
+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,https://docsansiblecom/ansible/latest/network/user_guide/platform_junoshtml)
+- Tested against JunOS v18.4R1
+options:
+ config:
+ description: A dictionary of acls options
+ type: list
+ elements: dict
+ suboptions:
+ afi:
+ description:
+ - Protocol family to use by the acl filter
+ type: str
+ required: true
+ choices:
+ - ipv4
+ - ipv6
+ acls:
+ description:
+ - List of Access Control Lists (ACLs).
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Name to use for the acl filter
+ type: str
+ required: true
+ aces:
+ description:
+ - List of Access Control Entries (ACEs) for this Access Control List (ACL).
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Filter term name
+ type: str
+ required: true
+ grant:
+ description:
+ - Action to take after matching condition (allow, discard/reject)
+ type: str
+ choices: [permit, deny]
+ source:
+ type: dict
+ description:
+ - Specifies the source for the filter
+ suboptions:
+ address:
+ description:
+ - IP source address to use for the filter
+ type: raw
+ prefix_list:
+ description:
+ - IP source prefix list to use for the filter
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Name of the list
+ type: str
+ port_protocol:
+ description:
+ - Specify the source port or protocol.
+ type: dict
+ suboptions:
+ eq:
+ description:
+ - Match only packets on a given port number.
+ type: str
+ range:
+ description:
+ - Match only packets in the range of port numbers
+ type: dict
+ suboptions:
+ start:
+ description:
+ - Specify the start of the port range
+ type: int
+ end:
+ description:
+ - Specify the end of the port range
+ type: int
+ destination:
+ type: dict
+ description:
+ - Specifies the destination for the filter
+ suboptions:
+ address:
+ description:
+ - Match IP destination address
+ type: raw
+ prefix_list:
+ description:
+ - Match IP destination prefixes in named list
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Name of the list
+ type: str
+ port_protocol:
+ description:
+ - Specify the destination port or protocol.
+ type: dict
+ suboptions:
+ eq:
+ description:
+ - Match only packets on a given port number.
+ type: str
+ range:
+ description:
+ - Match only packets in the range of port numbers
+ type: dict
+ suboptions:
+ start:
+ description:
+ - Specify the start of the port range
+ type: int
+ end:
+ description:
+ - Specify the end of the port range
+ type: int
+ protocol:
+ description:
+ - Specify the protocol to match.
+ - Refer to vendor documentation for valid values.
+ type: str
+ protocol_options:
+ description: All possible suboptions for the protocol chosen.
+ type: dict
+ suboptions:
+ icmp:
+ description: ICMP protocol options.
+ type: dict
+ suboptions:
+ dod_host_prohibited:
+ description: Host prohibited
+ type: bool
+ dod_net_prohibited:
+ description: Net prohibited
+ type: bool
+ echo:
+ description: Echo (ping)
+ type: bool
+ echo_reply:
+ description: Echo reply
+ type: bool
+ host_redirect:
+ description: Host redirect
+ type: bool
+ host_tos_redirect:
+ description: Host redirect for TOS
+ type: bool
+ host_tos_unreachable:
+ description: Host unreachable for TOS
+ type: bool
+ host_unknown:
+ description: Host unknown
+ type: bool
+ host_unreachable:
+ description: Host unreachable
+ type: bool
+ net_redirect:
+ description: Network redirect
+ type: bool
+ net_tos_redirect:
+ description: Net redirect for TOS
+ type: bool
+ network_unknown:
+ description: Network unknown
+ type: bool
+ port_unreachable:
+ description: Port unreachable
+ type: bool
+ protocol_unreachable:
+ description: Protocol unreachable
+ type: bool
+ reassembly_timeout:
+ description: Reassembly timeout
+ type: bool
+ redirect:
+ description: All redirects
+ type: bool
+ router_advertisement:
+ description: Router discovery advertisements
+ type: bool
+ router_solicitation:
+ description: Router discovery solicitations
+ type: bool
+ source_route_failed:
+ description: Source route failed
+ type: bool
+ time_exceeded:
+ description: All time exceeded.
+ type: bool
+ ttl_exceeded:
+ description: TTL exceeded
+ type: bool
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show firewall).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ default: merged
+"""
+EXAMPLES = """
+# Using merged
+
+# Before state:
+# -------------
+#
+# admin# show firewall
+
+- name: Merge JUNOS acl
+ junipernetworks.junos.junos_acls:
+ config:
+ - afi: ipv4
+ acls:
+ - name: allow_ssh_acl
+ aces:
+ - name: ssh_rule
+ source:
+ port_protocol:
+ eq: ssh
+ protocol: tcp
+ state: merged
+
+# After state:
+# -------------
+# admin# show firewall
+# family inet {
+# filter allow_ssh_acl {
+# term ssh_rule {
+# from {
+# protocol tcp;
+# source-port ssh;
+# }
+# }
+# }
+# }
+
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ type: list
+ 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: 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_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.acls.acls import (
+ AclsArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.acls.acls import (
+ Acls,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ module = AnsibleModule(
+ argument_spec=AclsArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+
+ result = Acls(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_banner.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_banner.py
new file mode 100644
index 000000000..d57f8f6aa
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_banner.py
@@ -0,0 +1,194 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_banner
+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.
+version_added: 1.0.0
+extends_documentation_fragment:
+- junipernetworks.junos.junos
+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.
+ type: str
+ 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).
+ type: str
+ state:
+ description:
+ - Specifies whether or not the configuration is present in the current devices
+ active running configuration.
+ type: str
+ 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.
+"""
+
+EXAMPLES = """
+- name: configure the login banner
+ junipernetworks.junos.junos_banner:
+ banner: login
+ text: |
+ this is my login banner
+ that contains a multiline
+ string
+ state: present
+
+- name: remove the motd banner
+ junipernetworks.junos.junos_banner:
+ banner: motd
+ state: absent
+
+- name: deactivate the motd banner
+ junipernetworks.junos.junos_banner:
+ banner: motd
+ state: present
+ active: false
+
+- name: activate the motd banner
+ junipernetworks.junos.junos_banner:
+ banner: motd
+ state: present
+ active: true
+
+- name: Configure banner from file
+ junipernetworks.junos.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_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ map_obj_to_ele,
+ map_params_to_obj,
+ tostring,
+)
+
+
+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"),
+ )
+
+ 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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_bgp_address_family.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_bgp_address_family.py
new file mode 100644
index 000000000..b40e5e816
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_bgp_address_family.py
@@ -0,0 +1,1651 @@
+#!/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_bgp_address_family
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+ANSIBLE_METADATA = {
+ "metadata_version": "1.1",
+ "status": ["preview"],
+ "supported_by": "network",
+}
+
+DOCUMENTATION = """
+---
+module: junos_bgp_address_family
+version_added: 1.3.0
+short_description: Manage BGP Address Family attributes of interfaces on Junos devices.
+description: Manage BGP Address Family attributes of interfaces on Junos network devices.
+author: Rohit Thakur (@rohitthakur2590)
+requirements:
+ - ncclient (>=v0.6.4)
+ - xmltodict (>=0.12.0)
+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:
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show protocols bgp).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ config:
+ description: The provided link BGP address family dictionary.
+ type: dict
+ suboptions:
+ address_family: &address_family
+ description: Enable address family and enter its config mode.
+ type: list
+ elements: dict
+ suboptions:
+ afi:
+ description: address family.
+ type: str
+ choices:
+ - evpn
+ - inet
+ - inet-mdt
+ - inet-mvpn
+ - inet-vpn
+ - inet6
+ - inet6-mvpn
+ - inet6-vpn
+ - iso-vpn
+ - l2vpn
+ - route-target
+ - traffic-engineering
+ af_type:
+ description: Address family type for ipv4.
+ type: list
+ elements: dict
+ suboptions:
+ type:
+ description: Specify type of NLRI.
+ type: str
+ choices:
+ - any
+ - flow
+ - labeled-unicast
+ - multicast
+ - segment-routing-te
+ - unicast
+ - signaling
+ - auto-discovery-mspw
+ - auto-discovery-only
+ set:
+ description: Set NLRI.
+ type: bool
+ accepted_prefix_limit:
+ description: Specify limit for maximum number of prefixes accepted from a peer.
+ type: dict
+ suboptions:
+ maximum:
+ description: Specify maximum number of prefixes accepted from a peer.
+ type: int
+ teardown:
+ description: Clear peer connection on reaching limit.
+ type: bool
+ limit_threshold:
+ description: Specify teardown percentage of prefix-limit to start warnings.
+ type: int
+ idle_timeout:
+ description: Set idle timeout node.
+ type: bool
+ idle_timeout_value:
+ description: Specify timeout before attempting to restart peer.
+ type: int
+ forever:
+ description: Idle the peer until the user intervenes.
+ type: bool
+ add_path:
+ description: Advertise multiple paths to peer.
+ type: dict
+ suboptions:
+ receive:
+ description: Receive multiple paths from peer.
+ type: bool
+ send:
+ description: Send multiple paths to peer.
+ type: dict
+ suboptions:
+ include_backup_path:
+ description: Specify number of backup paths to advertise.
+ type: int
+ multipath:
+ description: Include only multipath contributor routes.
+ type: bool
+ path_count:
+ description: Include only multipath contributor routes.
+ type: int
+ required: true
+ path_selection_mode:
+ description: Configure how to select add-path routes.
+ type: dict
+ suboptions:
+ all_paths:
+ description: Advertise all paths allowed by path count.
+ type: bool
+ equal_cost_paths:
+ description: Advertise equal cost paths.
+ type: bool
+ prefix_policy:
+ description: Perform add-path only for prefixes that match policy.
+ type: str
+ aggregate_label:
+ description: Aggregate labels of incoming routes with the same FEC.
+ type: dict
+ suboptions:
+ set:
+ description: Set Aggregate labels of incoming routes with the same FEC
+ type: bool
+ community:
+ description: Community to identify the FEC of incoming routesC.
+ type: str
+ aigp:
+ description: Allow sending and receiving of AIGP attribute.
+ type: dict
+ suboptions:
+ set:
+ description: Set AIGP.
+ type: bool
+ disable:
+ description: Dn not allow sending and receiving of AIGP attribute.
+ type: bool
+ damping:
+ description: Enable route flap damping.
+ type: bool
+ defer_initial_multipath_build:
+ description: Defer initial multipath build until EOR is received.
+ type: dict
+ suboptions:
+ set:
+ description: Set defer initial multipath build.
+ type: bool
+ maximum_delay:
+ description: Max delay(sec) multipath build after peer is up.
+ type: int
+ delay_route_advertisements:
+ description: Delay route updates for this family until FIB-sync.
+ type: dict
+ suboptions:
+ set:
+ description: Set delay route advertisements.
+ type: bool
+ max_delay_route_age:
+ description: Set max delay advertisement route age.
+ type: int
+ max_delay_routing_uptime:
+ description: Set max delay advertisement route age.
+ type: int
+ min_delay_inbound_convergence:
+ description: Set min delayadvertisement after source-peer sent all routes.
+ type: int
+ min_delay_routing_uptime:
+ description: Set min delay advertisement route age.
+ type: int
+ entropy_label:
+ description: Use entropy label for entropy label capable BGP LSPs.
+ type: dict
+ suboptions:
+ set:
+ description: Set entropy-label attribute.
+ type: bool
+ import:
+ description: Policy to select BGP LSPs to use entropy label.
+ type: str
+ no_next_hop_validation:
+ description: Don't validate next hop field against route next hop.
+ type: bool
+ explicit_null:
+ description: Advertise explicit null.
+ type: dict
+ suboptions:
+ set:
+ description: Set explicit-null attribute.
+ type: bool
+ connected_only:
+ description: Advertise explicit null only for connected routes.
+ type: bool
+ extended_nexthop:
+ description: Enable extended nexthop encoding.
+ type: bool
+ extended_nexthop_color:
+ description: Resolve using extended color nexthop.
+ type: bool
+ graceful_restart_forwarding_state_bit:
+ description: Specify BGP graceful restart options.
+ type: str
+ choices: ['from-fib', 'set']
+ local_ipv4_address:
+ description: Specify local IPv4 address.
+ type: str
+ legacy_redirect_ip_action:
+ description: Configure legacy redirect to IP support.
+ type: dict
+ suboptions:
+ set:
+ description: Set the legacy-redirect-ip-action.
+ type: bool
+ send:
+ description: Advertise Redirect action as legacy redirect attribute.
+ type: bool
+ receive:
+ description: Accept legacy encoded redirect-to-ip action attribute
+ type: bool
+ loops:
+ description: Allow local AS in received AS paths.
+ type: int
+ no_install:
+ description: Dont install received routes in forwarding.
+ type: bool
+ no_validate:
+ description: Bypass validation procedure for routes that match policy.
+ type: str
+ output_queue_priority_expedited:
+ description: Expedited queue; highest priority.
+ type: bool
+ output_queue_priority_priority:
+ description: Output queue priority; higher is better.
+ type: int
+ per_group_label:
+ description: Advertise prefixes with unique labels per group.
+ type: bool
+ per_prefix_label:
+ description: Allocate a unique label to each advertised prefix.
+ type: bool
+ prefix_limit:
+ description: Limit maximum number of prefixes from a peer.
+ type: dict
+ suboptions:
+ maximum:
+ description: Specify maximum number of prefixes from a peer.
+ type: int
+ teardown:
+ description: Clear peer connection on reaching limit.
+ type: bool
+ limit_threshold:
+ description: Percentage of prefix-limit to start warnings.
+ type: int
+ idle_timeout:
+ description: Set idle timeout node.
+ type: bool
+ idle_timeout_value:
+ description: Specify timeout before attempting to restart peer.
+ type: int
+ forever:
+ description: Idle the peer until the user intervenes.
+ type: bool
+ resolve_vpn:
+ description: Install received NLRI in inet.3 also.
+ type: bool
+ rib:
+ description: Select table used by labeled unicast routes.
+ type: str
+ choices: ['inet.3']
+ ribgroup_name:
+ description: Name of the routing table group.
+ type: str
+ route_refresh_priority_expedited:
+ description: Expedited queue; highest priority.
+ type: bool
+ route_refresh_priority_priority:
+ description: Output queue priority; higher is better.
+ type: int
+ secondary_independent_resolution:
+ description: Resolve FLOW routes in VRF table independent of VPN FLOW route.
+ type: bool
+ topology:
+ description: Multi topology routing tables.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify topology name.
+ type: str
+ community:
+ description: Community to identify multi topology routes.
+ type: list
+ elements: str
+ withdraw_priority_expedited:
+ description: Expedited queue; highest priority.
+ type: bool
+ withdraw_priority_priority:
+ description: Output queue priority; higher is better.
+ type: int
+ strip_nexthop:
+ description: Strip the next-hop from the outgoing flow update.
+ type: bool
+ traffic_statistics:
+ description: Collect statistics for BGP label-switched paths
+ type: dict
+ suboptions:
+ set:
+ description: Set traffic-statistics.
+ type: bool
+ interval:
+ description: Time to collect statistics (seconds).
+ type: int
+ labeled_path:
+ description: Enable ingress labeled path statistics.
+ type: bool
+ file:
+ description: Statistics file options.
+ type: dict
+ suboptions:
+ filename:
+ description: Name of file in which to write trace information.
+ type: str
+ files:
+ description: Maximum number of trace files.
+ type: int
+ no_world_readable:
+ description: Don't allow any user to read the log file.
+ type: bool
+ size:
+ description: Maximum trace file size.
+ type: int
+ world_readable:
+ description: Don't allow any user to read the log file.
+ type: bool
+ groups:
+ description: Specify address family config for groups.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify name of the group
+ type: str
+ address_family: *address_family
+ neighbors:
+ description: Specify address family config per neighbor.
+ type: list
+ elements: dict
+ suboptions:
+ neighbor_address:
+ description: Specify neighbor address.
+ type: str
+ address_family: *address_family
+ state:
+ description:
+ - The state the configuration should be left in.
+ - State I(deleted) only removes BGP address family attributes that this modules
+ manages and does not negate the BGP neighbor address family completely. Thereby, preserving
+ address-family related configurations under BGP group neighbor context.
+ - To delete the address family associated to neighbor use M(junipernetworks.junos.junos_bgp_neighbor_address_family)
+ modules for prior cleanup.
+ - Refer to examples for more details.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - parsed
+ - gathered
+ - rendered
+ default: merged
+"""
+EXAMPLES = """
+# Using merged
+#
+# Before state
+# ------------
+#
+# admin# show protocols bgp
+#
+# [edit]
+
+- name: Merge Junos BGP address family configuration
+ junipernetworks.junos.junos_bgp_address_family:
+ config:
+ address_family:
+ - afi: 'evpn'
+ af_type:
+ - type: 'signaling'
+ accepted_prefix_limit:
+ maximum: 20
+ limit_threshold: 98
+ idle_timeout_value: 2001
+ damping: true
+ defer_initial_multipath_build:
+ maximum_delay: 2
+ - afi: 'inet'
+ af_type:
+ - type: 'flow'
+ legacy_redirect_ip_action:
+ send: true
+ receive: true
+ loops: 4
+ no_install: true
+ output_queue_priority_expedited: true
+ secondary_independent_resolution: true
+
+ - type: 'unicast'
+ extended_nexthop: true
+ extended_nexthop_color: true
+ local_ipv4_address: '9.9.9.9'
+
+ - type: 'labeled-unicast'
+ entropy_label:
+ no_next_hop_validation: true
+ explicit_null:
+ connected_only: true
+ per_prefix_label: true
+ per_group_label: true
+ prefix_limit:
+ maximum: 20
+ limit_threshold: 99
+ forever: true
+ resolve_vpn: true
+ rib: 'inet.3'
+ route_refresh_priority_expedited: true
+ route_refresh_priority_priority: 3
+
+ - type: 'any'
+ accepted_prefix_limit:
+ maximum: 20
+ limit_threshold: 99
+ idle_timeout_value: 2000
+ damping: true
+ defer_initial_multipath_build:
+ maximum_delay: 2
+ delay_route_advertisements:
+ max_delay_route_age: 20
+ max_delay_routing_uptime: 32000
+ min_delay_inbound_convergence: 32000
+ min_delay_routing_uptime: 23000
+ graceful_restart_forwarding_state_bit: 'from-fib'
+ state: merged
+
+# After state
+# -----------
+#
+# admin# show protocols bgp
+# family inet {
+# unicast {
+# local-ipv4-address 9.9.9.9;
+# extended-nexthop;
+# extended-nexthop-color;
+# }
+# flow {
+# loops 4;
+# no-install;
+# output-queue-priority expedited;
+# legacy-redirect-ip-action {
+# receive;
+# send;
+# }
+# secondary-independent-resolution;
+# }
+# any {
+# accepted-prefix-limit {
+# maximum 20;
+# teardown 99 idle-timeout 2000;
+# }
+# damping;
+# delay-route-advertisements {
+# minimum-delay {
+# routing-uptime 23000;
+# inbound-convergence 32000;
+# }
+# maximum-delay {
+# route-age 20;
+# routing-uptime 32000;
+# }
+# }
+# defer-initial-multipath-build {
+# maximum-delay 2;
+# }
+# graceful-restart {
+# forwarding-state-bit from-fib;
+# }
+# }
+# labeled-unicast {
+# prefix-limit {
+# maximum 20;
+# teardown 99 idle-timeout forever;
+# }
+# route-refresh-priority priority 3;
+# per-prefix-label;
+# per-group-label;
+# rib {
+# inet.3;
+# }
+# explicit-null connected-only;
+# resolve-vpn;
+# entropy-label {
+# no-next-hop-validation;
+# }
+# }
+# }
+# family evpn {
+# signaling {
+# accepted-prefix-limit {
+# maximum 20;
+# teardown 98 idle-timeout 2001;
+# }
+# damping;
+# defer-initial-multipath-build {
+# maximum-delay 2;
+# }
+# }
+# }
+# Using replaced
+#
+# Before state
+# ------------
+#
+# admin# show protocols bgp
+# preference 2;
+# hold-time 5;
+# advertise-inactive;
+# out-delay 10;
+# bgp-error-tolerance {
+# malformed-route-limit 40000000;
+# }
+# authentication-algorithm md5;
+# advertise-bgp-static {
+# policy static-to-bgp;
+# }
+# family inet {
+# unicast {
+# local-ipv4-address 9.9.9.9;
+# extended-nexthop;
+# extended-nexthop-color;
+# }
+# flow {
+# loops 4;
+# no-install;
+# output-queue-priority expedited;
+# legacy-redirect-ip-action {
+# receive;
+# send;
+# }
+# secondary-independent-resolution;
+# }
+# any {
+# accepted-prefix-limit {
+# maximum 20;
+# teardown 99 idle-timeout 2000;
+# }
+# damping;
+# delay-route-advertisements {
+# minimum-delay {
+# routing-uptime 23000;
+# inbound-convergence 32000;
+# }
+# maximum-delay {
+# route-age 20;
+# routing-uptime 32000;
+# }
+# }
+# defer-initial-multipath-build {
+# maximum-delay 2;
+# }
+# graceful-restart {
+# forwarding-state-bit from-fib;
+# }
+# }
+# labeled-unicast {
+# prefix-limit {
+# maximum 20;
+# teardown 99 idle-timeout forever;
+# }
+# route-refresh-priority priority 3;
+# per-prefix-label;
+# per-group-label;
+# rib {
+# inet.3;
+# }
+# explicit-null connected-only;
+# resolve-vpn;
+# entropy-label {
+# no-next-hop-validation;
+# }
+# }
+# }
+# family evpn {
+# signaling {
+# accepted-prefix-limit {
+# maximum 20;
+# teardown 98 idle-timeout 2001;
+# }
+# damping;
+# defer-initial-multipath-build {
+# maximum-delay 2;
+# }
+# }
+# }
+
+- name: Replace existing Junos BGP address family config with provided config
+ junipernetworks.junos.junos_bgp_address_family:
+ config:
+ address_family:
+ - afi: 'evpn'
+ af_type:
+ - type: 'signaling'
+ accepted_prefix_limit:
+ maximum: 21
+ limit_threshold: 99
+ idle_timeout_value: 2002
+ delay_route_advertisements:
+ max_delay_route_age: 20
+ max_delay_routing_uptime: 32000
+ min_delay_inbound_convergence: 32000
+ min_delay_routing_uptime: 23000
+ damping: true
+ state: replaced
+
+# After state
+# -----------
+#
+# admin# show protocols bgp
+# preference 2;
+# hold-time 5;
+# advertise-inactive;
+# out-delay 10;
+# bgp-error-tolerance {
+# malformed-route-limit 40000000;
+# }
+# authentication-algorithm md5;
+# advertise-bgp-static {
+# policy static-to-bgp;
+# }
+# family inet {
+# unicast {
+# local-ipv4-address 9.9.9.9;
+# extended-nexthop;
+# extended-nexthop-color;
+# }
+# flow {
+# loops 4;
+# no-install;
+# output-queue-priority expedited;
+# legacy-redirect-ip-action {
+# receive;
+# send;
+# }
+# secondary-independent-resolution;
+# }
+# any {
+# accepted-prefix-limit {
+# maximum 20;
+# teardown 99 idle-timeout 2000;
+# }
+# damping;
+# delay-route-advertisements {
+# minimum-delay {
+# routing-uptime 23000;
+# inbound-convergence 32000;
+# }
+# maximum-delay {
+# route-age 20;
+# routing-uptime 32000;
+# }
+# }
+# defer-initial-multipath-build {
+# maximum-delay 2;
+# }
+# graceful-restart {
+# forwarding-state-bit from-fib;
+# }
+# }
+# labeled-unicast {
+# prefix-limit {
+# maximum 20;
+# teardown 99 idle-timeout forever;
+# }
+# route-refresh-priority priority 3;
+# per-prefix-label;
+# per-group-label;
+# rib {
+# inet.3;
+# }
+# explicit-null connected-only;
+# resolve-vpn;
+# entropy-label {
+# no-next-hop-validation;
+# }
+# }
+# }
+# family evpn {
+# signaling {
+# accepted-prefix-limit {
+# maximum 21;
+# teardown 99 idle-timeout 2002;
+# }
+# damping;
+# delay-route-advertisements {
+# minimum-delay {
+# routing-uptime 23000;
+# inbound-convergence 32000;
+# }
+# maximum-delay {
+# route-age 20;
+# routing-uptime 32000;
+# }
+# }
+# }
+# }
+# Using overridden
+#
+# Before state
+# ------------
+#
+# admin# show protocols bgp
+# family inet {
+# unicast {
+# local-ipv4-address 9.9.9.9;
+# extended-nexthop;
+# extended-nexthop-color;
+# }
+# flow {
+# loops 4;
+# no-install;
+# output-queue-priority expedited;
+# legacy-redirect-ip-action {
+# receive;
+# send;
+# }
+# secondary-independent-resolution;
+# }
+# any {
+# accepted-prefix-limit {
+# maximum 20;
+# teardown 99 idle-timeout 2000;
+# }
+# damping;
+# delay-route-advertisements {
+# minimum-delay {
+# routing-uptime 23000;
+# inbound-convergence 32000;
+# }
+# maximum-delay {
+# route-age 20;
+# routing-uptime 32000;
+# }
+# }
+# defer-initial-multipath-build {
+# maximum-delay 2;
+# }
+# graceful-restart {
+# forwarding-state-bit from-fib;
+# }
+# }
+# labeled-unicast {
+# prefix-limit {
+# maximum 20;
+# teardown 99 idle-timeout forever;
+# }
+# route-refresh-priority priority 3;
+# per-prefix-label;
+# per-group-label;
+# rib {
+# inet.3;
+# }
+# explicit-null connected-only;
+# resolve-vpn;
+# entropy-label {
+# no-next-hop-validation;
+# }
+# }
+# }
+# family evpn {
+# signaling {
+# accepted-prefix-limit {
+# maximum 20;
+# teardown 98 idle-timeout 2001;
+# }
+# damping;
+# defer-initial-multipath-build {
+# maximum-delay 2;
+# }
+# }
+# }
+
+- name: Override Junos BGP address family config
+ junipernetworks.junos.junos_bgp_address_family:
+ config:
+ address_family:
+ - afi: 'evpn'
+ af_type:
+ - type: 'signaling'
+ accepted_prefix_limit:
+ maximum: 21
+ limit_threshold: 99
+ idle_timeout_value: 2002
+ delay_route_advertisements:
+ max_delay_route_age: 20
+ max_delay_routing_uptime: 32000
+ min_delay_inbound_convergence: 32000
+ min_delay_routing_uptime: 23000
+ damping: true
+ state: overridden
+
+# After state
+# -----------
+#
+# admin# show protocols bgp
+# family evpn {
+# signaling {
+# accepted-prefix-limit {
+# maximum 21;
+# teardown 99 idle-timeout 2002;
+# }
+# damping;
+# delay-route-advertisements {
+# minimum-delay {
+# routing-uptime 23000;
+# inbound-convergence 32000;
+# }
+# maximum-delay {
+# route-age 20;
+# routing-uptime 32000;
+# }
+# }
+# }
+# }
+
+# Using deleted
+#
+# Before state
+# ------------
+#
+# admin# show protocols bgp
+# preference 2;
+# hold-time 5;
+# advertise-inactive;
+# out-delay 10;
+# family inet {
+# unicast {
+# local-ipv4-address 9.9.9.9;
+# extended-nexthop;
+# extended-nexthop-color;
+# }
+# flow {
+# loops 4;
+# no-install;
+# output-queue-priority expedited;
+# legacy-redirect-ip-action {
+# receive;
+# send;
+# }
+# secondary-independent-resolution;
+# }
+# any {
+# accepted-prefix-limit {
+# maximum 20;
+# teardown 99 idle-timeout 2000;
+# }
+# damping;
+# delay-route-advertisements {
+# minimum-delay {
+# routing-uptime 23000;
+# inbound-convergence 32000;
+# }
+# maximum-delay {
+# route-age 20;
+# routing-uptime 32000;
+# }
+# }
+# defer-initial-multipath-build {
+# maximum-delay 2;
+# }
+# graceful-restart {
+# forwarding-state-bit from-fib;
+# }
+# }
+# labeled-unicast {
+# prefix-limit {
+# maximum 20;
+# teardown 99 idle-timeout forever;
+# }
+# route-refresh-priority priority 3;
+# per-prefix-label;
+# per-group-label;
+# rib {
+# inet.3;
+# }
+# explicit-null connected-only;
+# resolve-vpn;
+# entropy-label {
+# no-next-hop-validation;
+# }
+# }
+# }
+# family evpn {
+# signaling {
+# accepted-prefix-limit {
+# maximum 20;
+# teardown 98 idle-timeout 2001;
+# }
+# damping;
+# defer-initial-multipath-build {
+# maximum-delay 2;
+# }
+# }
+# }
+
+- name: Delete Junos BGP address family config based on the afi
+ junipernetworks.junos.junos_bgp_address_family:
+ config:
+ address_family:
+ - afi: 'inet'
+ state: deleted
+
+# After state
+# -----------
+#
+# admin# show protocols bgp
+# preference 2;
+# hold-time 5;
+# advertise-inactive;
+# out-delay 10;
+# family evpn {
+# signaling {
+# accepted-prefix-limit {
+# maximum 20;
+# teardown 98 idle-timeout 2001;
+# }
+# damping;
+# defer-initial-multipath-build {
+# maximum-delay 2;
+# }
+# }
+# }
+
+# Using deleted
+#
+# Before state
+# ------------
+#
+# admin# show protocols bgp
+# preference 2;
+# hold-time 5;
+# advertise-inactive;
+# out-delay 10;
+# family inet {
+# unicast {
+# local-ipv4-address 9.9.9.9;
+# extended-nexthop;
+# extended-nexthop-color;
+# }
+# flow {
+# loops 4;
+# no-install;
+# output-queue-priority expedited;
+# legacy-redirect-ip-action {
+# receive;
+# send;
+# }
+# secondary-independent-resolution;
+# }
+# any {
+# accepted-prefix-limit {
+# maximum 20;
+# teardown 99 idle-timeout 2000;
+# }
+# damping;
+# delay-route-advertisements {
+# minimum-delay {
+# routing-uptime 23000;
+# inbound-convergence 32000;
+# }
+# maximum-delay {
+# route-age 20;
+# routing-uptime 32000;
+# }
+# }
+# defer-initial-multipath-build {
+# maximum-delay 2;
+# }
+# graceful-restart {
+# forwarding-state-bit from-fib;
+# }
+# }
+# labeled-unicast {
+# prefix-limit {
+# maximum 20;
+# teardown 99 idle-timeout forever;
+# }
+# route-refresh-priority priority 3;
+# per-prefix-label;
+# per-group-label;
+# rib {
+# inet.3;
+# }
+# explicit-null connected-only;
+# resolve-vpn;
+# entropy-label {
+# no-next-hop-validation;
+# }
+# }
+# }
+# family evpn {
+# signaling {
+# accepted-prefix-limit {
+# maximum 20;
+# teardown 98 idle-timeout 2001;
+# }
+# damping;
+# defer-initial-multipath-build {
+# maximum-delay 2;
+# }
+# }
+# }
+
+- name: Delete complete Junos BGP address family config
+ junipernetworks.junos.junos_bgp_address_family:
+ config:
+ state: deleted
+
+# After state
+# -----------
+#
+# admin# show protocols bgp
+# preference 2;
+# hold-time 5;
+# advertise-inactive;
+# out-delay 10;
+
+
+# Using gathered
+#
+# Before state
+# ------------
+#
+# admin# show protocols bgp
+# preference 2;
+# hold-time 5;
+# advertise-inactive;
+# out-delay 10;
+# family inet {
+# unicast {
+# local-ipv4-address 9.9.9.9;
+# extended-nexthop;
+# extended-nexthop-color;
+# }
+# flow {
+# loops 4;
+# no-install;
+# output-queue-priority expedited;
+# legacy-redirect-ip-action {
+# receive;
+# send;
+# }
+# secondary-independent-resolution;
+# }
+# any {
+# accepted-prefix-limit {
+# maximum 20;
+# teardown 99 idle-timeout 2000;
+# }
+# damping;
+# delay-route-advertisements {
+# minimum-delay {
+# routing-uptime 23000;
+# inbound-convergence 32000;
+# }
+# maximum-delay {
+# route-age 20;
+# routing-uptime 32000;
+# }
+# }
+# defer-initial-multipath-build {
+# maximum-delay 2;
+# }
+# graceful-restart {
+# forwarding-state-bit from-fib;
+# }
+# }
+# labeled-unicast {
+# prefix-limit {
+# maximum 20;
+# teardown 99 idle-timeout forever;
+# }
+# route-refresh-priority priority 3;
+# per-prefix-label;
+# per-group-label;
+# rib {
+# inet.3;
+# }
+# explicit-null connected-only;
+# resolve-vpn;
+# entropy-label {
+# no-next-hop-validation;
+# }
+# }
+# }
+# family evpn {
+# signaling {
+# accepted-prefix-limit {
+# maximum 20;
+# teardown 98 idle-timeout 2001;
+# }
+# damping;
+# defer-initial-multipath-build {
+# maximum-delay 2;
+# }
+# }
+# }
+
+- name: Gather Junos BGP address family config
+ junipernetworks.junos.junos_bgp_address_family:
+ config:
+ state: gathered
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+# "gathered": {
+# "address_family": [
+# {
+# "af_type": [
+# {
+# "accepted_prefix_limit": {
+# "idle_timeout_value": 2001,
+# "limit_threshold": 98,
+# "maximum": 20
+# },
+# "damping": true,
+# "defer_initial_multipath_build": {
+# "maximum_delay": 2
+# },
+# "type": "signaling"
+# }
+# ],
+# "afi": "evpn"
+# },
+# {
+# "af_type": [
+# {
+# "accepted_prefix_limit": {
+# "idle_timeout_value": 2000,
+# "limit_threshold": 99,
+# "maximum": 20
+# },
+# "damping": true,
+# "defer_initial_multipath_build": {
+# "maximum_delay": 2
+# },
+# "delay_route_advertisements": {
+# "max_delay_route_age": 20,
+# "max_delay_routing_uptime": 32000,
+# "min_delay_inbound_convergence": 32000,
+# "min_delay_routing_uptime": 23000
+# },
+# "graceful_restart_forwarding_state_bit": "from-fib",
+# "type": "any"
+# },
+# {
+# "legacy_redirect_ip_action": {
+# "receive": true,
+# "send": true
+# },
+# "loops": 4,
+# "no_install": true,
+# "output_queue_priority_expedited": true,
+# "secondary_independent_resolution": true,
+# "type": "flow"
+# },
+# {
+# "entropy_label": {
+# "no_next_hop_validation": true
+# },
+# "explicit_null": {
+# "connected_only": true
+# },
+# "per_group_label": true,
+# "per_prefix_label": true,
+# "prefix_limit": {
+# "forever": true,
+# "limit_threshold": 99,
+# "maximum": 20
+# },
+# "resolve_vpn": true,
+# "rib": "inet.3",
+# "route_refresh_priority_priority": 3,
+# "type": "labeled-unicast"
+# },
+# {
+# "extended_nexthop": true,
+# "extended_nexthop_color": true,
+# "local_ipv4_address": "9.9.9.9",
+# "type": "unicast"
+# }
+# ],
+# "afi": "inet"
+# }
+# ]
+# }
+#
+# Using parsed
+# parsed.cfg
+# ------------
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <version>18.4R1-S2.4</version>
+# <protocols>
+# <bgp>
+# <preference>2</preference>
+# <hold-time>5</hold-time>
+# <advertise-inactive/>
+# <out-delay>10</out-delay>
+# <family>
+# <inet>
+# <unicast>
+# <local-ipv4-address>9.9.9.9</local-ipv4-address>
+# <extended-nexthop/>
+# <extended-nexthop-color/>
+# </unicast>
+# <flow>
+# <loops>
+# <loops>4</loops>
+# </loops>
+# <no-install/>
+# <output-queue-priority>
+# <expedited/>
+# </output-queue-priority>
+# <legacy-redirect-ip-action>
+# <receive/>
+# <send/>
+# </legacy-redirect-ip-action>
+# <secondary-independent-resolution/>
+# </flow>
+# <any>
+# <accepted-prefix-limit>
+# <maximum>20</maximum>
+# <teardown>
+# <limit-threshold>99</limit-threshold>
+# <idle-timeout>
+# <timeout>2000</timeout>
+# </idle-timeout>
+# </teardown>
+# </accepted-prefix-limit>
+# <damping/>
+# <delay-route-advertisements>
+# <minimum-delay>
+# <routing-uptime>23000</routing-uptime>
+# <inbound-convergence>32000</inbound-convergence>
+# </minimum-delay>
+# <maximum-delay>
+# <route-age>20</route-age>
+# <routing-uptime>32000</routing-uptime>
+# </maximum-delay>
+# </delay-route-advertisements>
+# <defer-initial-multipath-build>
+# <maximum-delay>2</maximum-delay>
+# </defer-initial-multipath-build>
+# <graceful-restart>
+# <forwarding-state-bit>from-fib</forwarding-state-bit>
+# </graceful-restart>
+# </any>
+# <labeled-unicast>
+# <prefix-limit>
+# <maximum>20</maximum>
+# <teardown>
+# <limit-threshold>99</limit-threshold>
+# <idle-timeout>
+# <forever/>
+# </idle-timeout>
+# </teardown>
+# </prefix-limit>
+# <route-refresh-priority>
+# <priority>3</priority>
+# </route-refresh-priority>
+# <per-prefix-label/>
+# <per-group-label/>
+# <rib>
+# <inet.3/>
+# </rib>
+# <explicit-null>
+# <connected-only/>
+# </explicit-null>
+# <resolve-vpn/>
+# <entropy-label>
+# <no-next-hop-validation/>
+# </entropy-label>
+# </labeled-unicast>
+# </inet>
+# <evpn>
+# <signaling>
+# <accepted-prefix-limit>
+# <maximum>20</maximum>
+# <teardown>
+# <limit-threshold>98</limit-threshold>
+# <idle-timeout>
+# <timeout>2001</timeout>
+# </idle-timeout>
+# </teardown>
+# </accepted-prefix-limit>
+# <damping/>
+# <defer-initial-multipath-build>
+# <maximum-delay>2</maximum-delay>
+# </defer-initial-multipath-build>
+# </signaling>
+# </evpn>
+# </family>
+# </bgp>
+# <ospf3>
+# <area>
+# <name>0.0.0.100</name>
+# <stub>
+# <default-metric>200</default-metric>
+# </stub>
+# <interface>
+# <name>so-0/0/0.0</name>
+# <metric>5</metric>
+# <priority>3</priority>
+# </interface>
+# </area>
+# </ospf3>
+# </protocols>
+# <routing-options>
+# <static>
+# <route>
+# <name>172.16.17.0/24</name>
+# <discard />
+# </route>
+# </static>
+# <router-id>10.200.16.75</router-id>
+# <autonomous-system>
+# <as-number>65432</as-number>
+# </autonomous-system>
+# </routing-options>
+# </configuration>
+# </rpc-reply>
+
+
+- name: Parsed the bgp address family running config to get the facts
+ junipernetworks.junos.junos_bgp_address_family:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "parsed": {
+# "address_family": [
+# {
+# "af_type": [
+# {
+# "accepted_prefix_limit": {
+# "idle_timeout_value": 2001,
+# "limit_threshold": 98,
+# "maximum": 20
+# },
+# "damping": true,
+# "defer_initial_multipath_build": {
+# "maximum_delay": 2
+# },
+# "type": "signaling"
+# }
+# ],
+# "afi": "evpn"
+# },
+# {
+# "af_type": [
+# {
+# "accepted_prefix_limit": {
+# "idle_timeout_value": 2000,
+# "limit_threshold": 99,
+# "maximum": 20
+# },
+# "damping": true,
+# "defer_initial_multipath_build": {
+# "maximum_delay": 2
+# },
+# "delay_route_advertisements": {
+# "max_delay_route_age": 20,
+# "max_delay_routing_uptime": 32000,
+# "min_delay_inbound_convergence": 32000,
+# "min_delay_routing_uptime": 23000
+# },
+# "graceful_restart_forwarding_state_bit": "from-fib",
+# "type": "any"
+# },
+# {
+# "legacy_redirect_ip_action": {
+# "receive": true,
+# "send": true
+# },
+# "loops": 4,
+# "no_install": true,
+# "output_queue_priority_expedited": true,
+# "secondary_independent_resolution": true,
+# "type": "flow"
+# },
+# {
+# "entropy_label": {
+# "no_next_hop_validation": true
+# },
+# "explicit_null": {
+# "connected_only": true
+# },
+# "per_group_label": true,
+# "per_prefix_label": true,
+# "prefix_limit": {
+# "forever": true,
+# "limit_threshold": 99,
+# "maximum": 20
+# },
+# "resolve_vpn": true,
+# "rib": "inet.3",
+# "route_refresh_priority_priority": 3,
+# "type": "labeled-unicast"
+# },
+# {
+# "extended_nexthop": true,
+# "extended_nexthop_color": true,
+# "local_ipv4_address": "9.9.9.9",
+# "type": "unicast"
+# }
+# ],
+# "afi": "inet"
+# }
+# ]
+# }
+# Using rendered
+#
+#
+- name: Render the commands for provided configuration
+ junipernetworks.junos.junos_bgp_address_family:
+ config:
+ address_family:
+ - afi: 'evpn'
+ af_type:
+ - type: 'signaling'
+ accepted_prefix_limit:
+ maximum: 20
+ limit_threshold: 98
+ idle_timeout_value: 2001
+ damping: true
+ defer_initial_multipath_build:
+ maximum_delay: 2
+ - afi: 'inet'
+ af_type:
+ - type: 'flow'
+ legacy_redirect_ip_action:
+ send: true
+ receive: true
+ loops: 4
+ no_install: true
+ output_queue_priority_expedited: true
+ secondary_independent_resolution: true
+
+ - type: 'unicast'
+ extended_nexthop: true
+ extended_nexthop_color: true
+ local_ipv4_address: '9.9.9.9'
+
+ - type: 'labeled-unicast'
+ entropy_label:
+ no_next_hop_validation: true
+ explicit_null:
+ connected_only: true
+ per_prefix_label: true
+ per_group_label: true
+ prefix_limit:
+ maximum: 20
+ limit_threshold: 99
+ forever: true
+ resolve_vpn: true
+ rib: 'inet.3'
+ route_refresh_priority_expedited: true
+ route_refresh_priority_priority: 3
+
+ - type: 'any'
+ accepted_prefix_limit:
+ maximum: 20
+ limit_threshold: 99
+ idle_timeout_value: 2000
+ damping: true
+ defer_initial_multipath_build:
+ maximum_delay: 2
+ delay_route_advertisements:
+ max_delay_route_age: 20
+ max_delay_routing_uptime: 32000
+ min_delay_inbound_convergence: 32000
+ min_delay_routing_uptime: 23000
+ graceful_restart_forwarding_state_bit: 'from-fib'
+ state: rendered
+
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "rendered": "<nc:protocols xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# <nc:bgp><nc:family><nc:evpn><nc:signaling><nc:accepted-prefix-limit><nc:maximum>20</nc:maximum>
+# <nc:teardown><nc:limit-threshold>98</nc:limit-threshold><nc:idle-timeout><nc:timeout>2001</nc:timeout>
+# </nc:idle-timeout></nc:teardown></nc:accepted-prefix-limit><nc:damping/><nc:defer-initial-multipath-build>
+# <nc:maximum-delay>2</nc:maximum-delay></nc:defer-initial-multipath-build></nc:signaling>
+# </nc:evpn><nc:inet><nc:flow><nc:legacy-redirect-ip-action><nc:send/><nc:receive/>
+# </nc:legacy-redirect-ip-action><nc:loops>4</nc:loops><nc:no-install/>
+# <nc:output-queue-priority><nc:expedited/></nc:output-queue-priority>
+# <nc:secondary-independent-resolution/></nc:flow><nc:unicast><nc:extended-nexthop/>
+# <nc:extended-nexthop-color/><nc:local-ipv4-address>9.9.9.9</nc:local-ipv4-address>
+# </nc:unicast><nc:labeled-unicast><nc:entropy-label><nc:no-next-hop-validation/>
+# </nc:entropy-label><nc:explicit-null><nc:connected-only/></nc:explicit-null>
+# <nc:per-prefix-label/><nc:per-group-label/><nc:prefix-limit><nc:maximum>20</nc:maximum>
+# <nc:teardown>99<nc:idle-timeout><nc:forever/></nc:idle-timeout></nc:teardown>
+# </nc:prefix-limit><nc:resolve-vpn/><nc:rib><nc:inet.3/></nc:rib><nc:route-refresh-priority>
+# <nc:expedited/><nc:priority>3</nc:priority></nc:route-refresh-priority></nc:labeled-unicast>
+# <nc:any><nc:accepted-prefix-limit><nc:maximum>20</nc:maximum><nc:teardown>
+# <nc:limit-threshold>99</nc:limit-threshold><nc:idle-timeout><nc:timeout>2000</nc:timeout>
+# </nc:idle-timeout></nc:teardown></nc:accepted-prefix-limit><nc:damping/>
+# <nc:defer-initial-multipath-build><nc:maximum-delay>2</nc:maximum-delay>
+# </nc:defer-initial-multipath-build><nc:delay-route-advertisements>
+# <nc:maximum-delay><nc:route-age>20</nc:route-age><nc:routing-uptime>32000</nc:routing-uptime>
+# </nc:maximum-delay><nc:minimum-delay><nc:inbound-convergence>32000</nc:inbound-convergence>
+# <nc:routing-uptime>23000</nc:routing-uptime></nc:minimum-delay></nc:delay-route-advertisements>
+# <nc:graceful-restart><nc:forwarding-state-bit>from-fib</nc:forwarding-state-bit>
+# </nc:graceful-restart></nc:any></nc:inet></nc:family></nc:bgp></nc:protocols>"
+
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ type: dict
+ 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: 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: ['<nc:protocols xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ <nc:bgp><nc:family><nc:evpn><nc:signaling><nc:accepted-prefix-limit>
+ <nc:maximum>21</nc:maximum><nc:teardown><nc:limit-threshold>99</nc:limit-threshold>
+ <nc:idle-timeout><nc:timeout>2002</nc:timeout></nc:idle-timeout>
+ </nc:teardown></nc:accepted-prefix-limit><nc:damping/>
+ <nc:delay-route-advertisements><nc:maximum-delay>
+ <nc:route-age>20</nc:route-age><nc:routing-uptime>32000</nc:routing-uptime>
+ </nc:maximum-delay><nc:minimum-delay><nc:inbound-convergence>32000</nc:inbound-convergence>
+ <nc:routing-uptime>23000</nc:routing-uptime></nc:minimum-delay></nc:delay-route-advertisements>
+ </nc:signaling></nc:evpn></nc:family></nc:bgp></nc:protocols>', 'xml 2', 'xml 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.bgp_address_family.bgp_address_family import (
+ Bgp_address_familyArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.bgp_address_family.bgp_address_family import (
+ Bgp_address_family,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ module = AnsibleModule(
+ argument_spec=Bgp_address_familyArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+ result = Bgp_address_family(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_bgp_global.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_bgp_global.py
new file mode 100644
index 000000000..de4715ff0
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_bgp_global.py
@@ -0,0 +1,1763 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2020 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_bgp_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_bgp_global
+version_added: "1.3.0"
+short_description: Manages BGP Global configuration on devices running Juniper JUNOS.
+description:
+ - This module manages global bgp configuration on devices running Juniper JUNOS.
+author: Rohit Thakur (@rohitthakur2590)
+requirements:
+ - ncclient (>=v0.6.4)
+ - xmltodict (>=0.12.0)
+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:
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show protocols bgp).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ config:
+ description: A list of BGP process configuration.
+ type: dict
+ suboptions:
+ as_number:
+ description: Specify Autonomous system number.
+ type: str
+ loops:
+ description: Specify maximum number of times this AS can be in an AS path.
+ type: int
+ asdot_notation:
+ description: Enable AS-Dot notation to display true 4 byte AS numbers.
+ type: bool
+ accept_remote_nexthop: &accept_remote_nexthop
+ description: Allow import policy to specify a non-directly connected next-hop.
+ type: bool
+ add_path_display_ipv4_address: &add_path_display_ipv4_address
+ description: Display add-path path-id in IPv4 address format.
+ type: bool
+ advertise_bgp_static: &advertise_bgp_static
+ description: Advertise bgp-static routes.
+ type: dict
+ suboptions:
+ set:
+ description: Set Advertise bgp-static routes.
+ type: bool
+ policy:
+ description: Specify static route advertisement policy.
+ type: str
+ advertise_external: &advertise_external
+ description: Advertise best external routes.
+ type: dict
+ suboptions:
+ set:
+ description: Set Advertise best external routes.
+ type: bool
+ conditional:
+ description: Route matches active route upto med-comparison rule.
+ type: bool
+ advertise_from_main_vpn_tables:
+ description: Advertise VPN routes from bgp.Xvpn.0 tables in master instance.
+ type: bool
+ advertise_inactive: &advertise_inactive
+ description: Advertise inactive routes.
+ type: bool
+ advertise_peer_as: &advertise_peer_as
+ description: Advertise routes received from the same autonomous system.
+ type: bool
+ authentication_algorithm: &authentication_algorithm
+ description: Specify authentication algorithm name.
+ type: str
+ choices: ["aes-128-cmac-96", "hmac-sha-1-96", "md5"]
+ authentication_key: &authentication_key
+ description: Specify MD5 authentication key.
+ type: str
+ authentication_key_chain: &authentication_key_chain
+ description: Specify authentication key chain name.
+ type: str
+ bfd_liveness_detection: &bfd_liveness_detection
+ description: Bidirectional Forwarding Detection (BFD) options.
+ type: dict
+ suboptions:
+ authentication:
+ description: Authentication options.
+ type: dict
+ suboptions:
+ algorithm:
+ description: Specify algorithm name.
+ type: str
+ choices: ["keyed-md5", "keyed-sha-1", "meticulous-keyed-md5", "meticulous-keyed-sha-1", "simple-password"]
+ key_chain:
+ description: Specify Key chain name.
+ type: str
+ loose_check:
+ description: Verify authentication only if authentication is negotiated.
+ type: bool
+ detection_time:
+ description: Specify Detection-time optionss.
+ type: dict
+ suboptions:
+ threshold:
+ description: Specify high detection-time triggering a trap (milliseconds).
+ type: int
+ holddown_interval:
+ description: Specify time to hold the session-UP notification to the client.
+ type: int
+ minimum_interval:
+ description: Specify minimum transmit and receive interval.
+ type: int
+ minimum_receive_interval:
+ description: Specify minimum receive interval.
+ type: int
+ multiplier:
+ description: Specify detection time multiplier.
+ type: int
+ no_adaptation:
+ description: Disable adaptation.
+ type: bool
+ session_mode:
+ description: BFD single-hop or multihop session-mode.
+ type: str
+ choices: ["automatic", "multihop", "single-hop"]
+ transmit_interval:
+ description: Transmit-interval options.
+ type: dict
+ suboptions:
+ minimum_interval:
+ description: Specify Minimum transmit interval.
+ type: int
+ threshold:
+ description: Specify high transmit interval triggering a trap.
+ type: int
+ version:
+ description: Specify BFD protocol version number.
+ type: str
+ choices: ["0", "1", "automatic"]
+ bgp_error_tolerance: &bgp_error_tolerance
+ description: Handle BGP malformed updates softly.
+ type: dict
+ suboptions:
+ set:
+ description: Set BGP malformed updates softly.
+ type: bool
+ malformed_route_limit:
+ description: Maximum number of malformed routes from a peer.
+ type: int
+ malformed_update_log_interval:
+ description: Time used when logging malformed update.
+ type: int
+ no_malformed_route_limit:
+ description: Specify no malformed route limit.
+ type: bool
+ bmp: &bmp
+ description: Specific settings to override the routing-options settings.
+ type: dict
+ suboptions:
+ monitor:
+ description: Enable/Disable monitoring.
+ type: bool
+ route_monitoring:
+ description: Control route monitoring settings.
+ type: dict
+ suboptions:
+ none:
+ description: Do not send route montoring messages.
+ type: bool
+ post_policy:
+ description: Send post policy route montoring messages.
+ type: bool
+ post_policy_exclude_non_eligible:
+ description: Send post policy route montoring messages and exclude unresolved routes, etc.
+ type: bool
+ pre_policy:
+ description: Send pre policy route montoring messages.
+ type: bool
+ post_policy_exclude_non_feasible:
+ description: Send pre policy route montoring messages and exclude looped routes, etc.
+ type: bool
+ cluster_id: &cluster_id
+ description: Specify cluster identifier.
+ type: str
+ damping: &damping
+ description: Enable route flap damping.
+ type: bool
+ description: &description
+ description: Specify text description.
+ type: str
+ disable:
+ description: Disable BGP.
+ type: bool
+ egress_te: &egress_te
+ description: Use Egress Peering traffic engineering.
+ type: dict
+ suboptions:
+ set:
+ description: Set the attribute.
+ type: bool
+ backup_path:
+ description: The 'egress-te-backup-paths template' to use for this peer.
+ type: str
+ egress_te_backup_paths:
+ description: Backup-path for Egress-TE peer interface failure.
+ type: dict
+ suboptions:
+ templates:
+ description: Specify Backup-path template.
+ type: list
+ elements: dict
+ suboptions:
+ path_name:
+ description: Name of Egress-TE backup path.
+ type: str
+ required: true
+ ip_forward:
+ description: Use IP-forward backup path for Egress TE.
+ type: dict
+ suboptions:
+ set:
+ description: Set use IP-forward backup path for Egress TE.
+ type: bool
+ rti_name:
+ description: Routing-instance to use as IP forward backup-path.
+ type: str
+ peers:
+ description: Specify address of BGP peer to use as backup next-hop.
+ type: list
+ elements: str
+ remote_nexthop:
+ description: Specify address of remote-nexthop to use as backup path.
+ type: str
+ egress_te_set_segment:
+ description: Configure BGP-Peer-Set segment.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: The BGP-Peer-Set segment name.
+ type: str
+ required: true
+ label:
+ description: Backup segment label value from static label pool.
+ type: int
+ egress_te_backup_segment_label:
+ description: BGP-Peer-Set SID label value from static label pool.
+ type: int
+ egress_te_sid_stats:
+ description: Create BGP-Peer-SID sensor.
+ type: bool
+ enforce_first_as: &enforce_first_as
+ description: Enforce neighbor AS is the first AS in AS-PATH attribute (EBGP).
+ type: bool
+ export: &export
+ description: Specify export policy.
+ type: str
+ forwarding_context: &forwarding_context
+ description: Specify routing-instance used for data-forwarding and transport-session.
+ type: str
+ graceful_restart: &graceful_restart
+ description: BGP graceful restart options.
+ type: dict
+ suboptions:
+ set:
+ description: Set BGP graceful restart options.
+ type: bool
+ disable:
+ description: Disable graceful restart.
+ type: bool
+ dont_help_shared_fate_bfd_down:
+ description: Honor BFD-Down(C=0) if GR-restart not in progress.
+ type: bool
+ forwarding_state_bit:
+ description: Control forwarding-state flag negotiation.
+ type: dict
+ suboptions:
+ as_rr_client:
+ description: As for a route reflector client.
+ type: bool
+ from_fib:
+ description: Always use state of associated FIB(s).
+ type: bool
+ long_lived:
+ description: Long-lived graceful restart options.
+ type: dict
+ suboptions:
+ advertise_to_non_llgr_neighbor:
+ description: Advertise stale routes to non-LLGR neighbors.
+ type: dict
+ suboptions:
+ set:
+ description: Set Advertise stale routes to non-LLGR neighbors.
+ type: bool
+ omit_no_export:
+ description: Set Advertise stale routes to non-LLGR neighbors.
+ type: bool
+ receiver_disable:
+ description: Disable receiver (helper) functionality.
+ type: bool
+ restart_time:
+ description: Restart time used when negotiating with a peer.
+ type: int
+ stale_routes_time:
+ description: Maximum time for which stale routes are kept.
+ type: int
+ hold_time: &hold_time
+ description: Specify hold time used when negotiating with a peer.
+ type: int
+ holddown_all_stale_labels:
+ description: Hold all BGP stale-labels, facilating make-before-break for new label advertisements.
+ type: bool
+ idle_after_switch_over: &idle_after_switch_over
+ description: Stop peer session from coming up after nonstop-routing switch-over.
+ type: dict
+ suboptions:
+ timeout:
+ description: Specify timeout value, in seconds, for starting peer after switch over.
+ type: int
+ forever:
+ description: Idle the peer until the user intervenes.
+ type: bool
+ import: &import
+ description: Specify import policy.
+ type: list
+ elements: str
+ include_mp_next_hop: &include_mp_next_hop
+ description: Include NEXT-HOP attribute in multiprotocol updates.
+ type: bool
+ ipsec_sa: &ipsec_sa
+ description: Specify IPSec SA name.
+ type: str
+ keep: &keep
+ description: Specify how to retain routes in the routing table.
+ type: str
+ choices: ["all", "none"]
+ local_address: &local_address
+ description: Specify Address of local end of BGP session.
+ type: str
+ local_as: &local_as
+ description: Local autonomous system number.
+ type: dict
+ suboptions:
+ as_num:
+ description: Autonomous system number in plain number or (asdot notation) format.
+ type: str
+ required: true
+ alias:
+ description: Treat this AS as an alias to the system AS.
+ type: bool
+ loops:
+ description: Maximum number of times this AS can be in an AS path.
+ type: int
+ no_prepend_global_as:
+ description: Maximum number of times this AS can be in an AS path.
+ type: bool
+ private:
+ description: Hide this local AS in paths learned from this peering.
+ type: bool
+ local_interface: &local_interface
+ description: Specify Local interface for IPv6 link local EBGP peering.
+ type: str
+ local_preference: &local_preference
+ description: Specify value of LOCAL_PREF path attribute.
+ type: str
+ log_updown: &log_updown
+ description: Enable log a message for peer state transitions.
+ type: bool
+ metric_out: &metric_out
+ description: Specify route metric sent in MED.
+ type: dict
+ suboptions:
+ metric_value:
+ description: Specify metric value.
+ type: int
+ igp:
+ description: Track the IGP metric.
+ type: dict
+ suboptions:
+ set:
+ description: Set track the IGP metric.
+ type: bool
+ metric_offset:
+ description: Specify metric offset for MED.
+ type: int
+ delay_med_update:
+ description: Delay updating MED when IGP metric increases.
+ type: bool
+ minimum_igp:
+ description: Track the minimum IGP metric.
+ type: dict
+ suboptions:
+ set:
+ description: Set track the minimum IGP metric.
+ type: bool
+ metric_offset:
+ description: Specify metric offset for MED.
+ type: int
+ mtu_discovery: &mtu_discovery
+ description: Enable TCP path MTU discovery.
+ type: bool
+ multihop: &multihop
+ description: Configure an EBGP multihop session.
+ type: dict
+ suboptions:
+ set:
+ description: Set an EBGP multihop session.
+ type: bool
+ no_nexthop_change:
+ description: Do not change next hop to self in advertisements.
+ type: bool
+ ttl:
+ description: TTL value for the session.
+ type: int
+ multipath: &multipath
+ description: Allow load sharing among multiple BGP paths.
+ type: dict
+ suboptions:
+ set:
+ description: Set allow load sharing among multiple BGP paths.
+ type: bool
+ disable:
+ description: Disable Multipath.
+ type: bool
+ multiple_as:
+ description: Use paths received from different ASs.
+ type: bool
+ multiple_as_disable:
+ description: Disable multipath.
+ type: bool
+ multipath_build_priority:
+ description: Configure the multipath build priority.
+ type: str
+ choices: ["low", "medium"]
+ no_advertise_peer_as: &no_advertise_peer_as
+ description: Allows to not advertise routes received from the same autonomous system.
+ type: bool
+ no_aggregator_id: &no_aggregator_id
+ description: Set router ID in aggregator path attribute to 0.
+ type: bool
+ no_client_reflect: &no_client_reflect
+ description: Disable intracluster route redistribution.
+ type: bool
+ no_precision_timers: &no_precision_timers
+ description: Specify not to use precision timers for scheduling keepalives.
+ type: bool
+ out_delay: &out_delay
+ description: Specify how long before exporting routes from routing table.
+ type: int
+ outbound_route_filter: &outbound_route_filter
+ description: Dynamically negotiated cooperative route filtering.
+ type: dict
+ suboptions:
+ bgp_orf_cisco_mode:
+ description: Using BGP ORF capability code 130 and Prefix ORF type 128.
+ type: bool
+ prefix_based:
+ description: Prefix-based outbound route filtering.
+ type: dict
+ suboptions:
+ set:
+ description: Set prefix-based outbound route filtering.
+ type: bool
+ accept:
+ description: Honor Prefix-based ORFs from remote peers.
+ type: dict
+ suboptions:
+ set:
+ description: Set honor Prefix-based ORFs from remote peers.
+ type: bool
+ inet:
+ description: Honor IPv4 prefix filters.
+ type: bool
+ inet6:
+ description: Honor IPv6 prefix filters.
+ type: bool
+ output_queue_priority:
+ description: BGP output queue priority scheduler for updates.
+ type: dict
+ suboptions:
+ defaults:
+ description: Map policy's priority class and BGP output-queue.
+ type: dict
+ suboptions:
+ high:
+ description: Assign the 'high' priority class to this output-queue.
+ type: dict
+ suboptions:
+ expedited:
+ description: Expedited queue; highest priority.
+ type: bool
+ priority:
+ description: Specify output queue priorit.
+ type: int
+ low:
+ description: Assign the 'low' priority class to this output-queue.
+ type: dict
+ suboptions:
+ expedited:
+ description: Expedited queue; highest priority.
+ type: bool
+ priority:
+ description: Specify output queue priorit.
+ type: int
+ medium:
+ description: Assign the 'medium' priority class to this output-queue.
+ type: dict
+ suboptions:
+ expedited:
+ description: Expedited queue; highest priority.
+ type: bool
+ priority:
+ description: Specify output queue priorit.
+ type: int
+ expedited_update_tokens:
+ description: Expedited queue; highest priority for number of tokens.
+ type: int
+ priority_update_tokens:
+ description: Output queue priority; higher is better.
+ type: list
+ elements: dict
+ suboptions:
+ priority:
+ description: Specify the priority.
+ type: int
+ required: true
+ update_tokens:
+ description: Specify update_tokens.
+ type: int
+ required: true
+ passive: &passive
+ description: Specify to not send open messages to a peer.
+ type: bool
+ path_selection:
+ description: Configure path selection strategy.
+ type: dict
+ suboptions:
+ always_compare_med:
+ description: Compare MED on paths from different AS.
+ type: bool
+ as_path_ignore:
+ description: Ignore AS path comparison during path selection.
+ type: bool
+ cisco_non_deterministic:
+ description: Use Cisco IOS nondeterministic path selection algorithm.
+ type: bool
+ external_router_id:
+ description: Compare router ID on BGP externals.
+ type: bool
+ l2vpn_use_bgp_rules:
+ description: Use standard BGP rules during L2VPN path selection.
+ type: bool
+ med_plus_igp:
+ description: Add IGP cost to next-hop to MED before comparing MED values.
+ type: dict
+ suboptions:
+ set:
+ description: Set med-plus-igp attribute.
+ type: bool
+ igp_multiplier:
+ description: Specify multiplier for IGP cost to next-hop.
+ type: int
+ med_multiplier:
+ description: Specify Multiplier for MED.
+ type: int
+ peer_as: &peer_as
+ description: Specify Autonomous system number in plain number or 'higher 16bits'.'Lower 16 bits' format.
+ type: str
+ precision_timers:
+ description: Use precision timers for scheduling keepalives.
+ type: bool
+ preference: &preference
+ description: Specify preference value.
+ type: str
+ remove_private: &remove_private
+ description: Remove well-known private AS numbers.
+ type: dict
+ suboptions:
+ set:
+ description: Remove well-known private AS numbers.
+ type: bool
+ all:
+ description: Remove all private AS numbers and do not stop at the first public AS number.
+ type: bool
+ all_replace:
+ description: Specify private AS replacement.
+ type: bool
+ all_replace_nearest:
+ description: Use closest public AS number to replace a private AS number.
+ type: bool
+ no_peer_loop_check:
+ description: Remove peer loop-check.
+ type: bool
+ rfc6514_compliant_safi129: &rfc6514_compliant_safi129
+ description: Specify Compliance with RFC6514 SAFI129 format.
+ type: bool
+ route_server_client: &route_server_client
+ description: Enable route server client behavior.
+ type: bool
+ send_addpath_optimization:
+ description: Enable BGP addpath advertisement optimization.
+ type: bool
+ snmp_options:
+ description: Customize SNMP behaviors specifically for BGP MIBs.
+ type: dict
+ suboptions:
+ backward_traps_only_from_established:
+ description: Limit traps for backward transitions to only those moving from Established state.
+ type: bool
+ emit_inet_address_length_in_oid:
+ description: Emit Length in OID for InetAddress MIB type.
+ type: bool
+ sr_preference_override:
+ description: Replace received segment routing traffic engineering preference value with override value.
+ type: str
+ stale_labels_holddown_period:
+ description: Specify duration (sec) MPLS labels allocated by BGP are kept after they go stale.
+ type: int
+ tcp_aggressive_transmission: &tcp_aggressive_transmission
+ description: Enable aggressive transmission of pure TCP ACKs and retransmissions.
+ type: bool
+ tcp_mss: &tcp_mss
+ description: Specify maximum TCP segment size.
+ type: int
+ traceoptions: &traceoptions
+ description: Configure trace options for BGP.
+ type: dict
+ suboptions:
+ file:
+ description: Specify trace file options.
+ type: dict
+ suboptions:
+ filename:
+ description: Specify name of file in which to write trace information.
+ type: str
+ required: true
+ files:
+ description: Specify maximum number of trace files.
+ type: int
+ no_world_readable:
+ description: Don't allow any user to read the log file.
+ type: bool
+ world_readable:
+ description: Allow any user to read the log file.
+ type: bool
+ size:
+ description: Specify maximum trace file size.
+ type: int
+ flag:
+ description: Specify tracing parameters.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: specify event name
+ type: str
+ choices:
+ - 4byte-as
+ - add-path
+ - all
+ - bfd
+ - damping
+ - egress-te
+ - general
+ - graceful-restart
+ - keepalive
+ - normal
+ - nsr-synchronization
+ - open
+ - packets
+ - policy
+ - refresh
+ - route
+ - state
+ - task
+ - thread-io
+ - thread-update-io
+ - timer
+ - update
+ required: true
+ detail:
+ description: Trace detailed information.
+ type: bool
+ disable:
+ description: Disable this trace flag.
+ type: bool
+ receive:
+ description: Trace received packets.
+ type: bool
+ send:
+ description: Trace transmitted packets.
+ type: bool
+ filter:
+ description: Filter to apply to this flag.
+ type: dict
+ suboptions:
+ set:
+ description: Set filter to apply to this flag.
+ type: bool
+ match_on_prefix:
+ description: Specify filter based on prefix.
+ type: bool
+ policy:
+ description: Specify filter policy.
+ type: str
+ traffic_statistics_labeled_path:
+ description: Collect periodic ingress labeled statistics for BGP label-switched paths.
+ type: dict
+ suboptions:
+ file:
+ description: Specify statistics file options.
+ type: dict
+ suboptions:
+ filename:
+ description: Specify name of file in which to write trace information.
+ type: str
+ files:
+ description: Specify maximum number of trace files.
+ type: int
+ no_world_readable:
+ description: Don't allow any user to read the log file.
+ type: bool
+ world_readable:
+ description: Allow any user to read the log file.
+ type: bool
+ size:
+ description: Specify maximum trace file size.
+ type: int
+ interval:
+ description: Specify time interval to collect statistics.
+ type: int
+ ttl: &ttl
+ description: Specify TTL value for the single-hop peer.
+ type: int
+ unconfigured_peer_graceful_restart:
+ description: Specify BGP unconfigured peer graceful restart options.
+ type: bool
+ vpn_apply_export:
+ description: Apply BGP export policy when exporting VPN routes.
+ type: bool
+ groups:
+ description: Specify name of the group.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify the name of the group
+ type: str
+ accept_remote_nexthop: *accept_remote_nexthop
+ add_path_display_ipv4_address: *add_path_display_ipv4_address
+ advertise_bgp_static: *advertise_bgp_static
+ advertise_external: *advertise_external
+ advertise_inactive: *advertise_inactive
+ advertise_peer_as: *advertise_peer_as
+ allow:
+ description: Configure peer connections for specific networks.
+ type: list
+ elements: str
+ as_override: &as_override
+ description: Replace neighbor AS number with our AS number
+ type: bool
+ authentication_algorithm: *authentication_algorithm
+ authentication_key: *authentication_key
+ authentication_key_chain: *authentication_key_chain
+ bfd_liveness_detection: *bfd_liveness_detection
+ bgp_error_tolerance: *bgp_error_tolerance
+ bmp: *bmp
+ cluster_id: *cluster_id
+ damping: *damping
+ description: *description
+ egress_te: *egress_te
+ enforce_first_as: *enforce_first_as
+ export: *export
+ forwarding_context: *forwarding_context
+ graceful_restart: *graceful_restart
+ hold_time: *hold_time
+ idle_after_switch_over: *idle_after_switch_over
+ import: *import
+ include_mp_next_hop: *include_mp_next_hop
+ ipsec_sa: *ipsec_sa
+ keep: *keep
+ local_address: *local_address
+ local_as: *local_as
+ local_interface: *local_interface
+ local_preference: *local_preference
+ log_updown: *log_updown
+ metric_out: *metric_out
+ mtu_discovery: *mtu_discovery
+ multihop: *multihop
+ multipath: *multipath
+ no_advertise_peer_as: *no_advertise_peer_as
+ no_aggregator_id: *no_aggregator_id
+ no_client_reflect: *no_client_reflect
+ optimal_route_reflection:
+ description: Enable optimal route reflection for this client group.
+ type: dict
+ suboptions:
+ igp_backup:
+ description: Backup node identifier for this client group.
+ type: str
+ igp_primary:
+ description: Primary node identifier for this client group.
+ type: str
+ out_delay: *out_delay
+ outbound_route_filter: *outbound_route_filter
+ passive: *passive
+ peer_as: *peer_as
+ preference: *preference
+ remove_private: *remove_private
+ rfc6514_compliant_safi129: *rfc6514_compliant_safi129
+ route_server_client: *route_server_client
+ tcp_aggressive_transmission: *tcp_aggressive_transmission
+ tcp_mss: *tcp_mss
+ traceoptions: *traceoptions
+ ttl: *ttl
+ type:
+ description: Specify BGP group type.
+ type: str
+ choices: ['external', 'internal']
+ unconfigured_peer_graceful_restart: &unconfigured_peer_graceful_restart
+ description: Specify BGP unconfigured peer graceful restart options.
+ type: bool
+ vpn_apply_export: &vpn_apply_export
+ description: Apply BGP export policy when exporting VPN routes.
+ type: bool
+ neighbors:
+ description: Specify list of neighbors.
+ type: list
+ elements: dict
+ suboptions:
+ neighbor_address:
+ description: Specify neighbor address.
+ type: str
+ accept_remote_nexthop: *accept_remote_nexthop
+ add_path_display_ipv4_address: *add_path_display_ipv4_address
+ advertise_bgp_static: *advertise_bgp_static
+ advertise_external: *advertise_external
+ advertise_inactive: *advertise_inactive
+ advertise_peer_as: *advertise_peer_as
+ as_override: *as_override
+ authentication_algorithm: *authentication_algorithm
+ authentication_key: *authentication_key
+ authentication_key_chain: *authentication_key_chain
+ bfd_liveness_detection: *bfd_liveness_detection
+ bgp_error_tolerance: *bgp_error_tolerance
+ bmp: *bmp
+ cluster_id: *cluster_id
+ damping: *damping
+ description:
+ description: Specify neighbor description.
+ type: str
+ egress_te: *egress_te
+ enforce_first_as: *enforce_first_as
+ export: *export
+ forwarding_context: *forwarding_context
+ graceful_restart: *graceful_restart
+ hold_time: *hold_time
+ idle_after_switch_over: *idle_after_switch_over
+ import: *import
+ include_mp_next_hop: *include_mp_next_hop
+ ipsec_sa: *ipsec_sa
+ keep: *keep
+ local_address: *local_address
+ local_as: *local_as
+ local_interface: *local_interface
+ local_preference: *local_preference
+ log_updown: *log_updown
+ metric_out: *metric_out
+ mtu_discovery: *mtu_discovery
+ multihop: *multihop
+ multipath: *multipath
+ no_advertise_peer_as: *no_advertise_peer_as
+ no_aggregator_id: *no_aggregator_id
+ no_client_reflect: *no_client_reflect
+ out_delay: *out_delay
+ outbound_route_filter: *outbound_route_filter
+ passive: *passive
+ peer_as: *peer_as
+ preference: *preference
+ remove_private: *remove_private
+ rfc6514_compliant_safi129: *rfc6514_compliant_safi129
+ route_server_client: *route_server_client
+ tcp_aggressive_transmission: *tcp_aggressive_transmission
+ tcp_mss: *tcp_mss
+ traceoptions: *traceoptions
+ ttl: *ttl
+ unconfigured_peer_graceful_restart: *unconfigured_peer_graceful_restart
+ vpn_apply_export: *vpn_apply_export
+
+ state:
+ description:
+ - The state the configuration should be left in.
+ - State I(purged) removes all (routing-options autonomous-system, bgp global, bgp groups, bgp neighbors, bgp family
+ and bgp group and neighbor family) the BGP configurations from the
+ target device. Use caution with this state.
+ - State I(deleted) only removes BGP attributes that this modules
+ manages and does not negate the BGP process completely. Thereby, preserving
+ address-family related configurations under BGP context.
+ - Running states I(deleted) and I(replaced) will result in an error if there
+ are address-family configuration lines present under a neighbor.Please use the
+ M(junipernetworks.junos.junos_bgp_address_family)
+ modules for prior cleanup.
+ - Refer to examples for more details.
+ type: str
+ choices:
+ - purged
+ - merged
+ - replaced
+ - deleted
+ - gathered
+ - parsed
+ - rendered
+ default: merged
+"""
+EXAMPLES = """
+# Using merged
+#
+# Before state
+# ------------
+#
+# admin# show protocols bgp
+# [edit]
+
+# admin# show routing-options autonomous-system
+# [edit]
+
+- name: Merge Junos BGP config
+ junipernetworks.junos.junos_bgp_global:
+ config:
+ as_number: "65534"
+ loops: 3
+ asdot_notation: true
+ accept_remote_nexthop: true
+ add_path_display_ipv4_address: true
+ advertise_bgp_static:
+ policy: "static-to-bgp"
+ advertise_from_main_vpn_tables: true
+ advertise_inactive: true
+ authentication_algorithm: "md5"
+ bgp_error_tolerance:
+ malformed_route_limit: 20000000
+ bmp:
+ monitor: true
+ damping: true
+ description: "This is configured with Junos_bgp resource module"
+ egress_te_sid_stats: true
+ hold_time: 5
+ holddown_all_stale_labels: true
+ include_mp_next_hop: true
+ log_updown: true
+ no_advertise_peer_as: true
+ no_aggregator_id: true
+ no_client_reflect: true
+ out_delay: 10
+ precision_timers: true
+ preference: 2
+ state: merged
+
+# After state
+# -----------
+#
+# admin# show routing-options autonomous-system
+# 65534 loops 3 asdot-notation;
+
+# admin# show protocols bgp
+# precision-timers;
+# advertise-from-main-vpn-tables;
+# holddown-all-stale-labels;
+# description "This is configured with Junos_bgp resource module";
+# accept-remote-nexthop;
+# preference 2;
+# hold-time 5;
+# advertise-inactive;
+# no-advertise-peer-as;
+# no-aggregator-id;
+# out-delay 10;
+# log-updown;
+# damping;
+# bgp-error-tolerance {
+# malformed-route-limit 20000000;
+# }
+# authentication-algorithm md5;
+# no-client-reflect;
+# include-mp-next-hop;
+# bmp {
+# monitor enable;
+# }
+# advertise-bgp-static {
+# policy static-to-bgp;
+# }
+# add-path-display-ipv4-address;
+# egress-te-sid-stats;
+
+
+# Using merged
+#
+# Before state
+# ------------
+#
+# admin# show routing-options autonomous-system
+# 65534 loops 3 asdot-notation;
+
+# admin# show protocols bgp
+# precision-timers;
+# advertise-from-main-vpn-tables;
+# holddown-all-stale-labels;
+# description "This is configured with Junos_bgp resource module";
+# accept-remote-nexthop;
+# preference 2;
+# hold-time 5;
+# advertise-inactive;
+# no-advertise-peer-as;
+# no-aggregator-id;
+# out-delay 10;
+# log-updown;
+# damping;
+# bgp-error-tolerance {
+# malformed-route-limit 20000000;
+# }
+# authentication-algorithm md5;
+# no-client-reflect;
+# include-mp-next-hop;
+# bmp {
+# monitor enable;
+# }
+# advertise-bgp-static {
+# policy static-to-bgp;
+# }
+# add-path-display-ipv4-address;
+# egress-te-sid-stats;
+
+- name: Update running Junos BGP config
+ junipernetworks.junos.junos_bgp_global:
+ config:
+ egress_te_backup_paths:
+ templates:
+ - path_name: customer1
+ peers:
+ - '11.11.11.11'
+ - '11.11.11.12'
+ - '11.11.11.13'
+ remote_nexthop: '2.2.2.2'
+ groups:
+ - name: 'internal'
+ type: 'internal'
+ vpn_apply_export: true
+ out_delay: 30
+ accept_remote_nexthop: true
+ add_path_display_ipv4_address: true
+ peer_as: '65534'
+ allow:
+ - 'all'
+ - '1.1.1.0/24'
+ neighbors:
+ - neighbor_address: '11.11.11.11'
+ peer_as: '65534'
+ out_delay: 11
+ - neighbor_address: '11.11.11.12'
+ peer_as: '65534'
+ out_delay: 12
+
+ - name: 'external'
+ out_delay: 20
+ peer_as: '65534'
+ accept_remote_nexthop: true
+ add_path_display_ipv4_address: true
+ neighbors:
+ - neighbor_address: '12.12.12.12'
+ peer_as: '65534'
+ out_delay: 21
+ accept_remote_nexthop: true
+ add_path_display_ipv4_address: true
+ - neighbor_address: '11.11.11.13'
+ peer_as: '65534'
+ out_delay: 31
+ accept_remote_nexthop: true
+ add_path_display_ipv4_address: true
+ state: merged
+
+# After state
+# -----------
+#
+# admin# show routing-options autonomous-system
+# 65534 loops 3 asdot-notation;
+
+# admin# show protocols bgp
+# precision-timers;
+# advertise-from-main-vpn-tables;
+# holddown-all-stale-labels;
+# egress-te-backup-paths {
+# template customer1 {
+# peer 11.11.11.11;
+# peer 11.11.11.12;
+# peer 11.11.11.13;
+# remote-nexthop {
+# 2.2.2.2;
+# }
+# }
+# }
+# description "This is configured with Junos_bgp resource module";
+# accept-remote-nexthop;
+# preference 2;
+# hold-time 5;
+# advertise-inactive;
+# no-advertise-peer-as;
+# no-aggregator-id;
+# out-delay 10;
+# log-updown;
+# damping;
+# bgp-error-tolerance {
+# malformed-route-limit 20000000;
+# }
+# authentication-algorithm md5;
+# no-client-reflect;
+# include-mp-next-hop;
+# bmp {
+# monitor enable;
+# }
+# add-path-display-ipv4-address;
+# egress-te-sid-stats;
+# group internal {
+# type internal;
+# accept-remote-nexthop;
+# out-delay 30;
+# vpn-apply-export;
+# peer-as 65534;
+# add-path-display-ipv4-address;
+# allow [ 0.0.0.0/0 1.1.1.0/24 ];
+# neighbor 11.11.11.11 {
+# out-delay 11;
+# peer-as 65534;
+# }
+# neighbor 11.11.11.12 {
+# out-delay 12;
+# peer-as 65534;
+# }
+# }
+# group external {
+# accept-remote-nexthop;
+# out-delay 20;
+# peer-as 65534;
+# add-path-display-ipv4-address;
+# neighbor 12.12.12.12 {
+# accept-remote-nexthop;
+# out-delay 21;
+# peer-as 65534;
+# add-path-display-ipv4-address;
+# }
+# neighbor 11.11.11.13 {
+# accept-remote-nexthop;
+# out-delay 31;
+# peer-as 65534;
+# add-path-display-ipv4-address;
+# }
+# }
+
+
+# Using replaced
+#
+# Before state
+# ------------
+#
+# admin# show routing-options autonomous-system
+# [edit]
+# admin# show protocols bgp
+# precision-timers;
+# advertise-from-main-vpn-tables;
+# holddown-all-stale-labels;
+# description "This is configured with Junos_bgp resource module";
+# accept-remote-nexthop;
+# preference 2;
+# hold-time 5;
+# advertise-inactive;
+# no-advertise-peer-as;
+# no-aggregator-id;
+# out-delay 10;
+# log-updown;
+# damping;
+# bgp-error-tolerance {
+# malformed-route-limit 20000000;
+# }
+# authentication-algorithm md5;
+# no-client-reflect;
+# include-mp-next-hop;
+# bmp {
+# monitor enable;
+# }
+# advertise-bgp-static {
+# policy static-to-bgp;
+# }
+# add-path-display-ipv4-address;
+# egress-te-sid-stats;
+
+- name: Replace Junos BGP global config
+ junipernetworks.junos.junos_bgp_global:
+ config:
+ advertise_bgp_static:
+ policy: "static-to-bgp"
+ advertise_inactive: true
+ authentication_algorithm: "md5"
+ bfd_liveness_detection:
+ minimum_receive_interval: 8
+ multiplier: 30
+ no_adaptation: true
+ transmit_interval:
+ minimum_interval: 4
+ version: "automatic"
+ bgp_error_tolerance:
+ malformed_route_limit: 40000000
+ description: "This is configured with Junos_bgp resource module replace"
+ egress_te_sid_stats: true
+ hold_time: 5
+ out_delay: 10
+ preference: "2"
+ state: replaced
+
+# After state
+# -----------
+#
+# admin# show protocols bgp
+# description "This is configured with Junos_bgp resource module replace";
+# preference 2;
+# hold-time 5;
+# advertise-inactive;
+# out-delay 10;
+# bgp-error-tolerance {
+# malformed-route-limit 40000000;
+# }
+# authentication-algorithm md5;
+# advertise-bgp-static {
+# policy static-to-bgp;
+# }
+# bfd-liveness-detection {
+# version automatic;
+# minimum-receive-interval 8;
+# multiplier 30;
+# no-adaptation;
+# transmit-interval {
+# minimum-interval 4;
+# }
+# }
+# egress-te-sid-stats;
+
+# admin# show routing-options autonomous-system
+# [edit]
+
+#
+# Using deleted
+#
+# Before state
+# ------------
+#
+# admin# show protocols bgp
+# precision-timers;
+# advertise-from-main-vpn-tables;
+# holddown-all-stale-labels;
+# description "This is configured with Junos_bgp resource module";
+# accept-remote-nexthop;
+# preference 2;
+# hold-time 5;
+# advertise-inactive;
+# no-advertise-peer-as;
+# no-aggregator-id;
+# out-delay 10;
+# log-updown;
+# damping;
+# bgp-error-tolerance {
+# malformed-route-limit 20000000;
+# }
+# authentication-algorithm md5;
+# no-client-reflect;
+# include-mp-next-hop;
+# bmp {
+# monitor enable;
+# }
+# add-path-display-ipv4-address;
+# egress-te-sid-stats;
+# group internal {
+# out-delay 12;
+# }
+# admin# show routing-options autonomous-system
+# 65534 loops 3 asdot-notation;
+
+- name: Delete Junos BGP global config
+ junipernetworks.junos.junos_bgp_global:
+ config:
+ state: deleted
+
+# After state
+# -----------
+# admin# show protocols bgp
+# group internal {
+# out-delay 12;
+# }
+
+
+
+# admin# show protocols bgp
+# [edit]
+
+# admin# show routing-options autonomous-system
+# [edit]
+# Using gathered
+#
+# Before state
+# ------------
+#
+# admin# show protocols bgp
+# description "This is configured with Junos_bgp resource module replace";
+# preference 2;
+# hold-time 5;
+# advertise-inactive;
+# out-delay 10;
+# bgp-error-tolerance {
+# malformed-route-limit 40000000;
+# }
+# authentication-algorithm md5;
+# advertise-bgp-static {
+# policy static-to-bgp;
+# }
+# bfd-liveness-detection {
+# version automatic;
+# minimum-receive-interval 8;
+# multiplier 30;
+# no-adaptation;
+# transmit-interval {
+# minimum-interval 4;
+# }
+# }
+# egress-te-sid-stats;
+
+- name: Gather Junos BGP global config
+ junipernetworks.junos.junos_bgp_global:
+ config:
+ state: gathered
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+# "gathered": {
+# "advertise_bgp_static": {
+# "policy": "static-to-bgp"
+# },
+# "advertise_inactive": true,
+# "authentication_algorithm": "md5",
+# "bfd_liveness_detection": {
+# "minimum_receive_interval": 8,
+# "multiplier": 30,
+# "no_adaptation": true,
+# "transmit_interval": {
+# "minimum_interval": 4
+# },
+# "version": "automatic"
+# },
+# "bgp_error_tolerance": {
+# "malformed_route_limit": 40000000
+# },
+# "description": "This is configured with Junos_bgp resource module replace",
+# "egress_te_sid_stats": true,
+# "hold_time": 5,
+# "out_delay": 10,
+# "preference": "2"
+# }
+#
+#
+# Using purged
+#
+# Before state
+# ------------
+#
+# admin# show protocols bgp
+# precision-timers;
+# advertise-from-main-vpn-tables;
+# holddown-all-stale-labels;
+# description "This is configured with Junos_bgp resource module";
+# accept-remote-nexthop;
+# preference 2;
+# hold-time 5;
+# advertise-inactive;
+# no-advertise-peer-as;
+# no-aggregator-id;
+# out-delay 10;
+# log-updown;
+# damping;
+# bgp-error-tolerance {
+# malformed-route-limit 20000000;
+# }
+# authentication-algorithm md5;
+# no-client-reflect;
+# include-mp-next-hop;
+# bmp {
+# monitor enable;
+# }
+# add-path-display-ipv4-address;
+# egress-te-sid-stats;
+# group internal {
+# out-delay 12;
+# }
+# admin# show routing-options autonomous-system
+# 65534 loops 3 asdot-notation;
+
+- name: Purge Junos BGP global config
+ junipernetworks.junos.junos_bgp_global:
+ config:
+ state: purged
+
+# After state
+# ----------
+# admin# show protocols bgp
+#
+# [edit]
+# admin# show routing-options autonomous-system
+#
+#[edit]
+
+
+# Using rendered
+#
+#
+- name: Render the commands for provided configuration
+ junipernetworks.junos.junos_bgp_global:
+ config:
+ authentication_algorithm: "md5"
+ bfd_liveness_detection:
+ minimum_receive_interval: 4
+ multiplier: 10
+ no_adaptation: true
+ transmit_interval:
+ minimum_interval: 2
+ version: "automatic"
+ bgp_error_tolerance:
+ malformed_route_limit: 20000000
+ bmp:
+ monitor: true
+ damping: true
+ description: "This is configured with Junos_bgp resource module"
+ egress_te_sid_stats: true
+ hold_time: 5
+ state: rendered
+
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "rendered": "
+# <nc:protocols
+# xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# <nc:bgp>
+# <nc:damping/>
+# <nc:egress-te-sid-stats/>
+# <nc:authentication-algorithm>md5</nc:authentication-algorithm>
+# <nc:description>This is configured with Junos_bgp resource module</nc:description>
+# <nc:hold-time>5</nc:hold-time>
+# <nc:bfd-liveness-detection>
+# <nc:transmit-interval>
+# <nc:minimum-interval>2</nc:minimum-interval>
+# </nc:transmit-interval>
+# <nc:minimum-receive-interval>4</nc:minimum-receive-interval>
+# <nc:multiplier>10</nc:multiplier>
+# <nc:no-adaptation/>
+# <nc:version>automatic</nc:version>
+# </nc:bfd-liveness-detection>
+# <nc:bgp-error-tolerance>
+# <nc:malformed-route-limit>20000000</nc:malformed-route-limit>
+# </nc:bgp-error-tolerance>
+# <nc:bmp>
+# <nc:monitor>enable</nc:monitor>
+# </nc:bmp>
+# </nc:bgp>
+# </nc:protocols>"
+#
+# Using parsed
+# parsed.cfg
+# ------------
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <version>18.4R1-S2.4</version>
+# <protocols>
+# <bgp>
+# <precision-timers />
+# <advertise-from-main-vpn-tables />
+# <holddown-all-stale-labels />
+# <description>This is configured with Junos_bgp resource module</description>
+# <accept-remote-nexthop />
+# <preference>2</preference>
+# <hold-time>5</hold-time>
+# <advertise-inactive />
+# <no-advertise-peer-as />
+# <no-aggregator-id />
+# <out-delay>10</out-delay>
+# <log-updown />
+# <damping />
+# <bgp-error-tolerance>
+# <malformed-route-limit>20000000</malformed-route-limit>
+# </bgp-error-tolerance>
+# <authentication-algorithm>md5</authentication-algorithm>
+# <remove-private />
+# <no-client-reflect />
+# <include-mp-next-hop />
+# <bmp>
+# <monitor>disable</monitor>
+# <route-monitoring>
+# <none />
+# </route-monitoring>
+# </bmp>
+# <advertise-bgp-static>
+# <policy>static-to-bgp</policy>
+# </advertise-bgp-static>
+# <add-path-display-ipv4-address />
+# <bfd-liveness-detection>
+# <version>automatic</version>
+# <minimum-receive-interval>4</minimum-receive-interval>
+# <multiplier>10</multiplier>
+# <no-adaptation />
+# <transmit-interval>
+# <minimum-interval>2</minimum-interval>
+# </transmit-interval>
+# <detection-time>
+# <threshold>300000</threshold>
+# </detection-time>
+# </bfd-liveness-detection>
+# <egress-te-sid-stats />
+# <group>
+# <name>internal</name>
+# <out-delay>8</out-delay>
+# </group>
+# <group>
+# <name>external</name>
+# <out-delay>9</out-delay>
+# </group>
+# <group>
+# <name>inboun</name>
+# <type>internal</type>
+# </group>
+# <group>
+# <name>ibgp</name>
+# <type>internal</type>
+# <local-address>10.2.2.2</local-address>
+# <export>static-to-bgp</export>
+# <neighbor>
+# <name>10.1.1.1</name>
+# </neighbor>
+# </group>
+# </bgp>
+# <ospf3>
+# <area>
+# <name>0.0.0.100</name>
+# <stub>
+# <default-metric>200</default-metric>
+# </stub>
+# <interface>
+# <name>so-0/0/0.0</name>
+# <metric>5</metric>
+# <priority>3</priority>
+# </interface>
+# </area>
+# </ospf3>
+# </protocols>
+# <routing-options>
+# <static>
+# <route>
+# <name>172.16.17.0/24</name>
+# <discard />
+# </route>
+# </static>
+# <router-id>10.200.16.75</router-id>
+# <autonomous-system>
+# <as-number>65432</as-number>
+# </autonomous-system>
+# </routing-options>
+# </configuration>
+# </rpc-reply>
+
+
+- name: Parsed the device configuration to get output commands
+ junipernetworks.junos.junos_bgp_global:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "parsed": {
+# "accept_remote_nexthop": true,
+# "add_path_display_ipv4_address": true,
+# "advertise_bgp_static": {
+# "policy": "static-to-bgp"
+# },
+# "advertise_from_main_vpn_tables": true,
+# "advertise_inactive": true,
+# "as_number": "65432",
+# "authentication_algorithm": "md5",
+# "bfd_liveness_detection": {
+# "detection_time": {
+# "threshold": 300000
+# },
+# "minimum_receive_interval": 4,
+# "multiplier": 10,
+# "no_adaptation": true,
+# "transmit_interval": {
+# "minimum_interval": 2
+# },
+# "version": "automatic"
+# },
+# "bgp_error_tolerance": {
+# "malformed_route_limit": 20000000
+# },
+# "bmp": {
+# "monitor": false,
+# "route_monitoring": {
+# "none": true
+# }
+# },
+# "damping": true,
+# "description": "This is configured with Junos_bgp resource module",
+# "egress_te_sid_stats": true,
+# "hold_time": 5,
+# "holddown_all_stale_labels": true,
+# "include_mp_next_hop": true,
+# "log_updown": true,
+# "no_advertise_peer_as": true,
+# "no_aggregator_id": true,
+# "no_client_reflect": true,
+# "out_delay": 10,
+# "precision_timers": true,
+# "preference": "2"
+# }
+#
+
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ type: dict
+ 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: 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: ['
+ <nc:protocols
+ xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ <nc:bgp>
+ <nc:damping/>
+ <nc:egress-te-sid-stats/>
+ <nc:authentication-algorithm>md5</nc:authentication-algorithm>
+ <nc:description>This is configured with Junos_bgp resource module</nc:description>
+ <nc:hold-time>5</nc:hold-time>
+ <nc:bfd-liveness-detection>
+ <nc:transmit-interval>
+ <nc:minimum-interval>2</nc:minimum-interval>
+ </nc:transmit-interval>
+ <nc:minimum-receive-interval>4</nc:minimum-receive-interval>
+ <nc:multiplier>10</nc:multiplier>
+ <nc:no-adaptation/>
+ <nc:version>automatic</nc:version>
+ </nc:bfd-liveness-detection>
+ <nc:bgp-error-tolerance>
+ <nc:malformed-route-limit>20000000</nc:malformed-route-limit>
+ </nc:bgp-error-tolerance>
+ <nc:bmp>
+ <nc:monitor>enable</nc:monitor>
+ </nc:bmp>
+ </nc:bgp>
+ </nc:protocols>', 'xml 2', 'xml 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.bgp_global.bgp_global import (
+ Bgp_globalArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.bgp_global.bgp_global import (
+ Bgp_global,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+
+ module = AnsibleModule(
+ argument_spec=Bgp_globalArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+
+ result = Bgp_global(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_command.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_command.py
new file mode 100644
index 000000000..ec713f230
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_command.py
@@ -0,0 +1,481 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_command
+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.
+version_added: 1.0.0
+extends_documentation_fragment:
+- junipernetworks.junos.junos
+options:
+ commands:
+ description:
+ - The commands to send to the remote junos device. 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.
+ type: list
+ elements: str
+ 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.
+ type: list
+ elements: str
+ 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.
+ type: list
+ elements: str
+ aliases:
+ - waitfor
+ 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.
+ type: str
+ default: all
+ choices:
+ - any
+ - all
+ 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.
+ type: int
+ 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.
+ type: int
+ 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.
+ type: str
+ aliases:
+ - format
+ - output
+ choices:
+ - text
+ - json
+ - xml
+ - set
+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
+ junipernetworks.junos.junos_command:
+ commands: show version
+
+- name: run show version and check to see if output contains Juniper
+ junipernetworks.junos.junos_command:
+ commands: show version
+ wait_for: result[0] contains Juniper
+
+- name: run multiple commands on remote nodes
+ junipernetworks.junos.junos_command:
+ commands:
+ - show version
+ - show interfaces
+
+- name: run multiple commands and evaluate the output
+ junipernetworks.junos.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
+ junipernetworks.junos.junos_command:
+ commands: show version
+ display: json
+
+- name: run rpc on the remote device
+ junipernetworks.junos.junos_command:
+ commands: show configuration
+ display: set
+
+- name: run rpc on the remote device
+ junipernetworks.junos.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.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ exec_rpc,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.parsing import (
+ Conditional,
+ FailedConditionalError,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_lines
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ get_capabilities,
+ get_configuration,
+ get_connection,
+ tostring,
+)
+
+
+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 == "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 len(reply) >= 1:
+ if fetch_config:
+ data = reply.find(".//configuration-text")
+ else:
+ if text and text.startswith("show configuration"):
+ data = reply.find(".//configuration-output")
+ else:
+ data = reply.find(".//output")
+
+ if data is None:
+ module.fail_json(msg=tostring(reply))
+
+ responses.append(data.text.strip())
+ else:
+ responses.append(reply.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", elements="str"),
+ rpcs=dict(type="list", elements="str"),
+ display=dict(
+ choices=["text", "json", "xml", "set"],
+ aliases=["format", "output"],
+ ),
+ wait_for=dict(type="list", aliases=["waitfor"], elements="str"),
+ match=dict(default="all", choices=["all", "any"]),
+ retries=dict(default=10, type="int"),
+ interval=dict(default=1, type="int"),
+ )
+
+ 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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_config.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_config.py
new file mode 100644
index 000000000..c8bfde10c
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_config.py
@@ -0,0 +1,531 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_config
+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.
+version_added: 1.0.0
+extends_documentation_fragment:
+- junipernetworks.junos.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.
+ type: list
+ aliases:
+ - commands
+ elements: str
+ 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.
+ type: path
+ 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).
+ type: str
+ choices:
+ - xml
+ - set
+ - text
+ - json
+ 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.
+ type: int
+ 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
+ default: no
+ 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.
+ type: int
+ 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
+ type: str
+ 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
+ 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
+ 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'.
+ type: str
+ default: merge
+ choices:
+ - merge
+ - override
+ - replace
+ - update
+ 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
+ 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
+ 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>
+ type: str
+ 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
+ backup_format:
+ description:
+ - This argument specifies the format of the configuration the backup file will
+ be stored as. If the argument is not specified, the module will use the 'set'
+ format.
+ type: str
+ default: set
+ choices:
+ - xml
+ - set
+ - text
+ - json
+ type: dict
+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
+ junipernetworks.junos.junos_config:
+ src: srx.cfg
+ comment: update config
+
+- name: load configure lines into device
+ junipernetworks.junos.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
+ junipernetworks.junos.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
+ junipernetworks.junos.junos_config:
+ check_commit: yes
+
+- name: rollback the configuration to id 10
+ junipernetworks.junos.junos_config:
+ rollback: 10
+
+- name: zero out the current configuration
+ junipernetworks.junos.junos_config:
+ zeroize: yes
+
+- name: Set VLAN access and trunking
+ junipernetworks.junos.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
+ junipernetworks.junos.junos_config:
+ confirm_commit: yes
+
+- name: for idempotency, use full-form commands
+ junipernetworks.junos.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
+ junipernetworks.junos.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 json
+import re
+
+from ansible.module_utils._text import to_native, to_text
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ exec_rpc,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ get_configuration,
+ get_diff,
+ load_config,
+ load_configuration,
+ locked_config,
+ tostring,
+)
+
+
+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"),
+ backup_format=dict(
+ default="set",
+ choices=["xml", "text", "set", "json"],
+ ),
+ )
+ argument_spec = dict(
+ lines=dict(aliases=["commands"], type="list", elements="str"),
+ 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"),
+ )
+
+ 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"]:
+ if module.params["backup_options"] is not None:
+ conf_format = module.params["backup_options"]["backup_format"]
+ else:
+ conf_format = "set"
+ reply = get_configuration(module, format=conf_format)
+ if reply is None:
+ module.fail_json(msg="unable to retrieve device configuration")
+ else:
+ if conf_format in ["set", "text"]:
+ reply = reply.find(
+ ".//configuration-%s" % conf_format,
+ ).text.strip()
+ elif conf_format in "xml":
+ reply = str(
+ tostring(reply.find(".//configuration"), pretty_print=True),
+ ).strip()
+ elif conf_format in "json":
+ reply = str(reply.xpath("//rpc-reply/text()")[0]).strip()
+ if not isinstance(reply, str):
+ module.fail_json(
+ msg="unable to format retrieved device configuration",
+ )
+ result["__backup__"] = reply
+
+ 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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_facts.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_facts.py
new file mode 100644
index 000000000..f44bdf820
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_facts.py
@@ -0,0 +1,146 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_facts
+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.
+version_added: 1.0.0
+extends_documentation_fragment:
+- junipernetworks.junos.junos
+options:
+ gather_subset:
+ description:
+ - When supplied, this argument will restrict the facts collected to a given subset. Possible
+ values for this argument include C(all), C(hardware), C(config), C(interfaces) and C(min). Can
+ specify a list of values to include a larger subset. Values can also be used
+ with an initial C(!) 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.
+ required: false
+ default:
+ - 'min'
+ type: list
+ elements: str
+ 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.
+ type: str
+ required: false
+ default: text
+ choices:
+ - xml
+ - text
+ - set
+ - json
+ 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(!) 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
+ type: list
+ elements: str
+ available_network_resources:
+ description: When 'True' a list of network resources for which resource modules are available will be provided.
+ type: bool
+ default: false
+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.
+"""
+
+EXAMPLES = """
+- name: collect default set of facts
+ junipernetworks.junos.junos_facts:
+
+- name: collect default set of facts and configuration
+ junipernetworks.junos.junos_facts:
+ gather_subset: config
+
+- name: Gather legacy and resource facts
+ junipernetworks.junos.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_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.facts.facts import (
+ FactsArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.facts.facts import (
+ FACT_RESOURCE_SUBSETS,
+ Facts,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: ansible_facts
+ """
+ argument_spec = FactsArgs.argument_spec
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ warnings = []
+ ansible_facts = {}
+ if module.params.get("available_network_resources"):
+ ansible_facts["available_network_resources"] = sorted(
+ FACT_RESOURCE_SUBSETS.keys(),
+ )
+ result = Facts(module).get_facts()
+ additional_facts, additional_warnings = result
+ ansible_facts.update(additional_facts)
+ warnings.extend(additional_warnings)
+ module.exit_json(ansible_facts=ansible_facts, warnings=warnings)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_hostname.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_hostname.py
new file mode 100644
index 000000000..093645a6f
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_hostname.py
@@ -0,0 +1,362 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2021 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_hostname
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+ANSIBLE_METADATA = {
+ "metadata_version": "1.1",
+ "status": ["preview"],
+ "supported_by": "network",
+}
+
+DOCUMENTATION = """
+---
+module: junos_hostname
+version_added: 2.9.0
+short_description: Manage Hostname server configuration on Junos devices.
+description: This module manages hostname configuration on devices running Junos.
+author: Rohit Thakur (@rohitthakur2590)
+requirements:
+ - ncclient (>=v0.6.4)
+ - xmltodict (>=0.12.0)
+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,https://docs.ansible.com/ansible/latest/network/user_guide/platform_junos.html).
+ - Tested against JunOS v18.4R1
+options:
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show system hostname).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ config:
+ description: A dictionary of system Hostname configuration.
+ type: dict
+ suboptions:
+ hostname:
+ description: Specify the hostname.
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in.
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The states I(merged), I(replaced) and I(overridden) have identical
+ behaviour for this module.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command
+ I(show system hostname) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - deleted
+ - overridden
+ - parsed
+ - gathered
+ - rendered
+ default: merged
+"""
+EXAMPLES = """
+# Using merged
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show system hostname
+#
+# [edit]
+- name: Merge provided HOSTNAME configuration into running configuration.
+ junipernetworks.junos.junos_hostname:
+ config:
+ hostname: 'vsrx-18.4R1'
+ state: merged
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "hostname": "vsrx-18.4R1"
+# },
+# "before": {},
+# "changed": true,
+# "commands": [
+# "<nc:system xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# "<nc:host-name>vsrx-18.4R1</nc:host-name></nc:system>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx-18.4R1# show system host-name
+# host-name vsrx-18.4R1;
+#
+# Using replaced
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx-18.4R1# show system host-name
+# host-name vsrx-18.4R1;
+#
+# [edit]
+- name: Replaced target config with provided config.
+ junipernetworks.junos.junos_hostname:
+ config:
+ hostname: 'vsrx-12'
+ state: replaced
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "hostname": "vsrx-12"
+# },
+# "before": {
+# "hostname": "vsrx-18.4R1"
+# },
+# "changed": true,
+# "commands": [
+# "<nc:system xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# "<nc:host-name>vsrx-12</nc:host-name></nc:system>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx-18.4R1# show system host-name
+# host-name vsrx-12;
+#
+# Using overridden
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx-18.4R1# show system host-name
+# host-name vsrx-18.4R1;
+#
+# [edit]
+- name: Replaced target config with provided config.
+ junipernetworks.junos.junos_hostname:
+ config:
+ hostname: 'vsrx-12'
+ state: overridden
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "hostname": "vsrx-12"
+# },
+# "before": {
+# "hostname": "vsrx-18.4R1"
+# },
+# "changed": true,
+# "commands": [
+# "<nc:system xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# "<nc:host-name>vsrx-12</nc:host-name></nc:system>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx-18.4R1# show system host-name
+# host-name vsrx-12;
+#
+# Using deleted
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx-18.4R1# show system host-name
+# host-name vsrx-12;
+#
+- name: Delete running HOSTNAME global configuration
+ junipernetworks.junos.junos_hostname:
+ config:
+ state: deleted
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {},
+# "before": {
+# "hostname": "vsrx-12"
+# },
+# "changed": true,
+# "commands": [
+# "<nc:system xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# <nc:host-name delete=\"delete\"/></nc:system>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show system ntp
+#
+# [edit]
+# Using gathered
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx-18.4R1# show system host-name
+# host-name vsrx-12;
+#
+- name: Gather running HOSTNAME global configuration
+ junipernetworks.junos.junos_hostname:
+ state: gathered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "gathered": {
+# "hostname": "vsrx-12",
+# },
+# "changed": false,
+# Using rendered
+#
+# Before state
+# ------------
+#
+- name: Render xml for provided facts.
+ junipernetworks.junos.junos_hostname:
+ config:
+ boot_server: '78.46.194.186'
+ state: rendered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "rendered": [
+# "<nc:system xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:host-name>78.46.194.186</nc:host-name></nc:system>"
+# ]
+#
+# Using parsed
+# parsed.cfg
+# ------------
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <version>18.4R1-S2.4</version>
+# <system xmlns="http://yang.juniper.net/junos-es/conf/system">
+# <host-name>vsrx-18.4R1</host-name>
+# </system>
+# </configuration>
+# </rpc-reply>
+#
+- name: Parse HOSTNAME running config
+ junipernetworks.junos.junos_hostname:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "parsed": {
+# "hostname": "vsrx-18.4R1"
+# }
+#
+
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+after:
+ description: The resulting configuration model invocation.
+ returned: when changed
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ['"<nc:host-name>78.46.194.186</nc:host-name></nc:system>"']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.hostname.hostname import (
+ HostnameArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.hostname.hostname import (
+ Hostname,
+)
+
+
+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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ module = AnsibleModule(
+ argument_spec=HostnameArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+
+ result = Hostname(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_interfaces.py
new file mode 100644
index 000000000..f3b749d63
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_interfaces.py
@@ -0,0 +1,587 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_interfaces
+short_description: Junos Interfaces resource module
+description: This module manages the interfaces on Juniper Junos OS network devices.
+version_added: 1.0.0
+author: Ganesh Nalawade (@ganeshrn)
+options:
+ config:
+ description: The provided configuration
+ type: list
+ elements: dict
+ 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: str
+ units:
+ description:
+ - Specify Logical interfaces units.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Specify interface unit number.
+ type: int
+ description:
+ description: Specify logical interface description.
+ type: str
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show interfaces).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - parsed
+ - rendered
+ 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,https://docs.ansible.com/ansible/latest/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
+# unit 0 {
+# description "This is logical intf unit0";
+# }
+# 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)"
+ junipernetworks.junos.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;
+# }
+# fe-0/0/2 {
+# vlan-tagging;
+# unit 10 {
+# vlan-id 10;
+# }
+# unit 11 {
+# vlan-id 11;
+# }
+# }
+
+- name: Merge provided configuration with device configuration (default operation
+ is merge)
+ junipernetworks.junos.junos_interfaces:
+ config:
+ - name: ge-0/0/1
+ description: Configured by Ansible-1
+ enabled: true
+ units:
+ - name: 0
+ description: "This is logical intf unit0"
+ 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
+# unit 0 {
+# description "This is logical intf unit0";
+# }
+# }
+# 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
+ junipernetworks.junos.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
+ junipernetworks.junos.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";
+# }
+# Using gathered
+# Before state:
+# ------------
+#
+# vagrant@vsrx# show interfaces
+# fe-0/0/2 {
+# description "This is interface DESCRIPTION";
+# vlan-tagging;
+# unit 10 {
+# description "UNIT 10 DESCRIPTION";
+# vlan-id 10;
+# }
+# unit 11 {
+# description "UNIT 11 DESCRIPTION";
+# vlan-id 11;
+# }
+# }
+# fxp0 {
+# description OUTER;
+# unit 0 {
+# description "Sample config";
+# family inet {
+# dhcp;
+# }
+# }
+# }
+#
+- name: Gather junos interfaces as in given arguments
+ junipernetworks.junos.junos_interfaces:
+ state: gathered
+# Task Output (redacted)
+# -----------------------
+#
+# "gathered": [
+# {
+# "description": "This is interface DESCRIPTION",
+# "enabled": true,
+# "name": "fe-0/0/2",
+# "units": [
+# {
+# "description": "UNIT 10 DESCRIPTION",
+# "name": 10
+# },
+# {
+# "description": "UNIT 11 DESCRIPTION",
+# "name": 11
+# }
+# ]
+# },
+# {
+# "description": "OUTER",
+# "enabled": true,
+# "name": "fxp0",
+# "units": [
+# {
+# "description": "Sample config",
+# "name": 0
+# }
+# ]
+# }
+# ]
+# After state:
+# ------------
+#
+# vagrant@vsrx# show interfaces
+# fe-0/0/2 {
+# description "This is interface DESCRIPTION";
+# vlan-tagging;
+# unit 10 {
+# description "UNIT 10 DESCRIPTION";
+# vlan-id 10;
+# }
+# unit 11 {
+# description "UNIT 11 DESCRIPTION";
+# vlan-id 11;
+# }
+# }
+# fxp0 {
+# description OUTER;
+# unit 0 {
+# description "Sample config";
+# family inet {
+# dhcp;
+# }
+# }
+# }
+#
+# Using parsed
+# parsed.cfg
+# ------------
+#
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <interfaces>
+# <interface>
+# <name>ge-0/0/1</name>
+# <description>Configured by Ansible</description>
+# <disable/>
+# <speed>100m</speed>
+# <mtu>1024</mtu>
+# <hold-time>
+# <up>2000</up>
+# <down>2200</down>
+# </hold-time>
+# <link-mode>full-duplex</link-mode>
+# <unit>
+# <name>0</name>
+# <family>
+# <ethernet-switching>
+# <interface-mode>access</interface-mode>
+# <vlan>
+# <members>vlan100</members>
+# </vlan>
+# </ethernet-switching>
+# </family>
+# </unit>
+# </interface>
+# </interfaces>
+# </configuration>
+# </rpc-reply>
+# - name: Convert interfaces config to argspec without connecting to the appliance
+# junipernetworks.junos.junos_interfaces:
+# running_config: "{{ lookup('file', './parsed.cfg') }}"
+# state: parsed
+# Task Output (redacted)
+# -----------------------
+# "parsed": [
+# {
+# "description": "Configured by Ansible",
+# "duplex": "full-duplex",
+# "enabled": false,
+# "hold_time": {
+# "down": 2200,
+# "up": 2000
+# },
+# "mtu": 1024,
+# "name": "ge-0/0/1",
+# "speed": "100m"
+# }
+# ]
+#
+# Using rendered
+- name: Render platform specific xml from task input using rendered state
+ junipernetworks.junos.junos_interfaces:
+ config:
+ - name: ge-0/0/2
+ description: Configured by Ansibull
+ mtu: 2048
+ speed: 20m
+ hold_time:
+ up: 3200
+ down: 3200
+ state: rendered
+# Task Output (redacted)
+# -----------------------
+# "rendered": <nc:interfaces
+# xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# <nc:interface>
+# <nc:name>ge-0/0/2</nc:name>
+# <nc:description>Configured by Ansibull</nc:description>
+# <nc:speed>20m</nc:speed>
+# <nc:mtu>2048</nc:mtu>
+# <nc:hold-time>
+# <nc:up>3200</nc:up>
+# <nc:down>3200</nc:down>
+# </nc:hold-time>
+# </nc:interface>
+# </nc:interfaces>"
+
+"""
+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 version="1.0" encoding="UTF-8"?>
+<rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+ <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+ <interfaces>
+ <interface>
+ <name>ge-0/0/1</name>
+ <description>Configured by Ansible</description>
+ <disable/>
+ <speed>100m</speed>
+ <mtu>1024</mtu>
+ <hold-time>
+ <up>2000</up>
+ <down>2200</down>
+ </hold-time>
+ <link-mode>full-duplex</link-mode>
+ <unit>
+ <name>0</name>
+ <family>
+ <ethernet-switching>
+ <interface-mode>access</interface-mode>
+ <vlan>
+ <members>vlan100</members>
+ </vlan>
+ </ethernet-switching>
+ </family>
+ </unit>
+ </interface>
+ </interfaces>
+ </configuration>
+</rpc-reply>', 'xml 2', 'xml 3']
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.interfaces.interfaces import (
+ InterfacesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.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", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_l2_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_l2_interfaces.py
new file mode 100644
index 000000000..d5def410b
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_l2_interfaces.py
@@ -0,0 +1,697 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_l2_interfaces
+short_description: L2 interfaces resource module
+description: This module provides declarative management of a Layer-2 interface on
+ Juniper JUNOS devices.
+version_added: 1.0.0
+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
+ elements: str
+ 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
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show interfaces).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - parsed
+ - rendered
+ 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)."
+ junipernetworks.junos.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)
+ junipernetworks.junos.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
+ junipernetworks.junos.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
+ junipernetworks.junos.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 ];
+# }
+# }
+# }
+# }
+# Using gathered
+# Before state:
+# ------------
+#
+# user@junos01# show interfaces
+# ge-0/0/1 {
+# description "Configured by Ansible";
+# disable;
+# speed 100m;
+# mtu 1024;
+# hold-time up 2000 down 2200;
+# link-mode full-duplex;
+# unit 0 {
+# family ethernet-switching {
+# interface-mode access;
+# vlan {
+# members vlan100;
+# }
+# }
+# }
+# }
+# ge-0/0/2 {
+# description "Configured by Ansible";
+# native-vlan-id 400;
+# speed 10m;
+# mtu 2048;
+# hold-time up 3000 down 3200;
+# unit 0 {
+# family ethernet-switching {
+# interface-mode trunk;
+# vlan {
+# members [ vlan200 vlan300 ];
+# }
+# }
+# }
+# }
+# em1 {
+# description TEST;
+# }
+# fxp0 {
+# description ANSIBLE;
+# speed 1g;
+# link-mode automatic;
+# unit 0 {
+# family inet {
+# address 10.8.38.38/24;
+# }
+# }
+# }
+- name: Gather junos layer 2 interfaces as in given arguments
+ junipernetworks.junos.junos_l2_interfaces:
+ state: gathered
+# Task Output (redacted)
+# -----------------------
+#
+# "gathered": [
+# {
+# "access": {
+# "vlan": "vlan100"
+# },
+# "enhanced_layer": true,
+# "name": "ge-0/0/1",
+# "unit": 0
+# },
+# {
+# "enhanced_layer": true,
+# "name": "ge-0/0/2",
+# "trunk": {
+# "allowed_vlans": [
+# "vlan200",
+# "vlan300"
+# ],
+# "native_vlan": "400"
+# },
+# "unit": 0
+# }
+# ]
+# After state:
+# ------------
+#
+# user@junos01# show interfaces
+# ge-0/0/1 {
+# description "Configured by Ansible";
+# disable;
+# speed 100m;
+# mtu 1024;
+# hold-time up 2000 down 2200;
+# link-mode full-duplex;
+# unit 0 {
+# family ethernet-switching {
+# interface-mode access;
+# vlan {
+# members vlan100;
+# }
+# }
+# }
+# }
+# ge-0/0/2 {
+# description "Configured by Ansible";
+# native-vlan-id 400;
+# speed 10m;
+# mtu 2048;
+# hold-time up 3000 down 3200;
+# unit 0 {
+# family ethernet-switching {
+# interface-mode trunk;
+# vlan {
+# members [ vlan200 vlan300 ];
+# }
+# }
+# }
+# }
+# em1 {
+# description TEST;
+# }
+# fxp0 {
+# description ANSIBLE;
+# speed 1g;
+# link-mode automatic;
+# unit 0 {
+# family inet {
+# address 10.8.38.38/24;
+# }
+# }
+# }
+# Using parsed
+# parsed.cfg
+# ------------
+#
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <interfaces>
+# <interface>
+# <name>ge-0/0/1</name>
+# <description>Configured by Ansible</description>
+# <disable/>
+# <speed>100m</speed>
+# <mtu>1024</mtu>
+# <hold-time>
+# <up>2000</up>
+# <down>2200</down>
+# </hold-time>
+# <link-mode>full-duplex</link-mode>
+# <unit>
+# <name>0</name>
+# <family>
+# <ethernet-switching>
+# <interface-mode>access</interface-mode>
+# <vlan>
+# <members>vlan100</members>
+# </vlan>
+# </ethernet-switching>
+# </family>
+# </unit>
+# </interface>
+# </interfaces>
+# </configuration>
+# </rpc-reply>
+# - name: Convert interfaces config to argspec without connecting to the appliance
+# junipernetworks.junos.junos_l2_interfaces:
+# running_config: "{{ lookup('file', './parsed.cfg') }}"
+# state: parsed
+# Task Output (redacted)
+# -----------------------
+# "parsed": [
+# {
+# "access": {
+# "vlan": "vlan100"
+# },
+# "enhanced_layer": true,
+# "name": "ge-0/0/1",
+# "unit": 0
+# },
+# {
+# "enhanced_layer": true,
+# "name": "ge-0/0/2",
+# "trunk": {
+# "allowed_vlans": [
+# "vlan200",
+# "vlan300"
+# ],
+# "native_vlan": "400"
+# },
+# "unit": 0
+# }
+# ]
+#
+# Using rendered
+- name: Render platform specific xml from task input using rendered state
+ junipernetworks.junos.junos_l2_interfaces:
+ config:
+ - name: ge-0/0/1
+ access:
+ vlan: vlan100
+ - name: ge-0/0/2
+ trunk:
+ allowed_vlans:
+ - vlan200
+ - vlan300
+ native_vlan: '400'
+ state: rendered
+# Task Output (redacted)
+# -----------------------
+# "rendered": "<nc:interfaces
+# xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# <nc:interface>
+# <nc:name>ge-0/0/1</nc:name>
+# <nc:unit>
+# <nc:name>0</nc:name>
+# <nc:family>
+# <nc:ethernet-switching>
+# <nc:interface-mode>access</nc:interface-mode>
+# <nc:vlan>
+# <nc:members>vlan100</nc:members>
+# </nc:vlan>
+# </nc:ethernet-switching>
+# </nc:family>
+# </nc:unit>
+# </nc:interface>
+# <nc:interface>
+# <nc:name>ge-0/0/2</nc:name>
+# <nc:unit>
+# <nc:name>0</nc:name>
+# <nc:family>
+# <nc:ethernet-switching>
+# <nc:interface-mode>trunk</nc:interface-mode>
+# <nc:vlan>
+# <nc:members>vlan200</nc:members>
+# <nc:members>vlan300</nc:members>
+# </nc:vlan>
+# </nc:ethernet-switching>
+# </nc:family>
+# </nc:unit>
+# <nc:native-vlan-id>400</nc:native-vlan-id>
+# </nc:interface>
+# </nc:interfaces>"
+
+"""
+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: ['<nc:interfaces
+ xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ <nc:interface>
+ <nc:name>ge-0/0/1</nc:name>
+ <nc:unit>
+ <nc:name>0</nc:name>
+ <nc:family>
+ <nc:ethernet-switching>
+ <nc:interface-mode>access</nc:interface-mode>
+ <nc:vlan>
+ <nc:members>vlan100</nc:members>
+ </nc:vlan>
+ </nc:ethernet-switching>
+ </nc:family>
+ </nc:unit>
+ </nc:interface>
+ <nc:interface>
+ <nc:name>ge-0/0/2</nc:name>
+ <nc:unit>
+ <nc:name>0</nc:name>
+ <nc:family>
+ <nc:ethernet-switching>
+ <nc:interface-mode>trunk</nc:interface-mode>
+ <nc:vlan>
+ <nc:members>vlan200</nc:members>
+ <nc:members>vlan300</nc:members>
+ </nc:vlan>
+ </nc:ethernet-switching>
+ </nc:family>
+ </nc:unit>
+ <nc:native-vlan-id>400</nc:native-vlan-id>
+ </nc:interface>
+ </nc:interfaces>', 'xml 2', 'xml 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.l2_interfaces.l2_interfaces import (
+ L2_interfacesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.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", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_l3_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_l3_interfaces.py
new file mode 100644
index 000000000..3e59e0844
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_l3_interfaces.py
@@ -0,0 +1,777 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_l3_interfaces
+short_description: L3 interfaces resource module
+description: This module provides declarative management of a Layer 3 interface on
+ Juniper JUNOS devices
+version_added: 1.0.0
+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
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show interfaces).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ state:
+ description:
+ - The state of the configuration after module completion
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ 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
+ junipernetworks.junos.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)
+ junipernetworks.junos.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
+ junipernetworks.junos.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
+ junipernetworks.junos.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;
+# }
+# }
+# }
+# Using gathered
+# Before state:
+# ------------
+#
+# user@junos01# show interfaces
+# ge-0/0/1 {
+# description "Configured by Ansible";
+# disable;
+# speed 100m;
+# mtu 1024;
+# hold-time up 2000 down 2200;
+# link-mode full-duplex;
+# unit 0 {
+# family ethernet-switching {
+# interface-mode access;
+# vlan {
+# members vlan100;
+# }
+# }
+# }
+# }
+# ge-0/0/2 {
+# description "Configured by Ansible";
+# native-vlan-id 400;
+# speed 10m;
+# mtu 2048;
+# hold-time up 3000 down 3200;
+# unit 0 {
+# family ethernet-switching {
+# interface-mode trunk;
+# vlan {
+# members [ vlan200 vlan300 ];
+# }
+# }
+# }
+# }
+# ge-1/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.1/24;
+# address 10.200.16.20/24;
+# }
+# family inet6;
+# }
+# }
+# ge-2/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.2/24;
+# address 10.200.16.21/24;
+# }
+# family inet6;
+# }
+# }
+# ge-3/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.3/24;
+# address 10.200.16.22/24;
+# }
+# family inet6;
+# }
+# }
+# em1 {
+# description TEST;
+# }
+# fxp0 {
+# description ANSIBLE;
+# speed 1g;
+# link-mode automatic;
+# unit 0 {
+# family inet {
+# address 10.8.38.38/24;
+# }
+# }
+# }
+- name: Gather junos layer3 interfaces as in given arguments
+ junipernetworks.junos.junos_l3_interfaces:
+ state: gathered
+# Task Output (redacted)
+# -----------------------
+#
+# "gathered": [
+# {
+# "ipv4": [
+# {
+# "address": "192.168.100.1/24"
+# },
+# {
+# "address": "10.200.16.20/24"
+# }
+# ],
+# "name": "ge-1/0/0",
+# "unit": "0"
+# },
+# {
+# "ipv4": [
+# {
+# "address": "192.168.100.2/24"
+# },
+# {
+# "address": "10.200.16.21/24"
+# }
+# ],
+# "name": "ge-2/0/0",
+# "unit": "0"
+# },
+# {
+# "ipv4": [
+# {
+# "address": "192.168.100.3/24"
+# },
+# {
+# "address": "10.200.16.22/24"
+# }
+# ],
+# "name": "ge-3/0/0",
+# "unit": "0"
+# },
+# {
+# "ipv4": [
+# {
+# "address": "10.8.38.38/24"
+# }
+# ],
+# "name": "fxp0",
+# "unit": "0"
+# }
+# ]
+# After state:
+# ------------
+#
+# user@junos01# show interfaces
+# ge-0/0/1 {
+# description "Configured by Ansible";
+# disable;
+# speed 100m;
+# mtu 1024;
+# hold-time up 2000 down 2200;
+# link-mode full-duplex;
+# unit 0 {
+# family ethernet-switching {
+# interface-mode access;
+# vlan {
+# members vlan100;
+# }
+# }
+# }
+# }
+# ge-0/0/2 {
+# description "Configured by Ansible";
+# native-vlan-id 400;
+# speed 10m;
+# mtu 2048;
+# hold-time up 3000 down 3200;
+# unit 0 {
+# family ethernet-switching {
+# interface-mode trunk;
+# vlan {
+# members [ vlan200 vlan300 ];
+# }
+# }
+# }
+# }
+# ge-1/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.1/24;
+# address 10.200.16.20/24;
+# }
+# family inet6;
+# }
+# }
+# ge-2/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.2/24;
+# address 10.200.16.21/24;
+# }
+# family inet6;
+# }
+# }
+# ge-3/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.3/24;
+# address 10.200.16.22/24;
+# }
+# family inet6;
+# }
+# }
+# em1 {
+# description TEST;
+# }
+# fxp0 {
+# description ANSIBLE;
+# speed 1g;
+# link-mode automatic;
+# unit 0 {
+# family inet {
+# address 10.8.38.38/24;
+# }
+# }
+# }
+# Using parsed
+# parsed.cfg
+# ------------
+#
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <interfaces>
+# <interface>
+# <name>ge-1/0/0</name>
+# <unit>
+# <name>0</name>
+# <family>
+# <inet>
+# <address>
+# <name>192.168.100.1/24</name>
+# </address>
+# <address>
+# <name>10.200.16.20/24</name>
+# </address>
+# </inet>
+# <inet6></inet6>
+# </family>
+# </unit>
+# </interface>
+# <interface>
+# <name>ge-2/0/0</name>
+# <unit>
+# <name>0</name>
+# <family>
+# <inet>
+# <address>
+# <name>192.168.100.2/24</name>
+# </address>
+# <address>
+# <name>10.200.16.21/24</name>
+# </address>
+# </inet>
+# <inet6></inet6>
+# </family>
+# </unit>
+# </interface>
+# </interfaces>
+# </configuration>
+# </rpc-reply>
+# - name: Convert interfaces config to argspec without connecting to the appliance
+# junipernetworks.junos.junos_l3_interfaces:
+# running_config: "{{ lookup('file', './parsed.cfg') }}"
+# state: parsed
+# Task Output (redacted)
+# -----------------------
+# "parsed": [
+# {
+# "ipv4": [
+# {
+# "address": "192.168.100.1/24"
+# },
+# {
+# "address": "10.200.16.20/24"
+# }
+# ],
+# "name": "ge-1/0/0",
+# "unit": "0"
+# },
+# {
+# "ipv4": [
+# {
+# "address": "192.168.100.2/24"
+# },
+# {
+# "address": "10.200.16.21/24"
+# }
+# ],
+# "name": "ge-2/0/0",
+# "unit": "0"
+# }
+# ]
+#
+# Using rendered
+- name: Render platform specific xml from task input using rendered state
+ junipernetworks.junos.junos_l3_interfaces:
+ config:
+ - name: ge-1/0/0
+ ipv4:
+ - address: 192.168.100.1/24
+ - address: 10.200.16.20/24
+ unit: 0
+
+ - name: ge-2/0/0
+ ipv4:
+ - address: 192.168.100.2/24
+ - address: 10.200.16.21/24
+ unit: 0
+ state: rendered
+# Task Output (redacted)
+# -----------------------
+# "rendered": "<nc:interfaces
+# xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# <nc:interface>
+# <nc:name>ge-1/0/0</nc:name>
+# <nc:unit>
+# <nc:name>0</nc:name>
+# <nc:family>
+# <nc:inet>
+# <nc:address>
+# <nc:name>192.168.100.1/24</nc:name>
+# </nc:address>
+# <nc:address>
+# <nc:name>10.200.16.20/24</nc:name>
+# </nc:address>
+# </nc:inet>
+# </nc:family>
+# </nc:unit>
+# </nc:interface>
+# <nc:interface>
+# <nc:name>ge-2/0/0</nc:name>
+# <nc:unit>
+# <nc:name>0</nc:name>
+# <nc:family>
+# <nc:inet>
+# <nc:address>
+# <nc:name>192.168.100.2/24</nc:name>
+# </nc:address>
+# <nc:address>
+# <nc:name>10.200.16.21/24</nc:name>
+# </nc:address>
+# </nc:inet>
+# </nc:family>
+# </nc:unit>
+# </nc:interface>
+# </nc:interfaces>"
+
+"""
+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: ['<nc:interfaces
+ xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ <nc:interface>
+ <nc:name>ge-1/0/0</nc:name>
+ <nc:unit>
+ <nc:name>0</nc:name>
+ <nc:family>
+ <nc:inet>
+ <nc:address>
+ <nc:name>192.168.100.1/24</nc:name>
+ </nc:address>
+ <nc:address>
+ <nc:name>10.200.16.20/24</nc:name>
+ </nc:address>
+ </nc:inet>
+ </nc:family>
+ </nc:unit>
+</nc:interfaces>', 'xml 2', 'xml 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.l3_interfaces.l3_interfaces import (
+ L3_interfacesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.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", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_lacp.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_lacp.py
new file mode 100644
index 000000000..b2636f285
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_lacp.py
@@ -0,0 +1,305 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_lacp
+short_description: Global Link Aggregation Control Protocol (LACP) Junos resource
+ module
+description: This module provides declarative management of global LACP on Juniper
+ Junos network devices.
+version_added: 1.0.0
+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
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show chassis aggregated-devices ethernet lacp).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ state:
+ description:
+ - The state of the configuration after module completion
+ type: str
+ choices:
+ - merged
+ - replaced
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ 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
+ junipernetworks.junos.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
+ junipernetworks.junos.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
+ junipernetworks.junos.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;
+#
+# Using gathered
+# Before state:
+# ------------
+#
+# ansible@cm123456tr21# show chassis aggregated-devices ethernet lacp
+# system-priority 63;
+# link-protection;
+
+- name: Gather junos lacp as in given arguments
+ junipernetworks.junos.junos_lacp:
+ state: gathered
+# Task Output (redacted)
+# -----------------------
+#
+# "gathered": {
+# "link_protection": "revertive",
+# "system_priority": 63
+# }
+# After state:
+# ------------
+#
+# ansible@cm123456tr21# show chassis aggregated-devices ethernet lacp
+# system-priority 63;
+# link-protection;
+# Using rendered
+- name: Render platform specific xml from task input using rendered state
+ junipernetworks.junos.junos_lacp:
+ config:
+ system_priority: 63
+ link_protection: revertive
+ state: rendered
+# Task Output (redacted)
+# -----------------------
+# "rendered": "<nc:chassis
+# xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# <nc:aggregated-devices>
+# <nc:ethernet>
+# <nc:lacp>
+# <nc:system-priority>63</nc:system-priority>
+# <nc:link-protection>
+# <nc:non-revertive delete=\"delete\"/>
+# </nc:link-protection>
+# </nc:lacp>
+# </nc:ethernet>
+# </nc:aggregated-devices>
+# </nc:chassis>
+#
+# Using parsed
+# parsed.cfg
+# ------------
+#
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <chassis>
+# <aggregated-devices>
+# <ethernet>
+# <lacp>
+# <system-priority>63</system-priority>
+# <link-protection>
+# </link-protection>
+# </lacp>
+# </ethernet>
+# </aggregated-devices>
+# </chassis>
+# </configuration>
+# </rpc-reply>
+# - name: Convert lacp config to argspec without connecting to the appliance
+# junipernetworks.junos.junos_lacp:
+# running_config: "{{ lookup('file', './parsed.cfg') }}"
+# state: parsed
+# Task Output (redacted)
+# -----------------------
+# "parsed": {
+# "link_protection": "revertive",
+# "system_priority": 63
+# }
+
+"""
+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: ['<nc:chassis
+ xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ <nc:aggregated-devices>
+ <nc:ethernet>
+ <nc:lacp>
+ <nc:system-priority>63</nc:system-priority>
+ <nc:link-protection>
+ <nc:non-revertive delete=\"delete\"/>
+ </nc:link-protection>
+ </nc:lacp>
+ </nc:ethernet>
+ </nc:aggregated-devices>
+</nc:chassis>', 'xml 2', 'xml 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.lacp.lacp import (
+ LacpArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_lacp_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_lacp_interfaces.py
new file mode 100644
index 000000000..0c05a0c54
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_lacp_interfaces.py
@@ -0,0 +1,967 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_lacp_interfaces
+short_description: LACP interfaces resource module
+description:
+- This module manages Link Aggregation Control Protocol (LACP) attributes of interfaces
+ on Juniper JUNOS devices.
+version_added: 1.0.0
+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
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show interface).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ description:
+ - The state of the configuration after module completion.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - parsed
+ - rendered
+ 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
+ junipernetworks.junos.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
+ junipernetworks.junos.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
+ junipernetworks.junos.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)"
+ junipernetworks.junos.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;
+# }
+# }
+# }
+# Using gathered
+# Before state:
+# ------------
+#
+# user@junos01# show interfaces
+# ansible@cm123456tr21# show interfaces
+# ge-0/0/1 {
+# ether-options {
+# 802.3ad {
+# lacp {
+# force-up;
+# port-priority 100;
+# }
+# ae1;
+# }
+# }
+# }
+# ge-0/0/2 {
+# ether-options {
+# 802.3ad ae1;
+# }
+# }
+# ge-0/0/3 {
+# ether-options {
+# 802.3ad ae2;
+# }
+# }
+# ge-0/0/4 {
+# ether-options {
+# 802.3ad ae2;
+# }
+# }
+# ge-1/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.1/24;
+# address 10.200.16.20/24;
+# }
+# family inet6;
+# }
+# }
+# ge-2/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.2/24;
+# address 10.200.16.21/24;
+# }
+# family inet6;
+# }
+# }
+# ge-3/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.3/24;
+# address 10.200.16.22/24;
+# }
+# family inet6;
+# }
+# }
+# ae1 {
+# description "Configured by Ansible";
+# aggregated-ether-options {
+# lacp {
+# periodic fast;
+# sync-reset enable;
+# system-priority 100;
+# system-id 00:00:00:00:00:02;
+# }
+# }
+# }
+# ae2 {
+# description "Configured by Ansible";
+# }
+# em1 {
+# description TEST;
+# }
+# fxp0 {
+# description ANSIBLE;
+# speed 1g;
+# link-mode automatic;
+# unit 0 {
+# family inet {
+# address 10.8.38.38/24;
+# }
+# }
+# }
+- name: Gather junos lacp interfaces as in given arguments
+ junipernetworks.junos.junos_lacp_interfaces:
+ state: gathered
+# Task Output (redacted)
+# -----------------------
+#
+# "gathered": [
+# {
+# "force_up": true,
+# "name": "ge-0/0/1",
+# "port_priority": 100
+# },
+# {
+# "name": "ae1",
+# "period": "fast",
+# "sync_reset": "enable",
+# "system": {
+# "mac": {
+# "address": "00:00:00:00:00:02"
+# },
+# "priority": 100
+# }
+# }
+# ]
+# After state:
+# ------------
+#
+# ansible@cm123456tr21# show interfaces
+# ge-0/0/1 {
+# ether-options {
+# 802.3ad {
+# lacp {
+# force-up;
+# port-priority 100;
+# }
+# ae1;
+# }
+# }
+# }
+# ge-0/0/2 {
+# ether-options {
+# 802.3ad ae1;
+# }
+# }
+# ge-0/0/3 {
+# ether-options {
+# 802.3ad ae2;
+# }
+# }
+# ge-0/0/4 {
+# ether-options {
+# 802.3ad ae2;
+# }
+# }
+# ge-1/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.1/24;
+# address 10.200.16.20/24;
+# }
+# family inet6;
+# }
+# }
+# ge-2/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.2/24;
+# address 10.200.16.21/24;
+# }
+# family inet6;
+# }
+# }
+# ge-3/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.3/24;
+# address 10.200.16.22/24;
+# }
+# family inet6;
+# }
+# }
+# ae1 {
+# description "Configured by Ansible";
+# aggregated-ether-options {
+# lacp {
+# periodic fast;
+# sync-reset enable;
+# system-priority 100;
+# system-id 00:00:00:00:00:02;
+# }
+# }
+# }
+# ae2 {
+# description "Configured by Ansible";
+# }
+# em1 {
+# description TEST;
+# }
+# fxp0 {
+# description ANSIBLE;
+# speed 1g;
+# link-mode automatic;
+# unit 0 {
+# family inet {
+# address 10.8.38.38/24;
+# }
+# }
+# }
+# Using parsed
+# parsed.cfg
+# ------------
+#
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <interfaces>
+# <interface>
+# <name>ge-0/0/1</name>
+# <ether-options>
+# <ieee-802.3ad>
+# <lacp>
+# <force-up/>
+# <port-priority>100</port-priority>
+# </lacp>
+# <bundle>ae1</bundle>
+# </ieee-802.3ad>
+# </ether-options>
+# </interface>
+# <interface>
+# <name>ge-0/0/2</name>
+# <ether-options>
+# <ieee-802.3ad>
+# <bundle>ae1</bundle>
+# </ieee-802.3ad>
+# </ether-options>
+# </interface>
+# <interface>
+# <name>ge-0/0/3</name>
+# <ether-options>
+# <ieee-802.3ad>
+# <bundle>ae2</bundle>
+# </ieee-802.3ad>
+# </ether-options>
+# </interface>
+# <interface>
+# <name>ge-0/0/4</name>
+# <ether-options>
+# <ieee-802.3ad>
+# <bundle>ae2</bundle>
+# </ieee-802.3ad>
+# </ether-options>
+# </interface>
+# <interface>
+# <name>ge-1/0/0</name>
+# <unit>
+# <name>0</name>
+# <family>
+# <inet>
+# <address>
+# <name>192.168.100.1/24</name>
+# </address>
+# <address>
+# <name>10.200.16.20/24</name>
+# </address>
+# </inet>
+# <inet6>
+# </inet6>
+# </family>
+# </unit>
+# </interface>
+# <interface>
+# <name>ge-2/0/0</name>
+# <unit>
+# <name>0</name>
+# <family>
+# <inet>
+# <address>
+# <name>192.168.100.2/24</name>
+# </address>
+# <address>
+# <name>10.200.16.21/24</name>
+# </address>
+# </inet>
+# <inet6>
+# </inet6>
+# </family>
+# </unit>
+# </interface>
+# <interface>
+# <name>ge-3/0/0</name>
+# <unit>
+# <name>0</name>
+# <family>
+# <inet>
+# <address>
+# <name>192.168.100.3/24</name>
+# </address>
+# <address>
+# <name>10.200.16.22/24</name>
+# </address>
+# </inet>
+# <inet6>
+# </inet6>
+# </family>
+# </unit>
+# </interface>
+# <interface>
+# <name>ae1</name>
+# <description>Configured by Ansible</description>
+# <aggregated-ether-options>
+# <lacp>
+# <periodic>fast</periodic>
+# <sync-reset>enable</sync-reset>
+# <system-priority>100</system-priority>
+# <system-id>00:00:00:00:00:02</system-id>
+# </lacp>
+# </aggregated-ether-options>
+# </interface>
+# <interface>
+# <name>ae2</name>
+# <description>Configured by Ansible</description>
+# </interface>
+# <interface>
+# <name>em1</name>
+# <description>TEST</description>
+# </interface>
+# <interface>
+# <name>fxp0</name>
+# <description>ANSIBLE</description>
+# <speed>1g</speed>
+# <link-mode>automatic</link-mode>
+# <unit>
+# <name>0</name>
+# <family>
+# <inet>
+# <address>
+# <name>10.8.38.38/24</name>
+# </address>
+# </inet>
+# </family>
+# </unit>
+# </interface>
+# </interfaces>
+# </configuration>
+# </rpc-reply>
+# - name: Convert interfaces config to argspec without connecting to the appliance
+# junipernetworks.junos.junos_lacp_interfaces:
+# running_config: "{{ lookup('file', './parsed.cfg') }}"
+# state: parsed
+# Task Output (redacted)
+# -----------------------
+# "parsed": [
+# {
+# "force_up": true,
+# "name": "ge-0/0/1",
+# "port_priority": 100
+# },
+# {
+# "name": "ae1",
+# "period": "fast",
+# "sync_reset": "enable",
+# "system": {
+# "mac": {
+# "address": "00:00:00:00:00:02"
+# },
+# "priority": 100
+# }
+# }
+# ]
+# Using rendered
+- name: Render platform specific xml from task input using rendered state
+ junipernetworks.junos.junos_lacp_interfaces:
+ config:
+ - name: ae1
+ period: fast
+ sync_reset: enable
+ system:
+ priority: 100
+ mac:
+ address: 00:00:00:00:00:02
+
+ - name: ge-0/0/1
+ port_priority: 100
+ force_up: true
+ state: rendered
+# Task Output (redacted)
+# -----------------------
+# "rendered": "<nc:interfaces
+# xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# <nc:interface>
+# <nc:name>ae1</nc:name>
+# <nc:aggregated-ether-options>
+# <nc:lacp>
+# <nc:periodic>fast</nc:periodic>
+# <nc:sync-reset>enable</nc:sync-reset>
+# <nc:system-id>00:00:00:00:00:02</nc:system-id>
+# <nc:system-priority>100</nc:system-priority>
+# </nc:lacp>
+# </nc:aggregated-ether-options>
+# </nc:interface>
+# <nc:interface>
+# <nc:name>ge-0/0/1</nc:name>
+# <nc:ether-options>
+# <nc:ieee-802.3ad>
+# <nc:lacp>
+# <nc:port-priority>100</nc:port-priority>
+# <nc:force-up/>
+# </nc:lacp>
+# </nc:ieee-802.3ad>
+# </nc:ether-options>
+# </nc:interface>
+# </nc:interfaces>"
+
+"""
+
+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: ['<nc:interfaces
+ xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ <nc:interface>
+ <nc:name>ae1</nc:name>
+ <nc:aggregated-ether-options>
+ <nc:lacp>
+ <nc:periodic>fast</nc:periodic>
+ <nc:sync-reset>enable</nc:sync-reset>
+ <nc:system-id>00:00:00:00:00:02</nc:system-id>
+ <nc:system-priority>100</nc:system-priority>
+ </nc:lacp>
+ </nc:aggregated-ether-options>
+ </nc:interface>
+ <nc:interface>
+ <nc:name>ge-0/0/1</nc:name>
+ <nc:ether-options>
+ <nc:ieee-802.3ad>
+ <nc:lacp>
+ <nc:port-priority>100</nc:port-priority>
+ <nc:force-up/>
+ </nc:lacp>
+ </nc:ieee-802.3ad>
+ </nc:ether-options>
+ </nc:interface>
+</nc:interfaces>', 'xml 2', 'xml 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.lacp_interfaces.lacp_interfaces import (
+ Lacp_interfacesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.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", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_lag_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_lag_interfaces.py
new file mode 100644
index 000000000..81efca836
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_lag_interfaces.py
@@ -0,0 +1,887 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_lag_interfaces
+short_description: Link Aggregation Juniper JUNOS resource module
+description: This module manages properties of Link Aggregation Group on Juniper JUNOS
+ devices.
+version_added: 1.0.0
+author: Ganesh Nalawade (@ganeshrn)
+options:
+ config:
+ description: A list of link aggregation group configurations.
+ type: list
+ elements: dict
+ 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.
+ type: str
+ 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
+ elements: dict
+ 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.
+ type: str
+ choices:
+ - primary
+ - backup
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show interfaces).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ state:
+ description:
+ - The state of the configuration after module completion
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ 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)"
+ junipernetworks.junos.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
+ junipernetworks.junos.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
+ junipernetworks.junos.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
+ junipernetworks.junos.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";
+# }
+# Using gathered
+# Before state:
+# ------------
+#
+# ansible@cm123456tr21# show interfaces
+# ge-0/0/1 {
+# ether-options {
+# 802.3ad ae1;
+# }
+# }
+# ge-0/0/2 {
+# ether-options {
+# 802.3ad ae1;
+# }
+# }
+# ge-0/0/3 {
+# ether-options {
+# 802.3ad {
+# ae2;
+# primary;
+# }
+# }
+# }
+# ge-0/0/4 {
+# ether-options {
+# 802.3ad {
+# ae2;
+# backup;
+# }
+# }
+# }
+# ge-1/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.1/24;
+# address 10.200.16.20/24;
+# }
+# family inet6;
+# }
+# }
+# ge-2/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.2/24;
+# address 10.200.16.21/24;
+# }
+# family inet6;
+# }
+# }
+# ge-3/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.3/24;
+# address 10.200.16.22/24;
+# }
+# family inet6;
+# }
+# }
+# ae1 {
+# description "Configured by Ansible";
+# aggregated-ether-options {
+# lacp {
+# active;
+# }
+# }
+# }
+# ae2 {
+# description "Configured by Ansible";
+# aggregated-ether-options {
+# link-protection;
+# lacp {
+# passive;
+# }
+# }
+# }
+# em1 {
+# description TEST;
+# }
+# fxp0 {
+# description ANSIBLE;
+# speed 1g;
+# link-mode automatic;
+# unit 0 {
+# family inet {
+# address 10.8.38.38/24;
+# }
+# }
+# }
+- name: Gather junos lag interfaces as in given arguments
+ junipernetworks.junos.junos_lag_interfaces:
+ state: gathered
+# Task Output (redacted)
+# -----------------------
+#
+# "gathered": [
+# {
+# "members": [
+# {
+# "member": "ge-0/0/1"
+# },
+# {
+# "member": "ge-0/0/2"
+# }
+# ],
+# "mode": "active",
+# "name": "ae1"
+# },
+# {
+# "link_protection": true,
+# "members": [
+# {
+# "link_type": "primary",
+# "member": "ge-0/0/3"
+# },
+# {
+# "link_type": "backup",
+# "member": "ge-0/0/4"
+# }
+# ],
+# "mode": "passive",
+# "name": "ae2"
+# }
+# ]
+# After state:
+# ------------
+#
+# ansible@cm123456tr21# show interfaces
+# ge-0/0/1 {
+# ether-options {
+# 802.3ad ae1;
+# }
+# }
+# ge-0/0/2 {
+# ether-options {
+# 802.3ad ae1;
+# }
+# }
+# ge-0/0/3 {
+# ether-options {
+# 802.3ad {
+# ae2;
+# primary;
+# }
+# }
+# }
+# ge-0/0/4 {
+# ether-options {
+# 802.3ad {
+# ae2;
+# backup;
+# }
+# }
+# }
+# ge-1/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.1/24;
+# address 10.200.16.20/24;
+# }
+# family inet6;
+# }
+# }
+# ge-2/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.2/24;
+# address 10.200.16.21/24;
+# }
+# family inet6;
+# }
+# }
+# ge-3/0/0 {
+# unit 0 {
+# family inet {
+# address 192.168.100.3/24;
+# address 10.200.16.22/24;
+# }
+# family inet6;
+# }
+# }
+# ae1 {
+# description "Configured by Ansible";
+# aggregated-ether-options {
+# lacp {
+# active;
+# }
+# }
+# }
+# ae2 {
+# description "Configured by Ansible";
+# aggregated-ether-options {
+# link-protection;
+# lacp {
+# passive;
+# }
+# }
+# }
+# em1 {
+# description TEST;
+# }
+# fxp0 {
+# description ANSIBLE;
+# speed 1g;
+# link-mode automatic;
+# unit 0 {
+# family inet {
+# address 10.8.38.38/24;
+# }
+# }
+# }
+# Using parsed
+# parsed.cfg
+# ------------
+#
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <interfaces>
+# <interface>
+# <name>ge-0/0/1</name>
+# <ether-options>
+# <ieee-802.3ad>
+# <bundle>ae1</bundle>
+# </ieee-802.3ad>
+# </ether-options>
+# </interface>
+# <interface>
+# <name>ge-0/0/2</name>
+# <ether-options>
+# <ieee-802.3ad>
+# <bundle>ae1</bundle>
+# </ieee-802.3ad>
+# </ether-options>
+# </interface>
+# <interface>
+# <name>ge-0/0/3</name>
+# <ether-options>
+# <ieee-802.3ad>
+# <bundle>ae2</bundle>
+# <primary/>
+# </ieee-802.3ad>
+# </ether-options>
+# </interface>
+# <interface>
+# <name>ge-0/0/4</name>
+# <ether-options>
+# <ieee-802.3ad>
+# <bundle>ae2</bundle>
+# <backup/>
+# </ieee-802.3ad>
+# </ether-options>
+# </interface>
+# <interface>
+# <name>ge-1/0/0</name>
+# <unit>
+# <name>0</name>
+# <family>
+# <inet>
+# <address>
+# <name>192.168.100.1/24</name>
+# </address>
+# <address>
+# <name>10.200.16.20/24</name>
+# </address>
+# </inet>
+# <inet6>
+# </inet6>
+# </family>
+# </unit>
+# </interface>
+# <interface>
+# <name>ge-2/0/0</name>
+# <unit>
+# <name>0</name>
+# <family>
+# <inet>
+# <address>
+# <name>192.168.100.2/24</name>
+# </address>
+# <address>
+# <name>10.200.16.21/24</name>
+# </address>
+# </inet>
+# <inet6>
+# </inet6>
+# </family>
+# </unit>
+# </interface>
+# <interface>
+# <name>ge-3/0/0</name>
+# <unit>
+# <name>0</name>
+# <family>
+# <inet>
+# <address>
+# <name>192.168.100.3/24</name>
+# </address>
+# <address>
+# <name>10.200.16.22/24</name>
+# </address>
+# </inet>
+# <inet6>
+# </inet6>
+# </family>
+# </unit>
+# </interface>
+# <interface>
+# <name>ae1</name>
+# <description>Configured by Ansible</description>
+# <aggregated-ether-options>
+# <lacp>
+# <active/>
+# </lacp>
+# </aggregated-ether-options>
+# </interface>
+# <interface>
+# <name>ae2</name>
+# <description>Configured by Ansible</description>
+# <aggregated-ether-options>
+# <link-protection>
+# </link-protection>
+# <lacp>
+# <passive/>
+# </lacp>
+# </aggregated-ether-options>
+# </interface>
+# <interface>
+# <name>em1</name>
+# <description>TEST</description>
+# </interface>
+# <interface>
+# <name>fxp0</name>
+# <description>ANSIBLE</description>
+# <speed>1g</speed>
+# <link-mode>automatic</link-mode>
+# <unit>
+# <name>0</name>
+# <family>
+# <inet>
+# <address>
+# <name>10.8.38.38/24</name>
+# </address>
+# </inet>
+# </family>
+# </unit>
+# </interface>
+# </interfaces>
+# </configuration>
+# </rpc-reply>
+# - name: Convert interfaces config to argspec without connecting to the appliance
+# junipernetworks.junos.junos_lag_interfaces:
+# running_config: "{{ lookup('file', './parsed.cfg') }}"
+# state: parsed
+# Task Output (redacted)
+# -----------------------
+# "parsed": [
+# {
+# "members": [
+# {
+# "member": "ge-0/0/1"
+# },
+# {
+# "member": "ge-0/0/2"
+# }
+# ],
+# "mode": "active",
+# "name": "ae1"
+# },
+# {
+# "link_protection": true,
+# "members": [
+# {
+# "link_type": "primary",
+# "member": "ge-0/0/3"
+# },
+# {
+# "link_type": "backup",
+# "member": "ge-0/0/4"
+# }
+# ],
+# "mode": "passive",
+# "name": "ae2"
+# }
+# ]
+# Using rendered
+- name: Render platform specific xml from task input using rendered state
+ junipernetworks.junos.junos_lag_interfaces:
+ config:
+ - name: ae1
+ members:
+ - member: ge-0/0/1
+ - member: ge-0/0/2
+ mode: active
+
+ - name: ae2
+ link_protection: true
+ members:
+ - member: ge-0/0/3
+ link_type: primary
+ - member: ge-0/0/4
+ link_type: backup
+ mode: passive
+# Task Output (redacted)
+# -----------------------
+# "rendered": "<nc:interfaces
+# xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# <nc:interface>
+# <nc:name>ae1</nc:name>
+# <nc:aggregated-ether-options>
+# <nc:lacp>
+# <nc:active/>
+# </nc:lacp>
+# </nc:aggregated-ether-options>
+# </nc:interface>
+# <nc:interface>
+# <nc:name>ge-0/0/1</nc:name>
+# <nc:ether-options>
+# <nc:ieee-802.3ad>
+# <nc:bundle>ae1</nc:bundle>
+# </nc:ieee-802.3ad>
+# </nc:ether-options>
+# </nc:interface>
+# <nc:interface>
+# <nc:name>ge-0/0/2</nc:name>
+# <nc:ether-options>
+# <nc:ieee-802.3ad>
+# <nc:bundle>ae1</nc:bundle>
+# </nc:ieee-802.3ad>
+# </nc:ether-options>
+# </nc:interface>
+# <nc:interface>
+# <nc:name>ae2</nc:name>
+# <nc:aggregated-ether-options>
+# <nc:lacp>
+# <nc:passive/>
+# </nc:lacp>
+# <nc:link-protection/>
+# </nc:aggregated-ether-options>
+# </nc:interface>
+# <nc:interface>
+# <nc:name>ge-0/0/3</nc:name>
+# <nc:ether-options>
+# <nc:ieee-802.3ad>
+# <nc:bundle>ae2</nc:bundle>
+# <nc:primary/>
+# </nc:ieee-802.3ad>
+# </nc:ether-options>
+# </nc:interface>
+# <nc:interface>
+# <nc:name>ge-0/0/4</nc:name>
+# <nc:ether-options>
+# <nc:ieee-802.3ad>
+# <nc:bundle>ae2</nc:bundle>
+# <nc:backup/>
+# </nc:ieee-802.3ad>
+# </nc:ether-options>
+# </nc:interface>
+# </nc:interfaces>"
+
+"""
+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: ['<nc:interfaces
+ xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ <nc:interface>
+ <nc:name>ae1</nc:name>
+ <nc:aggregated-ether-options>
+ <nc:lacp>
+ <nc:active/>
+ </nc:lacp>
+ </nc:aggregated-ether-options>
+ </nc:interface>
+ <nc:interface>
+ <nc:name>ge-0/0/1</nc:name>
+ <nc:ether-options>
+ <nc:ieee-802.3ad>
+ <nc:bundle>ae1</nc:bundle>
+ </nc:ieee-802.3ad>
+ </nc:ether-options>
+ </nc:interface>
+ <nc:interface>
+ <nc:name>ge-0/0/2</nc:name>
+ <nc:ether-options>
+ <nc:ieee-802.3ad>
+ <nc:bundle>ae1</nc:bundle>
+ </nc:ieee-802.3ad>
+ </nc:ether-options>
+ </nc:interface>
+ <nc:interface>
+ <nc:name>ae2</nc:name>
+ <nc:aggregated-ether-options>
+ <nc:lacp>
+ <nc:passive/>
+ </nc:lacp>
+ <nc:link-protection/>
+ </nc:aggregated-ether-options>
+ </nc:interface>
+ <nc:interface>
+ <nc:name>ge-0/0/3</nc:name>
+ <nc:ether-options>
+ <nc:ieee-802.3ad>
+ <nc:bundle>ae2</nc:bundle>
+ <nc:primary/>
+ </nc:ieee-802.3ad>
+ </nc:ether-options>
+ </nc:interface>
+ <nc:interface>
+ <nc:name>ge-0/0/4</nc:name>
+ <nc:ether-options>
+ <nc:ieee-802.3ad>
+ <nc:bundle>ae2</nc:bundle>
+ <nc:backup/>
+ </nc:ieee-802.3ad>
+ </nc:ether-options>
+ </nc:interface>
+</nc:interfaces>', 'xml 2', 'xml 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.lag_interfaces.lag_interfaces import (
+ Lag_interfacesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.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", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_lldp_global.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_lldp_global.py
new file mode 100644
index 000000000..ebf826ce6
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_lldp_global.py
@@ -0,0 +1,331 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_lldp_global
+short_description: LLDP resource module
+description:
+- This module manages link layer discovery protocol (LLDP) attributes on Juniper JUNOS
+ devices.
+version_added: 1.0.0
+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
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show protocols lldp).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ state:
+ description:
+ - The state of the configuration after module completion.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ 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
+ junipernetworks.junos.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
+ junipernetworks.junos.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)
+ junipernetworks.junos.junos_lldp_global:
+ state: deleted
+
+# After state:
+# -------------
+# user@junos01# # show protocols lldp
+#
+#
+# Using gathered
+# Before state:
+# ------------
+#
+# ansible@cm123456tr21# show protocols lldp
+# management-address 10.1.1.1;
+# advertisement-interval 10000;
+# transmit-delay 400;
+# hold-multiplier 10;
+# interface ge-0/0/1;
+# interface ge-0/0/2 {
+# disable;
+# }
+- name: Gather junos lldp_global as in given arguments
+ junipernetworks.junos.junos_lldp_global:
+ state: gathered
+# Task Output (redacted)
+# -----------------------
+#
+# "gathered": {
+# "address": "10.1.1.1",
+# "hold_multiplier": 10,
+# "interval": 10000,
+# "transmit_delay": 400
+# }
+# After state:
+# ------------
+#
+# ansible@cm123456tr21# show protocols lldp
+# management-address 10.1.1.1;
+# advertisement-interval 10000;
+# transmit-delay 400;
+# hold-multiplier 10;
+# interface ge-0/0/1;
+# interface ge-0/0/2 {
+# disable;
+# }
+# Using rendered
+- name: Render platform specific xml from task input using rendered state
+ junipernetworks.junos.junos_lldp_global:
+ config:
+ interval: 10000
+ address: 10.1.1.1
+ transmit_delay: 400
+ hold_multiplier: 10
+ state: rendered
+# Task Output (redacted)
+# -----------------------
+# "rendered": "<nc:protocols
+# xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# <nc:lldp>
+# <nc:management-address>10.1.1.1</nc:management-address>
+# <nc:advertisement-interval>10000</nc:advertisement-interval>
+# <nc:transmit-delay>400</nc:transmit-delay>
+# <nc:hold-multiplier>10</nc:hold-multiplier>
+# <nc:disable delete=\"delete\"/>
+# </nc:lldp>
+# </nc:protocols>"
+#
+# parsed.cfg
+# ------------
+#
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <protocols>
+# <ospf>
+# <area>
+# <name>0.0.0.0</name>
+# <interface>
+# <name>ge-0/0/0.0</name>
+# </interface>
+# </area>
+# </ospf>
+# <lldp>
+# <management-address>10.1.1.1</management-address>
+# <advertisement-interval>10000</advertisement-interval>
+# <transmit-delay>400</transmit-delay>
+# <hold-multiplier>10</hold-multiplier>
+# <interface>
+# <name>ge-0/0/1</name>
+# </interface>
+# <interface>
+# <name>ge-0/0/2</name>
+# <disable/>
+# </interface>
+# </lldp>
+# </protocols>
+# </configuration>
+# </rpc-reply>
+# - name: Convert lldp global config to argspec without connecting to the appliance
+# junipernetworks.junos.junos_lldp_global:
+# running_config: "{{ lookup('file', './parsed.cfg') }}"
+# state: parsed
+# Task Output (redacted)
+# -----------------------
+# "parsed": {
+# "address": "10.1.1.1",
+# "hold_multiplier": 10,
+# "interval": 10000,
+# "transmit_delay": 400
+# }
+"""
+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: ['<nc:protocols
+ xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ <nc:lldp>
+ <nc:management-address>10.1.1.1</nc:management-address>
+ <nc:advertisement-interval>10000</nc:advertisement-interval>
+ <nc:transmit-delay>400</nc:transmit-delay>
+ <nc:hold-multiplier>10</nc:hold-multiplier>
+ <nc:disable delete=\"delete\"/>
+ </nc:lldp>
+</nc:protocols>', 'xml 2', 'xml 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.lldp_global.lldp_global import (
+ Lldp_globalArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_lldp_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_lldp_interfaces.py
new file mode 100644
index 000000000..b3d1b61ed
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_lldp_interfaces.py
@@ -0,0 +1,359 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_lldp_interfaces
+short_description: LLDP interfaces resource module
+description:
+- This module manages link layer discovery protocol (LLDP) attributes of interfaces
+ on Juniper JUNOS devices.
+version_added: 1.0.0
+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
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show protocols lldp).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ state:
+ description:
+ - The state of the configuration after module completion.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ 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
+ junipernetworks.junos.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
+ junipernetworks.junos.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
+ junipernetworks.junos.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)
+ junipernetworks.junos.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;
+# Using gathered
+# Before state:
+# ------------
+#
+#ansible@cm123456tr21# show protocols lldp
+# interface ge-0/0/1;
+# interface ge-0/0/2 {
+# disable;
+# }
+- name: Gather junos lldp interfaces as in given arguments
+ junipernetworks.junos.junos_lldp_interfaces:
+ state: gathered
+# Task Output (redacted)
+# -----------------------
+#
+# "gathered": [
+# {
+# "name": "ge-0/0/1"
+# },
+# {
+# "enabled": false,
+# "name": "ge-0/0/2"
+# }
+# ]
+# After state:
+# ------------
+#
+#ansible@cm123456tr21# show protocols lldp
+# interface ge-0/0/1;
+# interface ge-0/0/2 {
+# disable;
+# }
+# Using rendered
+- name: Render platform specific xml from task input using rendered state
+ junipernetworks.junos.junos_lldp_interfaces:
+ config:
+ - name: ge-0/0/1
+ - name: ge-0/0/2
+ enabled: false
+ state: rendered
+# Task Output (redacted)
+# -----------------------
+# "rendered": "<nc:protocols
+# xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# <nc:lldp>
+# <nc:interface>
+# <nc:name>ge-0/0/1</nc:name>
+# <nc:disable delete=\"delete\"/>
+# </nc:interface>
+# <nc:interface>
+# <nc:name>ge-0/0/2</nc:name>
+# <nc:disable/>
+# </nc:interface>
+# </nc:lldp>
+# </nc:protocols>"
+# Using parsed
+# parsed.cfg
+# ------------
+#
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <protocols>
+# <ospf>
+# <area>
+# <name>0.0.0.0</name>
+# <interface>
+# <name>ge-0/0/0.0</name>
+# </interface>
+# </area>
+# </ospf>
+# <lldp>
+# <interface>
+# <name>ge-0/0/1</name>
+# </interface>
+# <interface>
+# <name>ge-0/0/2</name>
+# <disable/>
+# </interface>
+# </lldp>
+# </protocols>
+# </configuration>
+# </rpc-reply>
+# - name: Convert lldp interfaces config to argspec without connecting to the appliance
+# junipernetworks.junos.junos_lldp_interfaces:
+# running_config: "{{ lookup('file', './parsed.cfg') }}"
+# state: parsed
+# Task Output (redacted)
+# -----------------------
+# "parsed": [
+# {
+# "name": "ge-0/0/1"
+# },
+# {
+# "enabled": false,
+# "name": "ge-0/0/2"
+# }
+# ]
+"""
+
+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: ['<nc:protocols
+ xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ <nc:lldp>
+ <nc:interface>
+ <nc:name>ge-0/0/1</nc:name>
+ <nc:disable delete=\"delete\"/>
+ </nc:interface>
+ <nc:interface>
+ <nc:name>ge-0/0/2</nc:name>
+ <nc:disable/>
+ </nc:interface>
+ </nc:lldp>
+</nc:protocols>', 'xml 2', 'xml 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.lldp_interfaces.lldp_interfaces import (
+ Lldp_interfacesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.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", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_logging.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_logging.py
new file mode 100644
index 000000000..c2713a855
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_logging.py
@@ -0,0 +1,403 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_logging
+author: Ganesh Nalawade (@ganeshrn)
+short_description: Manage logging on network devices
+description:
+- This module provides declarative management of logging on Juniper JUNOS devices.
+version_added: 1.0.0
+extends_documentation_fragment:
+- junipernetworks.junos.junos
+deprecated:
+ alternative: junos_logging_global
+ why: Updated module released with more functionality.
+ removed_at_date: '2023-08-01'
+options:
+ dest:
+ description:
+ - Destination of the logs.
+ choices:
+ - console
+ - host
+ - file
+ - user
+ type: str
+ 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.
+ type: str
+ facility:
+ description:
+ - Set logging facility.
+ type: str
+ level:
+ description:
+ - Set logging severity levels.
+ type: str
+ aggregate:
+ description:
+ - List of logging definitions.
+ type: list
+ elements: dict
+ suboptions:
+ dest:
+ description:
+ - Destination of the logs.
+ choices:
+ - console
+ - host
+ - file
+ - user
+ type: str
+ 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.
+ type: str
+ facility:
+ description:
+ - Set logging facility.
+ type: str
+ level:
+ description:
+ - Set logging severity levels.
+ type: str
+ state:
+ description:
+ - State of the logging configuration.
+ type: str
+ choices:
+ - present
+ - absent
+ active:
+ description:
+ - Specifies whether or not the configuration is active or deactivated
+ 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.
+ type: int
+ 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.
+ type: int
+ 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.
+ type: int
+ required: false
+ state:
+ description:
+ - State of the logging configuration.
+ default: present
+ type: str
+ 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.
+ type: int
+ 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
+ type: int
+ 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.
+ type: int
+ 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.
+"""
+
+EXAMPLES = """
+- name: configure console logging
+ junipernetworks.junos.junos_logging:
+ dest: console
+ facility: any
+ level: critical
+
+- name: remove console logging configuration
+ junipernetworks.junos.junos_logging:
+ dest: console
+ state: absent
+
+- name: configure file logging
+ junipernetworks.junos.junos_logging:
+ dest: file
+ name: test
+ facility: pfe
+ level: error
+
+- name: configure logging parameter
+ junipernetworks.junos.junos_logging:
+ files: 30
+ size: 65536
+ rotate_frequency: 10
+
+- name: Configure file logging using aggregate
+ junipernetworks.junos.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
+ junipernetworks.junos.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._text import to_text
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.common.validation import check_required_if
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_default_spec,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ map_obj_to_ele,
+ map_params_to_obj,
+ to_param_list,
+ tostring,
+)
+
+
+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"),
+ 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)
+
+ 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]
+
+ try:
+ check_required_if(required_if, param)
+ except TypeError as exc:
+ module.fail_json(to_text(exc))
+
+ 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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_logging_global.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_logging_global.py
new file mode 100644
index 000000000..bd4cdaadf
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_logging_global.py
@@ -0,0 +1,1743 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2021 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_logging_global
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+---
+module: junos_logging_global
+version_added: 2.4.0
+short_description: Manage logging configuration on Junos devices.
+description: This module manages logging configuration on devices running Junos.
+author: Rohit Thakur (@rohitthakur2590)
+requirements:
+ - ncclient (>=v0.6.4)
+ - xmltodict (>=0.12.0)
+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,https://docs.ansible.com/ansible/latest/network/user_guide/platform_junos.html).
+ - Tested against JunOS v18.4R1
+options:
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show system syslog).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ config:
+ description: A dictionary of logging configuration.
+ type: dict
+ suboptions:
+ allow_duplicates: &allow_duplicates
+ description: Do not suppress the repeated message for all targets.
+ type: bool
+ archive:
+ description: Specify archive file information.
+ type: dict
+ suboptions:
+ set:
+ description: Set archive file information.
+ type: bool
+ binary_data:
+ description: Mark file as if it contains binary data.
+ type: bool
+ files:
+ description: Specify number of files to be archived (1..1000).
+ type: int
+ no_binary_data:
+ description: Don't mark file as if it contains binary data.
+ type: bool
+ no_world_readable:
+ description: Don't allow any user to read the log file.
+ type: bool
+ file_size:
+ description: Size of files to be archived (65536..1073741824 bytes).
+ type: str
+ world_readable:
+ description: Allow any user to read the log file.
+ type: bool
+ console:
+ description: Set console logging parameters.
+ type: dict
+ suboptions:
+ any: &any
+ description: Set All facilities.
+ type: dict
+ suboptions:
+ level: &level
+ description: Set severity logging level.
+ type: str
+ required: true
+ choices: ["alert", "any", "critical", "emergency", "error", "info", "none", "notice", "warning"]
+ authorization: &authorization
+ description: Specify authorization system.
+ type: dict
+ suboptions:
+ level: *level
+ change_log: &change_log
+ description: Specify configuration change log.
+ type: dict
+ suboptions:
+ level: *level
+ conflict_log: &conflict_log
+ description: Specify configuration conflict log.
+ type: dict
+ suboptions:
+ level: *level
+ daemon: &daemon
+ description: Specify various system processes.
+ type: dict
+ suboptions:
+ level: *level
+ dfc: &dfc
+ description: Specify dynamic flow capture.
+ type: dict
+ suboptions:
+ level: *level
+ external: &external
+ description: Specify Local external applications.
+ type: dict
+ suboptions:
+ level: *level
+ firewall: &firewall
+ description: Specify Firewall filtering system.
+ type: dict
+ suboptions:
+ level: *level
+ ftp: &ftp
+ description: Specify FTP process.
+ type: dict
+ suboptions:
+ level: *level
+ interactive_commands: &interactive_commands
+ description: Specify commands executed by the UI.
+ type: dict
+ suboptions:
+ level: *level
+ kernel: &kernel
+ description: Specify Kernel specific logging.
+ type: dict
+ suboptions:
+ level: *level
+ ntp: &ntp
+ description: Specify NTP process specific logging.
+ type: dict
+ suboptions:
+ level: *level
+ pfe: &pfe
+ description: Specify Packet Forwarding Engine specific logging.
+ type: dict
+ suboptions:
+ level: *level
+ security: &security
+ description: Specify Security related logging.
+ type: dict
+ suboptions:
+ level: *level
+ user: &user
+ description: Specify user specific logging.
+ type: dict
+ suboptions:
+ level: *level
+ files:
+ description: Specify files logging.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify filename in which to log data.
+ type: str
+ allow_duplicates: *allow_duplicates
+ any: *any
+ archive:
+ description: Specify archive file information.
+ type: dict
+ suboptions:
+ set:
+ description: Set archive file information.
+ type: bool
+ archive_sites:
+ description: Specify Primary and failover URLs to receive archive facilities.
+ type: list
+ elements: str
+ binary_data:
+ description: Mark file as if it contains binary data.
+ type: bool
+ files:
+ description: Specify number of files to be archived (1..1000).
+ type: int
+ no_binary_data:
+ description: Don't mark file as if it contains binary data.
+ type: bool
+ no_world_readable:
+ description: Don't allow any user to read the log file.
+ type: bool
+ file_size:
+ description: Size of files to be archived (65536..1073741824 bytes).
+ type: str
+ start_time:
+ description: Specify start time for file transmission (yyyy-mm-dd.hh:mm).
+ type: str
+ transfer_interval:
+ description: Specify frequency at which to transfer files to archive sites (5..2880 minutes).
+ type: int
+ world_readable:
+ description: Allow any user to read the log file.
+ type: bool
+ authorization: *authorization
+ change_log: *change_log
+ conflict_log: *conflict_log
+ daemon: *daemon
+ dfc: *dfc
+ explicit_priority: &explicit_priority
+ description: Include priority and facility in messages.
+ type: bool
+ external: *external
+ firewall: *firewall
+ ftp: *ftp
+ interactive_commands: *interactive_commands
+ kernel: *kernel
+ match: &match
+ description: Specify regular expression for lines to be logged.
+ type: str
+ match_strings: &match_strings
+ description: Specify matching string(s) for lines to be logged.
+ type: list
+ elements: str
+ ntp: *ntp
+ pfe: *pfe
+ security: *security
+ structured_data: &structured_data
+ description: Specify Log system message in structured format.
+ type: dict
+ suboptions:
+ set:
+ description: Set Log system message in structured format.
+ type: bool
+ brief:
+ description: Omit English-language text from end of logged messages.
+ type: bool
+ user: *user
+ hosts: &hosts
+ description: Specify hosts to be notified.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify the host name.
+ type: str
+ allow_duplicates: *allow_duplicates
+ any: *any
+ authorization: *authorization
+ change_log: *change_log
+ conflict_log: *conflict_log
+ daemon: *daemon
+ dfc: *dfc
+ exclude_hostname:
+ description: Specify exclude hostname field in messages.
+ type: bool
+ explicit_priority: *explicit_priority
+ external: *external
+ facility_override:
+ description: Specify alternate facility for logging to remote host.
+ type: str
+ firewall: *firewall
+ ftp: *ftp
+ interactive_commands: *interactive_commands
+ kernel: *kernel
+ log_prefix:
+ description: Prefix for all logging to this host.
+ type: str
+ match: *match
+ match_strings: *match_strings
+ ntp: *ntp
+ pfe: *pfe
+ port:
+ description: Specify port number.
+ type: int
+ routing_instance:
+ description: Specify routing-instance.
+ type: str
+ security: *security
+ source_address:
+ description: Specify address as source address.
+ type: str
+ structured_data: *structured_data
+ user: *user
+ log_rotate_frequency:
+ description: Specify Rotate log frequency (1..59 minutes).
+ type: int
+ routing_instance:
+ description: Specify Routing routing-instance.
+ type: str
+ server:
+ description: Specify syslog server logging.
+ type: dict
+ suboptions:
+ set:
+ description: Enable syslog server.
+ type: bool
+ routing_instance:
+ description: nable/disable syslog server in routing-instances.
+ type: dict
+ suboptions:
+ all:
+ description: Enable/disable all routing instances.
+ type: bool
+ default:
+ description: Enable/disable default routing instances.
+ type: bool
+ routing_instances:
+ description: Specify routing-instances.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify routing-instance name.
+ type: str
+ disable:
+ description: Disable syslog server in this routing instances.
+ type: bool
+ source_address:
+ description: Specify address as source address.
+ type: str
+ time_format:
+ description: Specify additional information to include in system log timestamp.
+ type: dict
+ suboptions:
+ set:
+ description: Set time-format
+ type: bool
+ millisecond:
+ description: Include milliseconds in timestamp.
+ type: bool
+ year:
+ description: Include year in timestamp.
+ type: bool
+ users:
+ description: Specify user logging
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify user name.
+ type: str
+ allow_duplicates: *allow_duplicates
+ any: *any
+ authorization: *authorization
+ change_log: *change_log
+ conflict_log: *conflict_log
+ daemon: *daemon
+ dfc: *dfc
+ external: *external
+ firewall: *firewall
+ ftp: *ftp
+ interactive_commands: *interactive_commands
+ kernel: *kernel
+ match:
+ description: Specify regular expression for lines to be logged.
+ type: str
+ match_strings:
+ description: Specify matching string(s) for lines to be logged.
+ type: list
+ elements: str
+ ntp: *ntp
+ pfe: *pfe
+ security: *security
+ user: *user
+ state:
+ description:
+ - The state the configuration should be left in.
+ - Refer to examples for more details.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - deleted
+ - overridden
+ - parsed
+ - gathered
+ - rendered
+ default: merged
+"""
+EXAMPLES = """
+# Using merged
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show system syslog
+#
+# [edit]
+# vagrant@vsrx# show routing-instances
+# inst11 {
+# description inst11;
+# }
+- name: Merge provided logging configuration into running configuration.
+ junipernetworks.junos.junos_logging_global:
+ config:
+ allow_duplicates: true
+ archive:
+ set: true
+ no_binary_data: true
+ files: 10
+ file_size: 65578
+ no_world_readable: true
+ console:
+ any:
+ level: "info"
+ authorization:
+ level: "any"
+ change_log:
+ level: "critical"
+ ftp:
+ level: "none"
+ files:
+ - name: "file101"
+ allow_duplicates: true
+ - name: "file102"
+ allow_duplicates: true
+ any:
+ level: "any"
+ structured_data:
+ set: true
+ - name: "file103"
+ archive:
+ set: true
+ no_binary_data: true
+ files: 10
+ file_size: 65578
+ no_world_readable: true
+ explicit_priority: true
+ match: "^set*"
+ match_strings:
+ - "^delete"
+ - "^prompt"
+ hosts:
+ - name: host111
+ exclude_hostname: true
+ allow_duplicates: true
+ any:
+ level: "any"
+ structured_data:
+ set: true
+ brief: true
+ facility_override: "ftp"
+ log_prefix: "field"
+ match: "^set*"
+ match_strings:
+ - "^delete"
+ - "^prompt"
+ port: 1231
+ routing_instance: "inst11"
+ source_address: "11.1.1.11"
+ routing_instance: "inst11"
+ log_rotate_frequency: 45
+ source_address: "33.33.33.33"
+ time_format:
+ millisecond: true
+ year: true
+ users:
+ - name: "user1"
+ allow_duplicates: true
+ - name: "user2"
+ allow_duplicates: true
+ any:
+ level: "any"
+ user:
+ level: info
+ state: merged
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "allow_duplicates": true,
+# "archive": {
+# "file_size": 65578,
+# "files": 10,
+# "no_binary_data": true,
+# "no_world_readable": true
+# },
+# "console": {
+# "any": {
+# "level": "info"
+# },
+# "authorization": {
+# "level": "any"
+# },
+# "change_log": {
+# "level": "critical"
+# },
+# "ftp": {
+# "level": "none"
+# }
+# },
+# "files": [
+# {
+# "allow_duplicates": true,
+# "name": "file101"
+# },
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "name": "file102",
+# "structured_data": {
+# "set": true
+# }
+# },
+# {
+# "archive": {
+# "file_size": 65578,
+# "files": 10,
+# "no_binary_data": true,
+# "no_world_readable": true
+# },
+# "explicit_priority": true,
+# "match": "^set*",
+# "match_strings": [
+# "^delete",
+# "^prompt"
+# ],
+# "name": "file103"
+# }
+# ],
+# "hosts": [
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "exclude_hostname": true,
+# "facility_override": "ftp",
+# "log_prefix": "field",
+# "match": "^set*",
+# "match_strings": [
+# "^delete",
+# "^prompt"
+# ],
+# "name": "host111",
+# "port": 1231,
+# "routing_instance": "inst11",
+# "source_address": "11.1.1.11",
+# "structured_data": {
+# "brief": true
+# }
+# }
+# ],
+# "log_rotate_frequency": 45,
+# "routing_instance": "inst11",
+# "source_address": "33.33.33.33",
+# "time_format": {
+# "millisecond": true,
+# "year": true
+# },
+# "users": [
+# {
+# "allow_duplicates": true,
+# "name": "user1"
+# },
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "name": "user2",
+# "user": {
+# "level": "info"
+# }
+# }
+# ]
+# },
+# "before": {},
+# "changed": true,
+# "commands": [
+# "<nc:system xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:syslog><nc:allow-duplicates/><nc:archive><nc:files>10</nc:files>"
+# "<nc:no-binary-data/><nc:size>65578</nc:size><nc:no-world-readable/></nc:archive>"
+# "<nc:console><nc:name>change-log</nc:name><nc:critical/></nc:console><nc:console>"
+# "<nc:name>any</nc:name><nc:info/></nc:console><nc:console><nc:name>authorization</nc:name>"
+# "<nc:any/></nc:console><nc:console><nc:name>ftp</nc:name><nc:none/></nc:console><nc:file>"
+# "<nc:name>file101</nc:name><nc:allow-duplicates/></nc:file><nc:file><nc:name>file102</nc:name>"
+# "<nc:allow-duplicates/><nc:contents><nc:name>any</nc:name><nc:any/></nc:contents><nc:structured-data/>"
+# "</nc:file><nc:file><nc:name>file103</nc:name><nc:archive><nc:files>10</nc:files><nc:no-binary-data/>"
+# "<nc:size>65578</nc:size><nc:no-world-readable/></nc:archive><nc:explicit-priority/>"
+# "<nc:match>^set*</nc:match><nc:match-strings>^delete</nc:match-strings>"
+# "<nc:match-strings>^prompt</nc:match-strings></nc:file><nc:host><nc:name>host111</nc:name>"
+# "<nc:allow-duplicates/><nc:contents><nc:name>any</nc:name><nc:any/></nc:contents>"
+# "<nc:exclude-hostname/><nc:facility-override>ftp</nc:facility-override>"
+# "<nc:log-prefix>field</nc:log-prefix><nc:match>^set*</nc:match><nc:match-strings>^delete</nc:match-strings>"
+# "<nc:match-strings>^prompt</nc:match-strings><nc:port>1231</nc:port>"
+# "<nc:routing-instance>inst11</nc:routing-instance><nc:source-address>11.1.1.11</nc:source-address>"
+# "<nc:structured-data><nc:brief/></nc:structured-data></nc:host>"
+# "<nc:log-rotate-frequency>45</nc:log-rotate-frequency><nc:routing-instance>inst11</nc:routing-instance>"
+# "<nc:source-address>33.33.33.33</nc:source-address><nc:time-format><nc:millisecond/>"
+# "<nc:year/></nc:time-format><nc:user><nc:name>user1</nc:name><nc:allow-duplicates/></nc:user>"
+# "<nc:user><nc:name>user2</nc:name><nc:allow-duplicates/><nc:contents><nc:name>any</nc:name><nc:any/>"
+# "</nc:contents><nc:contents><nc:name>user</nc:name><nc:info/></nc:contents></nc:user></nc:syslog></nc:system>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show system syslog
+# archive size 65578 files 10 no-world-readable no-binary-data;
+# user user1 {
+# allow-duplicates;
+# }
+# user user2 {
+# any any;
+# user info;
+# allow-duplicates;
+# }
+# host host111 {
+# any any;
+# match "^set*";
+# allow-duplicates;
+# port 1231;
+# facility-override ftp;
+# log-prefix field;
+# source-address 11.1.1.11;
+# routing-instance inst11;
+# exclude-hostname;
+# match-strings [ "^delete" "^prompt" ];
+# structured-data {
+# brief;
+# }
+# }
+# allow-duplicates;
+# file file101 {
+# allow-duplicates;
+# }
+# file file102 {
+# any any;
+# allow-duplicates;
+# structured-data;
+# }
+# file file103 {
+# match "^set*";
+# archive size 65578 files 10 no-world-readable no-binary-data;
+# explicit-priority;
+# match-strings [ "^delete" "^prompt" ];
+# }
+# console {
+# any info;
+# authorization any;
+# ftp none;
+# change-log critical;
+# }
+# time-format year millisecond;
+# source-address 33.33.33.33;
+# routing-instance inst11;
+# log-rotate-frequency 45;
+# Using replaced
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show system syslog
+# archive size 65578 files 10 no-world-readable no-binary-data;
+# user user1 {
+# allow-duplicates;
+# }
+# user user2 {
+# any any;
+# user info;
+# allow-duplicates;
+# }
+# host host111 {
+# any any;
+# match "^set*";
+# allow-duplicates;
+# port 1231;
+# facility-override ftp;
+# log-prefix field;
+# source-address 11.1.1.11;
+# routing-instance inst11;
+# exclude-hostname;
+# match-strings [ "^delete" "^prompt" ];
+# structured-data {
+# brief;
+# }
+# }
+# allow-duplicates;
+# file file101 {
+# allow-duplicates;
+# }
+# file file102 {
+# any any;
+# allow-duplicates;
+# structured-data;
+# }
+# file file103 {
+# match "^set*";
+# archive size 65578 files 10 no-world-readable no-binary-data;
+# explicit-priority;
+# match-strings [ "^delete" "^prompt" ];
+# }
+# console {
+# any info;
+# authorization any;
+# ftp none;
+# change-log critical;
+# }
+# time-format year millisecond;
+# source-address 33.33.33.33;
+# routing-instance inst11;
+# log-rotate-frequency 45;
+- name: Replaced running logging global configuration with provided configuration
+ junipernetworks.junos.junos_logging_global:
+ config:
+ files:
+ - name: "file104"
+ allow_duplicates: true
+ - name: "file102"
+ allow_duplicates: true
+ any:
+ level: "any"
+ structured_data:
+ set: true
+ hosts:
+ - name: host222
+ exclude_hostname: true
+ allow_duplicates: true
+ any:
+ level: "any"
+ structured_data:
+ set: true
+ brief: true
+ facility_override: "ftp"
+ log_prefix: "field"
+ match: "^set*"
+ match_strings:
+ - "^delete"
+ - "^prompt"
+ port: 1231
+ routing_instance: "inst11"
+ source_address: "11.1.1.11"
+ users:
+ - name: "user1"
+ allow_duplicates: true
+ - name: "user2"
+ allow_duplicates: true
+ any:
+ level: "any"
+ user:
+ level: info
+ state: replaced
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "files": [
+# {
+# "allow_duplicates": true,
+# "name": "file104"
+# },
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "name": "file102",
+# "structured_data": {
+# "set": true
+# }
+# }
+# ],
+# "hosts": [
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "exclude_hostname": true,
+# "facility_override": "ftp",
+# "log_prefix": "field",
+# "match": "^set*",
+# "match_strings": [
+# "^delete",
+# "^prompt"
+# ],
+# "name": "host222",
+# "port": 1231,
+# "routing_instance": "inst11",
+# "source_address": "11.1.1.11",
+# "structured_data": {
+# "brief": true
+# }
+# }
+# ],
+# "users": [
+# {
+# "allow_duplicates": true,
+# "name": "user1"
+# },
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "name": "user2",
+# "user": {
+# "level": "info"
+# }
+# }
+# ]
+# },
+# "before": {
+# "allow_duplicates": true,
+# "archive": {
+# "file_size": 65578,
+# "files": 10,
+# "no_binary_data": true,
+# "no_world_readable": true
+# },
+# "console": {
+# "any": {
+# "level": "info"
+# },
+# "authorization": {
+# "level": "any"
+# },
+# "change_log": {
+# "level": "critical"
+# },
+# "ftp": {
+# "level": "none"
+# }
+# },
+# "files": [
+# {
+# "allow_duplicates": true,
+# "name": "file101"
+# },
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "name": "file102",
+# "structured_data": {
+# "set": true
+# }
+# },
+# {
+# "archive": {
+# "file_size": 65578,
+# "files": 10,
+# "no_binary_data": true,
+# "no_world_readable": true
+# },
+# "explicit_priority": true,
+# "match": "^set*",
+# "match_strings": [
+# "^delete",
+# "^prompt"
+# ],
+# "name": "file103"
+# }
+# ],
+# "hosts": [
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "exclude_hostname": true,
+# "facility_override": "ftp",
+# "log_prefix": "field",
+# "match": "^set*",
+# "match_strings": [
+# "^delete",
+# "^prompt"
+# ],
+# "name": "host111",
+# "port": 1231,
+# "routing_instance": "inst11",
+# "source_address": "11.1.1.11",
+# "structured_data": {
+# "brief": true
+# }
+# }
+# ],
+# "log_rotate_frequency": 45,
+# "routing_instance": "inst11",
+# "source_address": "33.33.33.33",
+# "time_format": {
+# "millisecond": true,
+# "year": true
+# },
+# "users": [
+# {
+# "allow_duplicates": true,
+# "name": "user1"
+# },
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "name": "user2",
+# "user": {
+# "level": "info"
+# }
+# }
+# ]
+# },
+# "changed": true,
+# "commands": [
+# "<nc:system xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:syslog delete=\"delete\"/><nc:syslog><nc:file><nc:name>file104</nc:name>"
+# "<nc:allow-duplicates/></nc:file><nc:file><nc:name>file102</nc:name><nc:allow-duplicates/>"
+# "<nc:contents><nc:name>any</nc:name><nc:any/></nc:contents><nc:structured-data/></nc:file>"
+# "<nc:host><nc:name>host222</nc:name><nc:allow-duplicates/><nc:contents><nc:name>any</nc:name>"
+# "<nc:any/></nc:contents><nc:exclude-hostname/><nc:facility-override>ftp</nc:facility-override>"
+# "<nc:log-prefix>field</nc:log-prefix><nc:match>^set*</nc:match>"
+# "<nc:match-strings>^delete</nc:match-strings>"
+# "<nc:match-strings>^prompt</nc:match-strings><nc:port>1231</nc:port>"
+# "<nc:routing-instance>inst11</nc:routing-instance><nc:source-address>11.1.1.11</nc:source-address>"
+# "<nc:structured-data><nc:brief/></nc:structured-data></nc:host><nc:user><nc:name>user1</nc:name>"
+# "<nc:allow-duplicates/></nc:user><nc:user><nc:name>user2</nc:name><nc:allow-duplicates/><nc:contents>"
+# "<nc:name>any</nc:name><nc:any/></nc:contents>"
+# "<nc:contents><nc:name>user</nc:name><nc:info/></nc:contents></nc:user></nc:syslog></nc:system>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show system syslog
+# user user1 {
+# allow-duplicates;
+# }
+# user user2 {
+# any any;
+# user info;
+# allow-duplicates;
+# }
+# host host222 {
+# any any;
+# match "^set*";
+# allow-duplicates;
+# port 1231;
+# facility-override ftp;
+# log-prefix field;
+# source-address 11.1.1.11;
+# routing-instance inst11;
+# exclude-hostname;
+# match-strings [ "^delete" "^prompt" ];
+# structured-data {
+# brief;
+# }
+# }
+# file file104 {
+# allow-duplicates;
+# }
+# file file102 {
+# any any;
+# allow-duplicates;
+# structured-data;
+# }
+# Using overridden
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show system syslog
+# archive size 65578 files 10 no-world-readable no-binary-data;
+# user user1 {
+# allow-duplicates;
+# }
+# user user2 {
+# any any;
+# user info;
+# allow-duplicates;
+# }
+# host host111 {
+# any any;
+# match "^set*";
+# allow-duplicates;
+# port 1231;
+# facility-override ftp;
+# log-prefix field;
+# source-address 11.1.1.11;
+# routing-instance inst11;
+# exclude-hostname;
+# match-strings [ "^delete" "^prompt" ];
+# structured-data {
+# brief;
+# }
+# }
+# allow-duplicates;
+# file file101 {
+# allow-duplicates;
+# }
+# file file102 {
+# any any;
+# allow-duplicates;
+# structured-data;
+# }
+# file file103 {
+# match "^set*";
+# archive size 65578 files 10 no-world-readable no-binary-data;
+# explicit-priority;
+# match-strings [ "^delete" "^prompt" ];
+# }
+# console {
+# any info;
+# authorization any;
+# ftp none;
+# change-log critical;
+# }
+# time-format year millisecond;
+# source-address 33.33.33.33;
+# routing-instance inst11;
+# log-rotate-frequency 45;
+- name: Override running logging global configuration with provided configuration
+ junipernetworks.junos.junos_logging_global:
+ config:
+ files:
+ - name: "file104"
+ allow_duplicates: true
+ - name: "file102"
+ allow_duplicates: true
+ any:
+ level: "any"
+ structured_data:
+ set: true
+ hosts:
+ - name: host222
+ exclude_hostname: true
+ allow_duplicates: true
+ any:
+ level: "any"
+ structured_data:
+ set: true
+ brief: true
+ facility_override: "ftp"
+ log_prefix: "field"
+ match: "^set*"
+ match_strings:
+ - "^delete"
+ - "^prompt"
+ port: 1231
+ routing_instance: "inst11"
+ source_address: "11.1.1.11"
+ users:
+ - name: "user1"
+ allow_duplicates: true
+ - name: "user2"
+ allow_duplicates: true
+ any:
+ level: "any"
+ user:
+ level: info
+ state: overridden
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "files": [
+# {
+# "allow_duplicates": true,
+# "name": "file104"
+# },
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "name": "file102",
+# "structured_data": {
+# "set": true
+# }
+# }
+# ],
+# "hosts": [
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "exclude_hostname": true,
+# "facility_override": "ftp",
+# "log_prefix": "field",
+# "match": "^set*",
+# "match_strings": [
+# "^delete",
+# "^prompt"
+# ],
+# "name": "host222",
+# "port": 1231,
+# "routing_instance": "inst11",
+# "source_address": "11.1.1.11",
+# "structured_data": {
+# "brief": true
+# }
+# }
+# ],
+# "users": [
+# {
+# "allow_duplicates": true,
+# "name": "user1"
+# },
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "name": "user2",
+# "user": {
+# "level": "info"
+# }
+# }
+# ]
+# },
+# "before": {
+# "allow_duplicates": true,
+# "archive": {
+# "file_size": 65578,
+# "files": 10,
+# "no_binary_data": true,
+# "no_world_readable": true
+# },
+# "console": {
+# "any": {
+# "level": "info"
+# },
+# "authorization": {
+# "level": "any"
+# },
+# "change_log": {
+# "level": "critical"
+# },
+# "ftp": {
+# "level": "none"
+# }
+# },
+# "files": [
+# {
+# "allow_duplicates": true,
+# "name": "file101"
+# },
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "name": "file102",
+# "structured_data": {
+# "set": true
+# }
+# },
+# {
+# "archive": {
+# "file_size": 65578,
+# "files": 10,
+# "no_binary_data": true,
+# "no_world_readable": true
+# },
+# "explicit_priority": true,
+# "match": "^set*",
+# "match_strings": [
+# "^delete",
+# "^prompt"
+# ],
+# "name": "file103"
+# }
+# ],
+# "hosts": [
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "exclude_hostname": true,
+# "facility_override": "ftp",
+# "log_prefix": "field",
+# "match": "^set*",
+# "match_strings": [
+# "^delete",
+# "^prompt"
+# ],
+# "name": "host111",
+# "port": 1231,
+# "routing_instance": "inst11",
+# "source_address": "11.1.1.11",
+# "structured_data": {
+# "brief": true
+# }
+# }
+# ],
+# "log_rotate_frequency": 45,
+# "routing_instance": "inst11",
+# "source_address": "33.33.33.33",
+# "time_format": {
+# "millisecond": true,
+# "year": true
+# },
+# "users": [
+# {
+# "allow_duplicates": true,
+# "name": "user1"
+# },
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "name": "user2",
+# "user": {
+# "level": "info"
+# }
+# }
+# ]
+# },
+# "changed": true,
+# "commands": [
+# "<nc:system xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:syslog delete=\"delete\"/><nc:syslog><nc:file><nc:name>file104</nc:name>"
+# "<nc:allow-duplicates/></nc:file><nc:file><nc:name>file102</nc:name><nc:allow-duplicates/>"
+# "<nc:contents><nc:name>any</nc:name><nc:any/></nc:contents><nc:structured-data/></nc:file>"
+# "<nc:host><nc:name>host222</nc:name><nc:allow-duplicates/><nc:contents><nc:name>any</nc:name>"
+# "<nc:any/></nc:contents><nc:exclude-hostname/><nc:facility-override>ftp</nc:facility-override>"
+# "<nc:log-prefix>field</nc:log-prefix><nc:match>^set*</nc:match>"
+# "<nc:match-strings>^delete</nc:match-strings>"
+# "<nc:match-strings>^prompt</nc:match-strings><nc:port>1231</nc:port>"
+# "<nc:routing-instance>inst11</nc:routing-instance><nc:source-address>11.1.1.11</nc:source-address>"
+# "<nc:structured-data><nc:brief/></nc:structured-data></nc:host><nc:user><nc:name>user1</nc:name>"
+# "<nc:allow-duplicates/></nc:user><nc:user><nc:name>user2</nc:name><nc:allow-duplicates/><nc:contents>"
+# "<nc:name>any</nc:name><nc:any/></nc:contents>"
+# "<nc:contents><nc:name>user</nc:name><nc:info/></nc:contents></nc:user></nc:syslog></nc:system>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show system syslog
+# user user1 {
+# allow-duplicates;
+# }
+# user user2 {
+# any any;
+# user info;
+# allow-duplicates;
+# }
+# host host222 {
+# any any;
+# match "^set*";
+# allow-duplicates;
+# port 1231;
+# facility-override ftp;
+# log-prefix field;
+# source-address 11.1.1.11;
+# routing-instance inst11;
+# exclude-hostname;
+# match-strings [ "^delete" "^prompt" ];
+# structured-data {
+# brief;
+# }
+# }
+# file file104 {
+# allow-duplicates;
+# }
+# file file102 {
+# any any;
+# allow-duplicates;
+# structured-data;
+# }
+# Using deleted
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show system syslog
+# user user1 {
+# allow-duplicates;
+# }
+# user user2 {
+# any any;
+# user info;
+# allow-duplicates;
+# }
+# host host222 {
+# any any;
+# match "^set*";
+# allow-duplicates;
+# port 1231;
+# facility-override ftp;
+# log-prefix field;
+# source-address 11.1.1.11;
+# routing-instance inst11;
+# exclude-hostname;
+# match-strings [ "^delete" "^prompt" ];
+# structured-data {
+# brief;
+# }
+# }
+# file file104 {
+# allow-duplicates;
+# }
+# file file102 {
+# any any;
+# allow-duplicates;
+# structured-data;
+# }
+- name: Delete running logging global configuration
+ junipernetworks.junos.junos_logging_global:
+ config:
+ state: deleted
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {},
+# "before": {
+# "files": [
+# {
+# "allow_duplicates": true,
+# "name": "file104"
+# },
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "name": "file102",
+# "structured_data": {
+# "set": true
+# }
+# }
+# ],
+# "hosts": [
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "exclude_hostname": true,
+# "facility_override": "ftp",
+# "log_prefix": "field",
+# "match": "^set*",
+# "match_strings": [
+# "^delete",
+# "^prompt"
+# ],
+# "name": "host222",
+# "port": 1231,
+# "routing_instance": "inst11",
+# "source_address": "11.1.1.11",
+# "structured_data": {
+# "brief": true
+# }
+# }
+# ],
+# "users": [
+# {
+# "allow_duplicates": true,
+# "name": "user1"
+# },
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "name": "user2",
+# "user": {
+# "level": "info"
+# }
+# }
+# ]
+# },
+# "changed": true,
+# "commands": [
+# "<nc:system xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:syslog delete=\"delete\"/></nc:system>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show system syslog
+#
+# [edit]
+# Using gathered
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show system syslog
+# user user1 {
+# allow-duplicates;
+# }
+# user user2 {
+# any any;
+# user info;
+# allow-duplicates;
+# }
+# host host222 {
+# any any;
+# match "^set*";
+# allow-duplicates;
+# port 1231;
+# facility-override ftp;
+# log-prefix field;
+# source-address 11.1.1.11;
+# routing-instance inst11;
+# exclude-hostname;
+# match-strings [ "^delete" "^prompt" ];
+# structured-data {
+# brief;
+# }
+# }
+# file file104 {
+# allow-duplicates;
+# }
+# file file102 {
+# any any;
+# allow-duplicates;
+# structured-data;
+# }
+- name: Gather running logging global configuration
+ junipernetworks.junos.junos_logging_global:
+ state: gathered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "gathered": {
+# "files": [
+# {
+# "allow_duplicates": true,
+# "name": "file104"
+# },
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "name": "file102",
+# "structured_data": {
+# "set": true
+# }
+# }
+# ],
+# "hosts": [
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "exclude_hostname": true,
+# "facility_override": "ftp",
+# "log_prefix": "field",
+# "match": "^set*",
+# "match_strings": [
+# "^delete",
+# "^prompt"
+# ],
+# "name": "host222",
+# "port": 1231,
+# "routing_instance": "inst11",
+# "source_address": "11.1.1.11",
+# "structured_data": {
+# "brief": true
+# }
+# }
+# ],
+# "users": [
+# {
+# "allow_duplicates": true,
+# "name": "user1"
+# },
+# {
+# "allow_duplicates": true,
+# "any": {
+# "level": "any"
+# },
+# "name": "user2",
+# "user": {
+# "level": "info"
+# }
+# }
+# ]
+# },
+# "changed": false,
+# Using rendered
+#
+# Before state
+# ------------
+#
+- name: Render xml for provided facts.
+ junipernetworks.junos.junos_logging_global:
+ config:
+ allow_duplicates: true
+ archive:
+ set: true
+ no_binary_data: true
+ files: 10
+ file_size: 65578
+ no_world_readable: true
+ console:
+ any:
+ level: "info"
+ authorization:
+ level: "any"
+ change_log:
+ level: "critical"
+ ftp:
+ level: "none"
+ files:
+ - name: "file101"
+ allow_duplicates: true
+ - name: "file102"
+ allow_duplicates: true
+ any:
+ level: "any"
+ structured_data:
+ set: true
+ - name: "file103"
+ archive:
+ set: true
+ no_binary_data: true
+ files: 10
+ file_size: 65578
+ no_world_readable: true
+ explicit_priority: true
+ match: "^set*"
+ match_strings:
+ - "^delete"
+ - "^prompt"
+ hosts:
+ - name: host111
+ exclude_hostname: true
+ allow_duplicates: true
+ any:
+ level: "any"
+ structured_data:
+ set: true
+ brief: true
+ facility_override: "ftp"
+ log_prefix: "field"
+ match: "^set*"
+ match_strings:
+ - "^delete"
+ - "^prompt"
+ port: 1231
+ routing_instance: "inst11"
+ source_address: "11.1.1.11"
+ routing_instance: "inst11"
+ log_rotate_frequency: 45
+ source_address: "33.33.33.33"
+ time_format:
+ millisecond: true
+ year: true
+ users:
+ - name: "user1"
+ allow_duplicates: true
+ - name: "user2"
+ allow_duplicates: true
+ any:
+ level: "any"
+ user:
+ level: info
+ state: rendered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "rendered": [
+# "<nc:system xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:syslog><nc:allow-duplicates/><nc:archive><nc:files>10</nc:files>"
+# "<nc:no-binary-data/><nc:size>65578</nc:size><nc:no-world-readable/></nc:archive>"
+# "<nc:console><nc:name>change-log</nc:name><nc:critical/></nc:console><nc:console>"
+# "<nc:name>any</nc:name><nc:info/></nc:console><nc:console><nc:name>authorization</nc:name>"
+# "<nc:any/></nc:console><nc:console><nc:name>ftp</nc:name><nc:none/></nc:console><nc:file>"
+# "<nc:name>file101</nc:name><nc:allow-duplicates/></nc:file><nc:file><nc:name>file102</nc:name>"
+# "<nc:allow-duplicates/><nc:contents><nc:name>any</nc:name><nc:any/></nc:contents><nc:structured-data/>"
+# "</nc:file><nc:file><nc:name>file103</nc:name><nc:archive><nc:files>10</nc:files><nc:no-binary-data/>"
+# "<nc:size>65578</nc:size><nc:no-world-readable/></nc:archive><nc:explicit-priority/>"
+# "<nc:match>^set*</nc:match><nc:match-strings>^delete</nc:match-strings>"
+# "<nc:match-strings>^prompt</nc:match-strings></nc:file><nc:host><nc:name>host111</nc:name>"
+# "<nc:allow-duplicates/><nc:contents><nc:name>any</nc:name><nc:any/></nc:contents>"
+# "<nc:exclude-hostname/><nc:facility-override>ftp</nc:facility-override>"
+# "<nc:log-prefix>field</nc:log-prefix><nc:match>^set*</nc:match><nc:match-strings>^delete</nc:match-strings>"
+# "<nc:match-strings>^prompt</nc:match-strings><nc:port>1231</nc:port>"
+# "<nc:routing-instance>inst11</nc:routing-instance><nc:source-address>11.1.1.11</nc:source-address>"
+# "<nc:structured-data><nc:brief/></nc:structured-data></nc:host>"
+# "<nc:log-rotate-frequency>45</nc:log-rotate-frequency><nc:routing-instance>inst11</nc:routing-instance>"
+# "<nc:source-address>33.33.33.33</nc:source-address><nc:time-format><nc:millisecond/>"
+# "<nc:year/></nc:time-format><nc:user><nc:name>user1</nc:name><nc:allow-duplicates/></nc:user>"
+# "<nc:user><nc:name>user2</nc:name><nc:allow-duplicates/><nc:contents><nc:name>any</nc:name><nc:any/>"
+# "</nc:contents><nc:contents><nc:name>user</nc:name><nc:info/></nc:contents></nc:user></nc:syslog></nc:system>"
+# ]
+# Using parsed
+# parsed.cfg
+# ------------
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <version>18.4R1-S2.4</version>
+# <system xmlns="http://yang.juniper.net/junos-es/conf/system">
+# <syslog>
+# <user>
+# <name>*</name>
+# <contents>
+# <name>any</name>
+# <emergency/>
+# </contents>
+# </user>
+# <file>
+# <name>messages</name>
+# <contents>
+# <name>any</name>
+# <any/>
+# </contents>
+# <contents>
+# <name>authorization</name>
+# <info/>
+# </contents>
+# </file>
+# <file>
+# <name>interactive-commands</name>
+# <contents>
+# <name>interactive-commands</name>
+# <any/>
+# </contents>
+# </file>
+# </syslog>
+# </system>
+# </configuration>
+# </rpc-reply>
+- name: Parse logging global running config
+ junipernetworks.junos.junos_routing_instances:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "parsed": {
+# "files": [
+# {
+# "any": {
+# "level": "any"
+# },
+# "authorization": {
+# "level": "info"
+# },
+# "name": "messages"
+# },
+# {
+# "interactive_commands": {
+# "level": "any"
+# },
+# "name": "interactive-commands"
+# }
+# ],
+# "users": [
+# {
+# "any": {
+# "level": "emergency"
+# },
+# "name": "*"
+# }
+# ]
+# }
+#
+#
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+after:
+ description: The resulting configuration model invocation.
+ returned: when changed
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ['<nc:allow-duplicates/></nc:user><nc:user><nc:name>user2</nc:name>
+ <nc:allow-duplicates/><nc:contents><nc:name>any</nc:name><nc:any/>
+ </nc:contents><nc:contents><nc:name>user</nc:name><nc:info/></nc:contents>
+ </nc:user></nc:syslog></nc:system>"', 'xml 2', 'xml 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.logging_global.logging_global import (
+ Logging_globalArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.logging_global.logging_global import (
+ Logging_global,
+)
+
+
+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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ module = AnsibleModule(
+ argument_spec=Logging_globalArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+ result = Logging_global(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_netconf.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_netconf.py
new file mode 100644
index 000000000..f1b3c4b52
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_netconf.py
@@ -0,0 +1,193 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_netconf
+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.
+version_added: 1.0.0
+extends_documentation_fragment:
+- junipernetworks.junos.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
+ type: int
+ 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.
+ type: str
+ 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
+ junipernetworks.junos.junos_netconf:
+ listens_on: 830
+ state: present
+
+- name: disable netconf service
+ junipernetworks.junos.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.basic import AnsibleModule
+from ansible.module_utils.connection import ConnectionError
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ get_connection,
+)
+
+
+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"]),
+ )
+
+ 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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_ntp_global.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_ntp_global.py
new file mode 100644
index 000000000..0bc72b4d1
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_ntp_global.py
@@ -0,0 +1,1019 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2021 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_logging_global
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+---
+module: junos_ntp_global
+version_added: 2.6.0
+short_description: Manage NTP configuration on Junos devices.
+description: This module manages NTP configuration on devices running Junos.
+author: Rohit Thakur (@rohitthakur2590)
+requirements:
+ - ncclient (>=v0.6.4)
+ - xmltodict (>=0.12.0)
+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,https://docs.ansible.com/ansible/latest/network/user_guide/platform_junos.html).
+ - Tested against JunOS v18.4R1
+options:
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show system syslog).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ config:
+ description: A dictionary of NTP configuration.
+ type: dict
+ suboptions:
+ authentication_keys:
+ description: NTP authentication key.
+ type: list
+ elements: dict
+ suboptions:
+ id:
+ description: Authentication key number.
+ type: int
+ algorithm:
+ description: Authentication key type.
+ type: str
+ choices: ['md5', 'sha1', 'sha256']
+ key:
+ description: Authentication key value.
+ type: str
+ boot_server:
+ description: Server to query during boot sequence.
+ type: str
+ broadcasts:
+ description: Broadcast parameters.
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description: Broadcast or multicast address to use.
+ type: str
+ key:
+ description: Authentication key.
+ type: str
+ routing_instance_name:
+ description: Routing intance name in which interface has address in broadcast subnet.
+ type: str
+ ttl:
+ description: TTL value to transmit.
+ type: int
+ version:
+ description: NTP version to use.
+ type: int
+ broadcast_client:
+ description: Listen to broadcast NTP.
+ type: bool
+ interval_range:
+ description: Set the minpoll and maxpoll interval range.
+ type: int
+ multicast_client:
+ description: Listen to multicast NTP address.
+ type: str
+ peers:
+ description: NTP Peers.
+ type: list
+ elements: dict
+ suboptions: &peers
+ peer:
+ description: Hostname/IP address of the NTP Peer.
+ type: str
+ key_id:
+ description: Key-id to be used while communicating.
+ type: int
+ prefer:
+ description: Prefer this peer.
+ type: bool
+ version:
+ description: NTP version to use.
+ type: int
+ servers:
+ description: NTP Servers.
+ type: list
+ elements: dict
+ suboptions:
+ server:
+ description: IP address or hostname of the server.
+ type: str
+ key_id:
+ description: Key-id to be used while communicating.
+ type: int
+ prefer:
+ description: Prefer this peer_serv.
+ type: bool
+ version:
+ description: NTP version to use.
+ type: int
+ routing_instance:
+ description: Routing instance through which server is reachable.
+ type: str
+ source_addresses:
+ description: Source-Address parameters.
+ type: list
+ elements: dict
+ suboptions:
+ source_address:
+ description: Use specified address as source address.
+ type: str
+ routing_instance:
+ description: Routing intance name in which source address is defined.
+ type: str
+ threshold:
+ description: Set the maximum threshold(sec) allowed for NTP adjustment.
+ type: dict
+ suboptions:
+ value:
+ description: The maximum value(sec) allowed for NTP adjustment.
+ type: int
+ action:
+ description: Select actions for NTP abnormal adjustment.
+ type: str
+ choices: ['accept', 'reject']
+ trusted_keys:
+ description: List of trusted authentication keys.
+ type: list
+ elements: dict
+ suboptions:
+ key_id:
+ description: Trusted-Key number.
+ type: int
+ state:
+ description:
+ - The state the configuration should be left in.
+ - The states I(replaced) and I(overridden) have identical
+ behaviour for this module.
+ - Refer to examples for more details.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - deleted
+ - overridden
+ - parsed
+ - gathered
+ - rendered
+ default: merged
+"""
+EXAMPLES = """
+# Using merged
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show system ntp
+#
+# [edit]
+# vagrant@vsrx# show routing-instances
+# rt1 {
+# description rt1;
+# }
+# rt2 {
+- name: Merge provided NTP configuration into running configuration.
+ junipernetworks.junos.junos_ntp_global:
+ config:
+ boot_server: '78.46.194.186'
+ broadcasts:
+ - address: '172.16.255.255'
+ key: '50'
+ ttl: 200
+ version: 3
+ routing_instance_name: 'rt1'
+ - address: '192.16.255.255'
+ key: '50'
+ ttl: 200
+ version: 3
+ routing_instance_name: 'rt2'
+ broadcast_client: true
+ interval_range: 2
+ multicast_client: "224.0.0.1"
+ peers:
+ - peer: "78.44.194.186"
+ - peer: "172.44.194.186"
+ key_id: 10000
+ prefer: true
+ version: 3
+ servers:
+ - server: "48.46.194.186"
+ key_id: 34
+ prefer: true
+ version: 2
+ routing_instance: 'rt1'
+ - server: "48.45.194.186"
+ key_id: 34
+ prefer: true
+ version: 2
+ source_addresses:
+ - source_address: "172.45.194.186"
+ routing_instance: 'rt1'
+ - source_address: "171.45.194.186"
+ routing_instance: 'rt2'
+ threshold:
+ value: 300
+ action: "accept"
+ trusted_keys:
+ - key_id: 3000
+ - key_id: 2000
+ state: merged
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "boot_server": "78.46.194.186",
+# "broadcast_client": true,
+# "broadcasts": [
+# {
+# "address": "172.16.255.255",
+# "key": "50",
+# "routing_instance_name": "rt1",
+# "ttl": 200,
+# "version": 3
+# },
+# {
+# "address": "192.16.255.255",
+# "key": "50",
+# "routing_instance_name": "rt2",
+# "ttl": 200,
+# "version": 3
+# }
+# ],
+# "interval_range": 2,
+# "multicast_client": "224.0.0.1",
+# "peers": [
+# {
+# "peer": "78.44.194.186"
+# },
+# {
+# "key_id": 10000,
+# "peer": "172.44.194.186",
+# "prefer": true,
+# "version": 3
+# }
+# ],
+# "servers": [
+# {
+# "key_id": 34,
+# "prefer": true,
+# "routing_instance": "rt1",
+# "server": "48.46.194.186",
+# "version": 2
+# },
+# {
+# "key_id": 34,
+# "prefer": true,
+# "server": "48.45.194.186",
+# "version": 2
+# }
+# ],
+# "source_addresses": [
+# {
+# "routing_instance": "rt1",
+# "source_address": "172.45.194.186"
+# },
+# {
+# "routing_instance": "rt2",
+# "source_address": "171.45.194.186"
+# }
+# ],
+# "threshold": {
+# "action": "accept",
+# "value": 300
+# },
+# "trusted_keys": [
+# {"key_id": 2000},
+# {"key_id": 3000}
+# ]
+# },
+# "before": {},
+# "changed": true,
+# "commands": [
+# "<nc:system xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:ntp><nc:boot-server>78.46.194.186</nc:boot-server><nc:broadcast>"
+# "<nc:name>172.16.255.255</nc:name><nc:key>50</nc:key><nc:routing-instance-name>rt1</nc:routing-instance-name>"
+# "<nc:ttl>200</nc:ttl><nc:version>3</nc:version></nc:broadcast><nc:broadcast><nc:name>192.16.255.255</nc:name>"
+# "<nc:key>50</nc:key><nc:routing-instance-name>rt2</nc:routing-instance-name><nc:ttl>200</nc:ttl>"
+# "<nc:version>3</nc:version></nc:broadcast><nc:broadcast-client/><nc:interval-range>2</nc:interval-range>"
+# "<nc:multicast-client>224.0.0.1</nc:multicast-client><nc:peer><nc:name>78.44.194.186</nc:name></nc:peer>"
+# "<nc:peer><nc:name>172.44.194.186</nc:name><nc:key>10000</nc:key><nc:prefer/><nc:version>3</nc:version>"
+# "</nc:peer><nc:server><nc:name>48.46.194.186</nc:name><nc:key>34</nc:key><nc:routing-instance>rt1</nc:routing-instance>"
+# "<nc:prefer/><nc:version>2</nc:version></nc:server><nc:server><nc:name>48.45.194.186</nc:name><nc:key>34</nc:key>"
+# "<nc:prefer/><nc:version>2</nc:version></nc:server><nc:source-address><nc:name>172.45.194.186</nc:name>"
+# "<nc:routing-instance>rt1</nc:routing-instance></nc:source-address><nc:source-address>"
+# "<nc:name>171.45.194.186</nc:name><nc:routing-instance>rt2</nc:routing-instance></nc:source-address>"
+# "<nc:threshold><nc:value>300</nc:value><nc:action>accept</nc:action></nc:threshold>"
+# "<nc:trusted-key>3000</nc:trusted-key><nc:trusted-key>2000</nc:trusted-key></nc:ntp></nc:system>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show system ntp
+# boot-server 78.46.194.186;
+# interval-range 2;
+# peer 78.44.194.186;
+# peer 172.44.194.186 key 10000 version 3 prefer; ## SECRET-DATA
+# server 48.46.194.186 key 34 version 2 prefer routing-instance rt1; ## SECRET-DATA
+# server 48.45.194.186 key 34 version 2 prefer; ## SECRET-DATA
+# broadcast 172.16.255.255 routing-instance-name rt1 key 50 version 3 ttl 200;
+# broadcast 192.16.255.255 routing-instance-name rt2 key 50 version 3 ttl 200;
+# broadcast-client;
+# multicast-client 224.0.0.1;
+# trusted-key [ 3000 2000 ];
+# threshold 300 action accept;
+# source-address 172.45.194.186 routing-instance rt1;
+# source-address 171.45.194.186 routing-instance rt2;
+#
+#
+# Using Replaced
+# Before state
+# ------------
+#
+# vagrant@vsrx# show system ntp
+# boot-server 78.46.194.186;
+# interval-range 2;
+# peer 78.44.194.186;
+# peer 172.44.194.186 key 10000 version 3 prefer; ## SECRET-DATA
+# server 48.46.194.186 key 34 version 2 prefer routing-instance rt1; ## SECRET-DATA
+# server 48.45.194.186 key 34 version 2 prefer; ## SECRET-DATA
+# broadcast 172.16.255.255 routing-instance-name rt1 key 50 version 3 ttl 200;
+# broadcast 192.16.255.255 routing-instance-name rt2 key 50 version 3 ttl 200;
+# broadcast-client;
+# multicast-client 224.0.0.1;
+# trusted-key [ 3000 2000 ];
+# threshold 300 action accept;
+# source-address 172.45.194.186 routing-instance rt1;
+# source-address 171.45.194.186 routing-instance rt2;
+
+- name: Replaced running ntp global configuration with provided configuration
+ junipernetworks.junos.junos_ntp_global:
+ config:
+ authentication_keys:
+ - id: 2
+ algorithm: 'md5'
+ key: 'asdfghd'
+ - id: 5
+ algorithm: 'sha1'
+ key: 'aasdad'
+ servers:
+ - server: "48.46.194.186"
+ key_id: 34
+ prefer: true
+ version: 2
+ routing_instance: 'rt1'
+ - server: "48.45.194.186"
+ key_id: 34
+ prefer: true
+ version: 2
+ state: replaced
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "authentication_keys": [
+# {
+# "algorithm": "md5",
+# "id": 2,
+# "key": "$9$03aAB1hreW7NbO1rvMLVbgoJ"
+# },
+# {
+# "algorithm": "sha1",
+# "id": 5,
+# "key": "$9$DXiHmf5F/A0ZUjq.P3n"
+# }
+# ],
+# "servers": [
+# {
+# "key_id": 34,
+# "prefer": true,
+# "routing_instance": "rt1",
+# "server": "48.46.194.186",
+# "version": 2
+# },
+# {
+# "key_id": 34,
+# "prefer": true,
+# "server": "48.45.194.186",
+# "version": 2
+# }
+# ]
+# },
+# "before": {
+# "boot_server": "78.46.194.186",
+# "broadcast_client": true,
+# "broadcasts": [
+# {
+# "address": "172.16.255.255",
+# "key": "50",
+# "routing_instance_name": "rt1",
+# "ttl": 200,
+# "version": 3
+# },
+# {
+# "address": "192.16.255.255",
+# "key": "50",
+# "routing_instance_name": "rt2",
+# "ttl": 200,
+# "version": 3
+# }
+# ],
+# "interval_range": 2,
+# "multicast_client": "224.0.0.1",
+# "peers": [
+# {
+# "peer": "78.44.194.186"
+# },
+# {
+# "key_id": 10000,
+# "peer": "172.44.194.186",
+# "prefer": true,
+# "version": 3
+# }
+# ],
+# "servers": [
+# {
+# "key_id": 34,
+# "prefer": true,
+# "routing_instance": "rt1",
+# "server": "48.46.194.186",
+# "version": 2
+# },
+# {
+# "key_id": 34,
+# "prefer": true,
+# "server": "48.45.194.186",
+# "version": 2
+# }
+# ],
+# "source_addresses": [
+# {
+# "routing_instance": "rt1",
+# "source_address": "172.45.194.186"
+# },
+# {
+# "routing_instance": "rt2",
+# "source_address": "171.45.194.186"
+# }
+# ],
+# "threshold": {
+# "action": "accept",
+# "value": 300
+# },
+# "trusted_keys": [
+# {"key_id": 2000},
+# {"key_id": 3000}
+# ]
+# },
+# "changed": true,
+# "commands": [
+# "<nc:system xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# "<nc:ntp delete=\"delete\"/><nc:ntp><nc:authentication-key><nc:name>2</nc:name><nc:type>md5</nc:type>
+# "<nc:value>asdfghd</nc:value></nc:authentication-key><nc:authentication-key><nc:name>5</nc:name>
+# "<nc:type>sha1</nc:type><nc:value>aasdad</nc:value></nc:authentication-key><nc:server>
+# "<nc:name>48.46.194.186</nc:name><nc:key>34</nc:key><nc:routing-instance>rt1</nc:routing-instance>
+# "<nc:prefer/><nc:version>2</nc:version></nc:server><nc:server><nc:name>48.45.194.186</nc:name>
+# "<nc:key>34</nc:key><nc:prefer/><nc:version>2</nc:version></nc:server></nc:ntp></nc:system>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show system ntp
+# authentication-key 2 type md5 value "$9$03aAB1hreW7NbO1rvMLVbgoJ"; ## SECRET-DATA
+# authentication-key 5 type sha1 value "$9$DXiHmf5F/A0ZUjq.P3n"; ## SECRET-DATA
+# server 48.46.194.186 key 34 version 2 prefer routing-instance rt1; ## SECRET-DATA
+# server 48.45.194.186 key 34 version 2 prefer; ## SECRET-DATA
+
+# Using overridden
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show system ntp
+# boot-server 78.46.194.186;
+# interval-range 2;
+# peer 78.44.194.186;
+# peer 172.44.194.186 key 10000 version 3 prefer; ## SECRET-DATA
+# server 48.46.194.186 key 34 version 2 prefer routing-instance rt1; ## SECRET-DATA
+# server 48.45.194.186 key 34 version 2 prefer; ## SECRET-DATA
+# broadcast 172.16.255.255 routing-instance-name rt1 key 50 version 3 ttl 200;
+# broadcast 192.16.255.255 routing-instance-name rt2 key 50 version 3 ttl 200;
+# broadcast-client;
+# multicast-client 224.0.0.1;
+# trusted-key [ 3000 2000 ];
+# threshold 300 action accept;
+# source-address 172.45.194.186 routing-instance rt1;
+# source-address 171.45.194.186 routing-instance rt2;
+
+- name: Override running ntp global configuration with provided configuration
+ junipernetworks.junos.junos_ntp_global:
+ config:
+ authentication_keys:
+ - id: 2
+ algorithm: 'md5'
+ key: 'asdfghd'
+ - id: 5
+ algorithm: 'sha1'
+ key: 'aasdad'
+ servers:
+ - server: "48.46.194.186"
+ key_id: 34
+ prefer: true
+ version: 2
+ routing_instance: 'rt1'
+ - server: "48.45.194.186"
+ key_id: 34
+ prefer: true
+ version: 2
+ state: overridden
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "authentication_keys": [
+# {
+# "algorithm": "md5",
+# "id": 2,
+# "key": "$9$03aAB1hreW7NbO1rvMLVbgoJ"
+# },
+# {
+# "algorithm": "sha1",
+# "id": 5,
+# "key": "$9$DXiHmf5F/A0ZUjq.P3n"
+# }
+# ],
+# "servers": [
+# {
+# "key_id": 34,
+# "prefer": true,
+# "routing_instance": "rt1",
+# "server": "48.46.194.186",
+# "version": 2
+# },
+# {
+# "key_id": 34,
+# "prefer": true,
+# "server": "48.45.194.186",
+# "version": 2
+# }
+# ]
+# },
+# "before": {
+# "boot_server": "78.46.194.186",
+# "broadcast_client": true,
+# "broadcasts": [
+# {
+# "address": "172.16.255.255",
+# "key": "50",
+# "routing_instance_name": "rt1",
+# "ttl": 200,
+# "version": 3
+# },
+# {
+# "address": "192.16.255.255",
+# "key": "50",
+# "routing_instance_name": "rt2",
+# "ttl": 200,
+# "version": 3
+# }
+# ],
+# "interval_range": 2,
+# "multicast_client": "224.0.0.1",
+# "peers": [
+# {
+# "peer": "78.44.194.186"
+# },
+# {
+# "key_id": 10000,
+# "peer": "172.44.194.186",
+# "prefer": true,
+# "version": 3
+# }
+# ],
+# "servers": [
+# {
+# "key_id": 34,
+# "prefer": true,
+# "routing_instance": "rt1",
+# "server": "48.46.194.186",
+# "version": 2
+# },
+# {
+# "key_id": 34,
+# "prefer": true,
+# "server": "48.45.194.186",
+# "version": 2
+# }
+# ],
+# "source_addresses": [
+# {
+# "routing_instance": "rt1",
+# "source_address": "172.45.194.186"
+# },
+# {
+# "routing_instance": "rt2",
+# "source_address": "171.45.194.186"
+# }
+# ],
+# "threshold": {
+# "action": "accept",
+# "value": 300
+# },
+# "trusted_keys": [
+# {"key_id": 2000},
+# {"key_id": 3000}
+# ]
+# },
+# "changed": true,
+# "commands": [
+# "<nc:system xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# "<nc:ntp delete=\"delete\"/><nc:ntp><nc:authentication-key><nc:name>2</nc:name><nc:type>md5</nc:type>
+# "<nc:value>asdfghd</nc:value></nc:authentication-key><nc:authentication-key><nc:name>5</nc:name>
+# "<nc:type>sha1</nc:type><nc:value>aasdad</nc:value></nc:authentication-key><nc:server>
+# "<nc:name>48.46.194.186</nc:name><nc:key>34</nc:key><nc:routing-instance>rt1</nc:routing-instance>
+# "<nc:prefer/><nc:version>2</nc:version></nc:server><nc:server><nc:name>48.45.194.186</nc:name>
+# "<nc:key>34</nc:key><nc:prefer/><nc:version>2</nc:version></nc:server></nc:ntp></nc:system>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show system ntp
+# authentication-key 2 type md5 value "$9$03aAB1hreW7NbO1rvMLVbgoJ"; ## SECRET-DATA
+# authentication-key 5 type sha1 value "$9$DXiHmf5F/A0ZUjq.P3n"; ## SECRET-DATA
+# server 48.46.194.186 key 34 version 2 prefer routing-instance rt1; ## SECRET-DATA
+# server 48.45.194.186 key 34 version 2 prefer; ## SECRET-DATA
+#
+# Using deleted
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show system ntp
+# authentication-key 2 type md5 value "$9$03aAB1hreW7NbO1rvMLVbgoJ"; ## SECRET-DATA
+# authentication-key 5 type sha1 value "$9$DXiHmf5F/A0ZUjq.P3n"; ## SECRET-DATA
+# server 48.46.194.186 key 34 version 2 prefer routing-instance rt1; ## SECRET-DATA
+# server 48.45.194.186 key 34 version 2 prefer; ## SECRET-DATA
+#
+- name: Delete running NTP global configuration
+ junipernetworks.junos.junos_ntp_global:
+ config:
+ state: deleted
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {},
+# "before": {
+# "authentication_keys": [
+# {
+# "algorithm": "md5",
+# "id": 2,
+# "key": "$9$03aAB1hreW7NbO1rvMLVbgoJ"
+# },
+# {
+# "algorithm": "sha1",
+# "id": 5,
+# "key": "$9$DXiHmf5F/A0ZUjq.P3n"
+# }
+# ],
+# "servers": [
+# {
+# "key_id": 34,
+# "prefer": true,
+# "routing_instance": "rt1",
+# "server": "48.46.194.186",
+# "version": 2
+# },
+# {
+# "key_id": 34,
+# "prefer": true,
+# "server": "48.45.194.186",
+# "version": 2
+# }
+# ]
+# },
+# "changed": true,
+# "commands": [
+# "<nc:system xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:ntp delete=\"delete\"/></nc:system>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show system ntp
+#
+# [edit]
+# Using gathered
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show system ntp
+# boot-server 78.46.194.186;
+# interval-range 2;
+# peer 78.44.194.186;
+# peer 172.44.194.186 key 10000 version 3 prefer; ## SECRET-DATA
+# server 48.46.194.186 key 34 version 2 prefer routing-instance rt1; ## SECRET-DATA
+# server 48.45.194.186 key 34 version 2 prefer; ## SECRET-DATA
+# broadcast 172.16.255.255 routing-instance-name rt1 key 50 version 3 ttl 200;
+# broadcast 192.16.255.255 routing-instance-name rt2 key 50 version 3 ttl 200;
+# broadcast-client;
+# multicast-client 224.0.0.1;
+# trusted-key [ 3000 2000 ];
+# threshold 300 action accept;
+# source-address 172.45.194.186 routing-instance rt1;
+# source-address 171.45.194.186 routing-instance rt2;
+- name: Gather running NTP global configuration
+ junipernetworks.junos.junos_ntp_global:
+ state: gathered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "gathered": {
+# "boot_server": "78.46.194.186",
+# "broadcast_client": true,
+# "broadcasts": [
+# {
+# "address": "172.16.255.255",
+# "key": "50",
+# "routing_instance_name": "rt1",
+# "ttl": 200,
+# "version": 3
+# },
+# {
+# "address": "192.16.255.255",
+# "key": "50",
+# "routing_instance_name": "rt2",
+# "ttl": 200,
+# "version": 3
+# }
+# ],
+# "interval_range": 2,
+# "multicast_client": "224.0.0.1",
+# "peers": [
+# {
+# "peer": "78.44.194.186"
+# },
+# {
+# "key_id": 10000,
+# "peer": "172.44.194.186",
+# "prefer": true,
+# "version": 3
+# }
+# ],
+# "servers": [
+# {
+# "key_id": 34,
+# "prefer": true,
+# "routing_instance": "rt1",
+# "server": "48.46.194.186",
+# "version": 2
+# },
+# {
+# "key_id": 34,
+# "prefer": true,
+# "server": "48.45.194.186",
+# "version": 2
+# }
+# ],
+# "source_addresses": [
+# {
+# "routing_instance": "rt1",
+# "source_address": "172.45.194.186"
+# },
+# {
+# "routing_instance": "rt2",
+# "source_address": "171.45.194.186"
+# }
+# ],
+# "threshold": {
+# "action": "accept",
+# "value": 300
+# },
+# "trusted_keys": [
+# {"key_id": 2000},
+# {"key_id": 3000}
+# ]
+# },
+# "changed": false,
+# Using rendered
+#
+# Before state
+# ------------
+#
+- name: Render xml for provided facts.
+ junipernetworks.junos.junos_ntp_global:
+ config:
+ boot_server: '78.46.194.186'
+ broadcasts:
+ - address: '172.16.255.255'
+ key: '50'
+ ttl: 200
+ version: 3
+ routing_instance_name: 'rt1'
+ - address: '192.16.255.255'
+ key: '50'
+ ttl: 200
+ version: 3
+ routing_instance_name: 'rt2'
+ broadcast_client: true
+ interval_range: 2
+ multicast_client: "224.0.0.1"
+ peers:
+ - peer: "78.44.194.186"
+ - peer: "172.44.194.186"
+ key_id: 10000
+ prefer: true
+ version: 3
+ servers:
+ - server: "48.46.194.186"
+ key_id: 34
+ prefer: true
+ version: 2
+ routing_instance: 'rt1'
+ - server: "48.45.194.186"
+ key_id: 34
+ prefer: true
+ version: 2
+ source_addresses:
+ - source_address: "172.45.194.186"
+ routing_instance: 'rt1'
+ - source_address: "171.45.194.186"
+ routing_instance: 'rt2'
+ threshold:
+ value: 300
+ action: "accept"
+ trusted_keys:
+ - 3000
+ - 2000
+ state: rendered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "rendered": [
+# "<nc:system xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:ntp><nc:boot-server>78.46.194.186</nc:boot-server><nc:broadcast><nc:name>172.16.255.255</nc:name>"
+# "<nc:key>50</nc:key><nc:routing-instance-name>rt1</nc:routing-instance-name><nc:ttl>200</nc:ttl>"
+# "<nc:version>3</nc:version></nc:broadcast><nc:broadcast><nc:name>192.16.255.255</nc:name>"
+# "<nc:key>50</nc:key><nc:routing-instance-name>rt2</nc:routing-instance-name>"
+# "<nc:ttl>200</nc:ttl><nc:version>3</nc:version></nc:broadcast><nc:broadcast-client/>"
+# "<nc:interval-range>2</nc:interval-range><nc:multicast-client>224.0.0.1</nc:multicast-client><nc:peer>"
+# "<nc:name>78.44.194.186</nc:name></nc:peer><nc:peer><nc:name>172.44.194.186</nc:name>"
+# "<nc:key>10000</nc:key><nc:prefer/><nc:version>3</nc:version></nc:peer><nc:server>"
+# "<nc:name>48.46.194.186</nc:name><nc:key>34</nc:key><nc:routing-instance>rt1</nc:routing-instance>"
+# "<nc:prefer/><nc:version>2</nc:version></nc:server><nc:server><nc:name>48.45.194.186</nc:name>"
+# "<nc:key>34</nc:key><nc:prefer/><nc:version>2</nc:version></nc:server><nc:source-address>"
+# "<nc:name>172.45.194.186</nc:name><nc:routing-instance>rt1</nc:routing-instance></nc:source-address>"
+# "<nc:source-address><nc:name>171.45.194.186</nc:name><nc:routing-instance>rt2</nc:routing-instance>"
+# "</nc:source-address><nc:threshold><nc:value>300</nc:value><nc:action>accept</nc:action></nc:threshold>"
+# "<nc:trusted-key>3000</nc:trusted-key><nc:trusted-key>2000</nc:trusted-key></nc:ntp></nc:system>"
+# ]
+#
+# Using parsed
+# parsed.cfg
+# ------------
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <version>18.4R1-S2.4</version>
+# <system xmlns="http://yang.juniper.net/junos-es/conf/system">
+# <ntp>
+# <authentication-key>
+# <name>2</name>
+# <type>md5</type>
+# <value>$9$GxDjqfT3CA0UjfzF6u0RhS</value>
+# </authentication-key>
+# <authentication-key>
+# <name>5</name>
+# <type>sha1</type>
+# <value>$9$ZsUDk.mT3/toJGiHqQz</value>
+# </authentication-key>
+# </ntp>
+# </system>
+# </configuration>
+# </rpc-reply>
+#
+- name: Parse NTP global running config
+ junipernetworks.junos.junos_ntp_global:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "parsed": {
+# "authentication_keys": [
+# {
+# "algorithm": "md5",
+# "id": 2,
+# "key": "$9$GxDjqfT3CA0UjfzF6u0RhS"
+# },
+# {
+# "algorithm": "sha1",
+# "id": 5,
+# "key": "$9$ZsUDk.mT3/toJGiHqQz"
+# }
+# ]
+# }
+#
+#
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+after:
+ description: The resulting configuration model invocation.
+ returned: when changed
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ["<nc:name>78.44.194.186</nc:name></nc:peer><nc:peer><nc:name>172.44.194.186</nc:name>",
+ 'xml 2', 'xml 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.ntp_global.ntp_global import (
+ Ntp_globalArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.ntp_global.ntp_global import (
+ Ntp_global,
+)
+
+
+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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ module = AnsibleModule(
+ argument_spec=Ntp_globalArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+
+ result = Ntp_global(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_ospf_interfaces.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_ospf_interfaces.py
new file mode 100644
index 000000000..fdfaf2640
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_ospf_interfaces.py
@@ -0,0 +1,611 @@
+#!/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_ospf_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_ospf_interfaces
+version_added: 1.3.0
+short_description: OSPF Interfaces Resource Module.
+description:
+ - This module manages OSPF(v2/v3) configuration of interfaces on devices running Juniper JUNOS.
+author: Rohit Thakur (@rohitthakur2590)
+requirements:
+ - ncclient (>=v0.6.4)
+ - xmltodict (>=0.12.0)
+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 list of OSPF configuration for interfaces.
+ type: list
+ elements: dict
+ suboptions:
+ router_id:
+ description:
+ - The OSPF router id.
+ type: str
+ name:
+ description:
+ - Name/Identifier of the interface.
+ type: str
+ required: True
+ address_family:
+ description:
+ - OSPF settings on the interfaces in address-family context.
+ type: list
+ elements: dict
+ suboptions:
+ afi:
+ description:
+ - Address Family Identifier (AFI) for OSPF settings on the interfaces.
+ type: str
+ choices: ['ipv4', 'ipv6']
+ required: True
+ processes:
+ description:
+ - Interfaces configuration for an OSPF process.
+ type: dict
+ suboptions:
+ area:
+ description: Specify the area-id
+ type: dict
+ suboptions:
+ area_id:
+ description: Specify area id.
+ type: str
+ authentication:
+ description: Specify authentication type
+ type: dict
+ suboptions:
+ simple_password:
+ description:
+ - Specify password for authentication.
+ type: str
+ md5:
+ description:
+ - Specify md5 based authentication.
+ type: dict
+ suboptions:
+ key_id:
+ description: Specify md5 key-id
+ type: str
+ key_value:
+ description: Specify key value
+ type: str
+ start_time:
+ description: Specify start time for key transmission
+ type: str
+ interface_type:
+ description: Specify type of interface
+ type: str
+ choices: ["nbma", "p2mp", "p2p"]
+ bandwidth_based_metrics:
+ description: Specify list of bandwidth based metrics
+ type: list
+ elements: dict
+ suboptions:
+ bandwidth:
+ description:
+ - BW to apply metric to.
+ type: str
+ choices: [1g, 10g]
+ metric:
+ description: Specify metric
+ type: int
+ priority:
+ description:
+ - Priority for the interface.
+ type: int
+ passive:
+ description:
+ - Do not run OSPF, but advertise it.
+ type: bool
+ metric:
+ description:
+ - Metric applied to the interface.
+ type: int
+ te_metric:
+ description:
+ - Traffic engineering metric applied to the interface.
+ type: int
+ mtu:
+ description:
+ - Maximum OSPF packet size
+ type: int
+ ipsec_sa:
+ description:
+ - IPSec security association name
+ type: str
+ secondary:
+ description:
+ - Treat interface as secondary
+ type: bool
+ flood_reduction:
+ description:
+ - Enable flood reduction.
+ type: bool
+ demand_circuit:
+ description:
+ - Interface functions as a demand circuit.
+ type: bool
+ no_advertise_adjacency_segment:
+ description:
+ - Do not advertise an adjacency segment for this interface.
+ type: bool
+ no_eligible_backup:
+ description:
+ - Not eligible to backup traffic from protected interfaces.
+ type: bool
+ no_eligible_remote_backup:
+ description:
+ - Not eligible for Remote-LFA backup traffic from protected interfaces.
+ type: bool
+ no_interface_state_traps:
+ description:
+ - Do not send interface state change traps.
+ type: bool
+ no_neighbor_down_notification:
+ description:
+ - Don't inform other protocols about neighbor down events.
+ type: bool
+ node_link_protection:
+ description:
+ - Protect interface from both link and node faults.
+ type: str
+ dead_interval:
+ description:
+ - Dead interval (seconds).
+ type: int
+ hello_interval:
+ description:
+ - Hello interval (seconds).
+ type: int
+ poll_interval:
+ description:
+ - Poll interval (seconds).
+ type: int
+ retransmit_interval:
+ description:
+ - Retransmit interval (seconds).
+ type: int
+ transit_delay:
+ description:
+ - Transit delay (seconds).
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show protocols ospf).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - parsed
+ - gathered
+ - rendered
+ default: merged
+"""
+EXAMPLES = """
+# Using merged
+#
+# Before state
+# ------------
+#
+# admin# show protocols ospf
+
+- name: Merge Junos OSPF interfaces config
+ junipernetworks.junos.junos_ospf_interfaces:
+ config:
+ - name: 'ge-0/0/2.0'
+ address_family:
+ - afi: 'ipv4'
+ processes:
+ area:
+ area_id: '0.0.0.2'
+ priority: 3
+ metric: 5
+ state: merged
+
+# After state
+# -----------
+#
+# admin# show protocols ospf
+# area 0.0.0.2 {
+# interface ge-0/0/2.0 {
+# metric 5;
+# priority 3;
+# }
+# }
+
+# Using replaced
+#
+# Before state
+# ------------
+#
+# admin# show protocols ospf
+# area 0.0.0.2 {
+# interface ge-0/0/2.0 {
+# metric 5;
+# priority 3;
+# }
+# }
+- name: Replace Junos OSPF interfaces config
+ junipernetworks.junos.junos_ospf_interfaces:
+ config:
+ - name: 'ge-0/0/2.0'
+ address_family:
+ - afi: 'ipv4'
+ processes:
+ area:
+ area_id: '0.0.0.1'
+ priority: 6
+ metric: 6
+ state: replaced
+
+# After state
+# -----------
+#
+# admin# show protocols ospf
+# area 0.0.0.1 {
+# interface ge-0/0/2.0 {
+# metric 6;
+# priority 6;
+# }
+# }
+
+# Using overridden
+#
+# Before state
+# ------------
+#
+# admin# show protocols ospf
+# area 0.0.0.3 {
+# interface ge-0/0/3.0 {
+# metric 5;
+# priority 3;
+# }
+# }
+# area 0.0.0.2 {
+# interface ge-0/0/2.0 {
+# metric 5;
+# priority 3;
+# }
+# }
+
+- name: Override Junos OSPF interfaces config
+ junipernetworks.junos.junos_ospf_interfaces:
+ config:
+ - name: 'ge-0/0/1.0'
+ address_family:
+ - afi: 'ipv4'
+ processes:
+ area:
+ area_id: '0.0.0.1'
+ priority: 3
+ metric: 5
+ state: overridden
+
+# After state
+# -----------
+#
+# admin# show protocols ospf
+# area 0.0.0.1 {
+# interface ge-0/0/1.0 {
+# metric 5;
+# priority 3;
+# }
+# }
+
+#
+# Using deleted
+#
+# Before state
+# ------------
+#
+# admin# show protocols ospf
+# area 0.0.0.1 {
+# interface ge-0/0/1.0 {
+# metric 5;
+# priority 3;
+# }
+# }
+
+- name: Delete Junos OSPF interfaces config
+ junipernetworks.junos.junos_ospf_interfaces:
+ config:
+ - name: 'ge-0/0/1.0'
+ state: deleted
+
+# After state
+# -----------
+#
+# admin# show protocols ospf
+# Using gathered
+#
+# Before state
+# ------------
+#
+# admin# show protocols ospf
+# area 0.0.0.3 {
+# interface ge-0/0/3.0 {
+# metric 5;
+# priority 3;
+# }
+# }
+# area 0.0.0.2 {
+# interface ge-0/0/2.0 {
+# metric 5;
+# priority 3;
+# }
+# }
+
+- name: Gather Junos OSPF interfaces config
+ junipernetworks.junos.junos_ospf_interfaces:
+ config:
+ state: gathered
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+# "gathered": [
+# {
+# "address_family": [
+# {
+# "afi": "ipv4",
+# "processes": {
+# "area": {
+# "area_id": "0.0.0.3"
+# },
+# "metric": 5,
+# "priority": 3
+# }
+# }
+# ],
+# "name": "ge-0/0/3.0",
+# },
+# {
+# "address_family": [
+# {
+# "afi": "ipv4",
+# "processes": {
+# "area": {
+# "area_id": "0.0.0.2"
+# },
+# "metric": 5,
+# "priority": 3
+# }
+# }
+# ],
+# "name": "ge-0/0/2.0",
+# }
+# ]
+#
+# Using rendered
+#
+#
+- name: Render the commands for provided configuration
+ junipernetworks.junos.junos_ospf_interfaces:
+ config:
+ - name: 'ge-0/0/2.0'
+ address_family:
+ - afi: 'ipv4'
+ processes:
+ area:
+ area_id: '0.0.0.2'
+ priority: 3
+ metric: 5
+ state: rendered
+
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "rendered": "
+# <nc:protocols
+# xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# <nc:ospf>
+# <nc:area>
+# <nc:name>0.0.0.2</nc:name>
+# <nc:interface>
+# <nc:name>ge-0/0/2.0</nc:name>
+# <nc:priority>3</nc:priority>
+# <nc:metric>5</nc:metric>
+# </nc:interface>
+# </nc:area>
+# </nc:ospf>
+# </nc:protocols>"
+#
+# Using parsed
+# parsed.cfg
+# ------------
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <protocols>
+# <ospf>
+# <area>
+# <name>0.0.0.2</name>
+# <stub>
+# <default-metric>200</default-metric>
+# </stub>
+# <interface>
+# <name>ge-0/0/2.0</name>
+# <metric>5</metric>
+# <priority>3</priority>
+# </interface>
+# </area>
+# </ospf>
+# </protocols>
+# <routing-options>
+# <router-id>10.200.16.75</router-id>
+# </routing-options>
+# </configuration>
+# </rpc-reply>
+
+
+- name: Parsed the device configuration to get output commands
+ junipernetworks.junos.junos_ospf_interfaces:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "parsed": [
+# {
+# "address_family": [
+# {
+# "afi": "ipv4",
+# "processes": {
+# "area": {
+# "area_id": "0.0.0.2"
+# },
+# "metric": 5,
+# "priority": 3
+# }
+# }
+# ],
+# "name": "ge-0/0/2.0",
+# }
+# ]
+#
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ type: dict
+ 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: 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: ['<nc:protocols
+ xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ <nc:ospf>
+ <nc:area>
+ <nc:name>0.0.0.3</nc:name>
+ <nc:interface>
+ <nc:name>ge-0/0/3.0</nc:name>
+ <nc:priority>3</nc:priority>
+ <nc:metric>5</nc:metric>
+ </nc:interface>
+ </nc:area>
+ <nc:area>
+ <nc:name>0.0.0.2</nc:name>
+ <nc:interface>
+ <nc:name>ge-0/0/2.0</nc:name>
+ <nc:priority>3</nc:priority>
+ <nc:metric>5</nc:metric>
+ </nc:interface>
+ </nc:area>
+ </nc:ospf>
+</nc:protocols>",
+ "
+<nc:routing-options
+ xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ <nc:router-id>10.200.16.75</nc:router-id>
+ <nc:router-id>10.200.16.75</nc:router-id>
+</nc:routing-options>', 'xml 2', 'xml 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.ospf_interfaces.ospf_interfaces import (
+ Ospf_interfacesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.ospf_interfaces.ospf_interfaces import (
+ Ospf_interfaces,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ module = AnsibleModule(
+ argument_spec=Ospf_interfacesArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+ result = Ospf_interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_ospfv2.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_ospfv2.py
new file mode 100644
index 000000000..9d951cf79
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_ospfv2.py
@@ -0,0 +1,347 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2020 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_ospfv2
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: junos_ospfv2
+short_description: OSPFv2 resource module
+description:
+- This module manages global OSPFv2 configuration on devices running Juniper JUNOS.
+version_added: 1.0.0
+author:
+- Daniel Mellado (@dmellado)
+requirements:
+- ncclient (>=v0.6.4)
+- xmltodict (>=0.12.0)
+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,https://docs.ansible.com/ansible/latest/network/user_guide/platform_junos.html).
+- Tested against JunOS v18.4R1
+options:
+ config:
+ description: A list of OSPFv2 process configuration.
+ type: list
+ elements: dict
+ suboptions:
+ router_id:
+ description:
+ - The OSPFv2 router id.
+ type: str
+ areas:
+ description:
+ - A list of OSPFv2 areas' configuration.
+ type: list
+ elements: dict
+ suboptions:
+ area_id:
+ description:
+ - The Area ID as an integer or IP Address.
+ type: str
+ required: true
+ area_range:
+ description:
+ - Configure an address range for the area.
+ type: str
+ stub:
+ description:
+ - Settings for configuring the area as a stub.
+ type: dict
+ suboptions:
+ default_metric:
+ description:
+ - Metric for the default route in this area.
+ type: int
+ set:
+ description:
+ - Configure the area as a stub.
+ type: bool
+ interfaces:
+ description:
+ - List of interfaces in this area.
+ type: list
+ elements: dict
+ suboptions:
+ authentication:
+ description: Specify authentication type
+ type: dict
+ suboptions:
+ type:
+ description:
+ - Type of authentication to use.
+ type: dict
+ bandwidth_based_metrics:
+ description: Specify list of bandwidth based metrics
+ type: list
+ elements: dict
+ suboptions:
+ bandwidth:
+ description:
+ - BW to apply metric to.
+ type: str
+ choices: [1g, 10g]
+ metric:
+ description: Specify metric
+ type: int
+ name:
+ description:
+ - Name of the interface.
+ type: str
+ required: true
+ priority:
+ description:
+ - Priority for the interface.
+ type: int
+ metric:
+ description:
+ - Metric applied to the interface.
+ type: int
+ flood_reduction:
+ description:
+ - Enable flood reduction.
+ type: bool
+ passive:
+ description: Specify passive
+ type: bool
+ timers:
+ description: Specify timers
+ type: dict
+ suboptions:
+ dead_interval:
+ description:
+ - Dead interval (seconds).
+ type: int
+ hello_interval:
+ description:
+ - Hello interval (seconds).
+ type: int
+ poll_interval:
+ description:
+ - Poll interval (seconds).
+ type: int
+ retransmit_interval:
+ description:
+ - Retransmit interval (seconds).
+ type: int
+ transit_delay:
+ description:
+ - Transit delay (seconds).
+ type: int
+ external_preference:
+ description:
+ - Preference of external routes.
+ type: int
+ overload:
+ description: Specify time for overload mode reset
+ type: dict
+ suboptions:
+ timeout:
+ description:
+ - Time after which overload mode is reset (seconds).
+ type: int
+ preference:
+ description:
+ - Preference of internal routes.
+ type: int
+ prefix_export_limit:
+ description:
+ - Maximum number of external prefixes that can be exported.
+ type: int
+ reference_bandwidth:
+ description:
+ - Bandwidth for calculating metric defaults.
+ type: str
+ choices: [1g, 10g]
+ rfc1583compatibility:
+ description:
+ - Set RFC1583 compatibility
+ type: bool
+ spf_options:
+ description:
+ - Configure options for SPF.
+ type: dict
+ suboptions:
+ delay:
+ description:
+ - Time to wait before running an SPF (seconds).
+ type: int
+ holddown:
+ description:
+ - Time to hold down before running an SPF (seconds).
+ type: int
+ rapid_runs:
+ description:
+ - Number of maximum rapid SPF runs before holddown (seconds).
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show protocols ospf.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ default: merged
+"""
+EXAMPLES = """
+# Using merged
+#
+# Before state
+# ------------
+#
+# admin# show protocols ospf
+
+- name: Merge Junos OSPFv2 config
+ junipernetworks.junos.junos_ospfv2:
+ config:
+ - reference_bandwidth: 10g
+ areas:
+ - area_id: 0.0.0.100
+ area_range: 10.200.16.0/24
+ stub:
+ default_metric: 100
+ set: true
+ interfaces:
+ - name: so-0/0/0.0
+ priority: 3
+ metric: 5
+ flood_reduction: false
+ passive: true
+ bandwidth_based_metrics:
+ - bandwidth: 1g
+ metric: 5
+ - bandwidth: 10g
+ metric: 40
+ timers:
+ dead_interval: 4
+ hello_interval: 2
+ poll_interval: 2
+ retransmit_interval: 2
+ rfc1583compatibility: false
+ state: merged
+
+# After state
+# -----------
+#
+# admin# show protocols ospf
+# reference-bandwidth 10g;
+# no-rfc-1583;
+# area 0.0.0.100 {
+# stub default-metric 100;
+# area-range 10.200.16.0/24;
+# interface so-0/0/0.0 {
+# passive;
+# bandwidth-based-metrics {
+# bandwidth 1g metric 5;
+# bandwidth 10g metric 40;
+# }
+# metric 5;
+# priority 3;
+# retransmit-interval 2;
+# hello-interval 2;
+# dead-interval 4;
+# poll-interval 2;
+# }
+# }
+
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ type: dict
+ 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: 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: ['command 1', 'command 2', 'command 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.ospfv2.ospfv2 import (
+ Ospfv2Args,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.ospfv2.ospfv2 import (
+ Ospfv2,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ module = AnsibleModule(
+ argument_spec=Ospfv2Args.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+ result = Ospfv2(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_ospfv3.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_ospfv3.py
new file mode 100644
index 000000000..0d49c625b
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_ospfv3.py
@@ -0,0 +1,693 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2020 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_ospfv3
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: junos_ospfv3
+short_description: OSPFv3 resource module
+description:
+- This module manages global OSPFv3 configuration on devices running Juniper JUNOS.
+version_added: 1.2.0
+author: Rohit Thakur (@rohitthakur2590)
+requirements:
+- ncclient (>=v0.6.4)
+- xmltodict (>=0.12.0)
+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 list of OSPFv3 process configuration.
+ type: list
+ elements: dict
+ suboptions:
+ router_id:
+ description:
+ - The OSPFv3 router id.
+ type: str
+ areas:
+ description:
+ - A list of OSPFv3 areas' configuration.
+ type: list
+ elements: dict
+ suboptions:
+ area_id:
+ description:
+ - The Area ID as an integer or IP Address.
+ type: str
+ required: true
+ area_range:
+ description:
+ - Configure an address range for the area.
+ type: str
+ stub:
+ description:
+ - Settings for configuring the area as a stub.
+ type: dict
+ suboptions:
+ default_metric:
+ description:
+ - Metric for the default route in this area.
+ type: int
+ set:
+ description:
+ - Configure the area as a stub.
+ type: bool
+ interfaces:
+ description:
+ - List of interfaces in this area.
+ type: list
+ elements: dict
+ suboptions:
+ authentication:
+ description: Specify authentication type
+ type: dict
+ suboptions:
+ type:
+ description:
+ - Type of authentication to use.
+ type: dict
+ bandwidth_based_metrics:
+ description: Specify list of bandwidth based metrics
+ type: list
+ elements: dict
+ suboptions:
+ bandwidth:
+ description:
+ - BW to apply metric to.
+ type: str
+ choices: [1g, 10g]
+ metric:
+ description: Specify metric
+ type: int
+ name:
+ description:
+ - Name of the interface.
+ type: str
+ required: true
+ priority:
+ description:
+ - Priority for the interface.
+ type: int
+ metric:
+ description:
+ - Metric applied to the interface.
+ type: int
+ flood_reduction:
+ description:
+ - Enable flood reduction.
+ type: bool
+ passive:
+ description: Specify passive
+ type: bool
+ timers:
+ description: Specify timers
+ type: dict
+ suboptions:
+ dead_interval:
+ description:
+ - Dead interval (seconds).
+ type: int
+ hello_interval:
+ description:
+ - Hello interval (seconds).
+ type: int
+ poll_interval:
+ description:
+ - Poll interval (seconds).
+ type: int
+ retransmit_interval:
+ description:
+ - Retransmit interval (seconds).
+ type: int
+ transit_delay:
+ description:
+ - Transit delay (seconds).
+ type: int
+ external_preference:
+ description:
+ - Preference of external routes.
+ type: int
+ overload:
+ description: Specify time for overload mode reset
+ type: dict
+ suboptions:
+ timeout:
+ description:
+ - Time after which overload mode is reset (seconds).
+ type: int
+ preference:
+ description:
+ - Preference of internal routes.
+ type: int
+ prefix_export_limit:
+ description:
+ - Maximum number of external prefixes that can be exported.
+ type: int
+ reference_bandwidth:
+ description:
+ - Bandwidth for calculating metric defaults.
+ type: str
+ choices: [1g, 10g]
+ rfc1583compatibility:
+ description:
+ - Set RFC1583 compatibility
+ type: bool
+ spf_options:
+ description:
+ - Configure options for SPF.
+ type: dict
+ suboptions:
+ delay:
+ description:
+ - Time to wait before running an SPF (seconds).
+ type: int
+ holddown:
+ description:
+ - Time to hold down before running an SPF (seconds).
+ type: int
+ rapid_runs:
+ description:
+ - Number of maximum rapid SPF runs before holddown (seconds).
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show protocols ospf.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ default: merged
+"""
+EXAMPLES = """
+# Using merged
+#
+# Before state
+# ------------
+#
+# admin# show protocols ospf3
+
+- name: Merge Junos OSPFv3 config
+ junipernetworks.junos.junos_ospfv3:
+ config:
+ - areas:
+ - area_id: 0.0.0.100
+ stub:
+ default_metric: 200
+ set: true
+ interfaces:
+ - name: so-0/0/0.0
+ priority: 3
+ metric: 5
+ state: merged
+
+# After state
+# -----------
+#
+# adimn# show protocols ospf3
+# area 0.0.0.100 {
+# stub default-metric 200;
+# interface so-0/0/0.0 {
+# metric 5;
+# priority 3;
+# }
+# }
+# Using replaced
+#
+# Before state
+# ------------
+#
+# adimn# show protocols ospf3
+# area 0.0.0.100 {
+# stub default-metric 200;
+# interface so-0/0/0.0 {
+# metric 5;
+# priority 3;
+# }
+# }
+- name: Replace Junos OSPFv3 config
+ junipernetworks.junos.junos_ospfv3:
+ config:
+ - areas:
+ - area_id: 0.0.0.100
+ interfaces:
+ - name: so-0/0/0.0
+ state: replaced
+
+# After state
+# -----------
+#
+# admin# show protocols ospf3
+# area 0.0.0.100 {
+# interface so-0/0/0.0;
+# }
+# Using overridden
+#
+# Before state
+# ------------
+#
+# admin# show protocols ospf3
+# area 0.0.0.100 {
+# interface so-0/0/0.0;
+# }
+- name: Override Junos OSPFv3 config
+ junipernetworks.junos.junos_ospfv3:
+ config:
+ - areas:
+ - area_id: 0.0.0.100
+ stub:
+ default_metric: 200
+ set: true
+ interfaces:
+ - name: so-0/0/0.0
+ priority: 3
+ metric: 5
+ flood_reduction: true
+ passive: true
+ - area_id: 0.0.0.200
+ interfaces:
+ - name: ge-1/1/0.0
+ - name: ge-2/2/0.0
+ state: overridden
+
+# After state
+# -----------
+#
+# admin# show protocols ospf3
+# area 0.0.0.100 {
+# stub default-metric 200;
+# interface so-0/0/0.0 {
+# passive;
+# metric 5;
+# priority 3;
+# flood-reduction;
+# }
+# }
+# area 0.0.0.200 {
+# interface ge-1/1/0.0;
+# interface ge-2/2/0.0;
+# }
+#
+# Using deleted
+#
+# Before state
+# ------------
+#
+# adimn# show protocols ospf3
+# area 0.0.0.100 {
+# stub default-metric 200;
+# interface so-0/0/0.0 {
+# metric 5;
+# priority 3;
+# }
+# }
+
+- name: Delete Junos OSPFv3 config
+ junipernetworks.junos.junos_ospfv3:
+ config:
+ - areas:
+ - area_id: 0.0.0.100
+ interfaces:
+ - name: so-0/0/0.0
+ state: deleted
+
+# After state
+# -----------
+#
+# admin# show protocols ospf3
+# Using gathered
+#
+# Before state
+# ------------
+#
+# adimn# show protocols ospf3
+# area 0.0.0.100 {
+# stub default-metric 200;
+# interface so-0/0/0.0 {
+# passive;
+# metric 5;
+# priority 3;
+# flood-reduction;
+# }
+# }
+# area 0.0.0.200 {
+# interface ge-1/1/0.0;
+# interface ge-2/2/0.0;
+# }
+
+- name: Gather Junos OSPFv3 config
+ junipernetworks.junos.junos_ospfv3:
+ config:
+ state: gathered
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+# "gathered": {
+# "areas": [
+# {
+# "area_id": "0.0.0.100",
+# "interfaces": [
+# {
+# "flood_reduction": true,
+# "metric": 5,
+# "name": "so-0/0/0.0",
+# "passive": true,
+# "priority": 3
+# }
+# ],
+# "stub": {
+# "default_metric": 200,
+# "set": true
+# }
+# },
+# {
+# "area_id": "0.0.0.200",
+# "interfaces": [
+# {
+# "name": "ge-1/1/0.0"
+# },
+# {
+# "name": "ge-2/2/0.0"
+# }
+# ]
+# }
+# ],
+# }
+#
+# Using rendered
+#
+#
+- name: Render the commands for provided configuration
+ junipernetworks.junos.junos_ospfv3:
+ config:
+ - areas:
+ - area_id: 0.0.0.100
+ stub:
+ default_metric: 200
+ set: true
+ interfaces:
+ - name: so-0/0/0.0
+ priority: 3
+ metric: 5
+ flood_reduction: true
+ passive: true
+ - area_id: 0.0.0.200
+ interfaces:
+ - name: ge-1/1/0.0
+ - name: ge-2/2/0.0
+ state: rendered
+
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "rendered": "
+# <nc:protocols
+# xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# <nc:ospf3>
+# <nc:area>
+# <nc:name>0.0.0.100</nc:name>
+# <nc:interface>
+# <nc:name>so-0/0/0.0</nc:name>
+# <nc:priority>3</nc:priority>
+# <nc:flood-reduction/>
+# <nc:metric>5</nc:metric>
+# <nc:passive/>
+# </nc:interface>
+# <nc:stub>
+# <nc:default-metric>200</nc:default-metric>
+# </nc:stub>
+# </nc:area>
+# <nc:area>
+# <nc:name>0.0.0.200</nc:name>
+# <nc:interface>
+# <nc:name>ge-1/1/0.0</nc:name>
+# </nc:interface>
+# <nc:interface>
+# <nc:name>ge-2/2/0.0</nc:name>
+# </nc:interface>
+# </nc:area>
+# </nc:ospf3>
+# </nc:protocols>"
+#
+# Using parsed
+# parsed.cfg
+# ------------
+# <rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:junos="http://xml.juniper.net/junos/18.4R1/junos">
+# <data>
+# <configuration xmlns="http://xml.juniper.net/xnm/1.1/xnm"
+# junos:commit-seconds="1601355317" junos:commit-localtime="2020-09-29 04:55:17 UTC" junos:commit-user="rohit">
+# <version>18.4R1-S2.4</version>
+# <interfaces>
+# <interface>
+# <name>ge-0/0/0</name>
+# <description>Configured by Ansi-Team</description>
+# </interface>
+# <interface>
+# <name>gr-0/0/0</name>
+# <description>Configured Manually</description>
+# </interface>
+# <interface>
+# <name>fxp0</name>
+# <unit>
+# <name>0</name>
+# <family>
+# <inet>
+# <dhcp>
+# </dhcp>
+# </inet>
+# </family>
+# </unit>
+# </interface>
+# </interfaces>
+# <protocols>
+# <ospf3>
+# <area>
+# <name>0.0.0.100</name>
+# <stub>
+# <default-metric>200</default-metric>
+# </stub>
+# <interface>
+# <name>so-0/0/0.0</name>
+# <passive>
+# </passive>
+# <metric>5</metric>
+# <priority>3</priority>
+# <flood-reduction/>
+# </interface>
+# </area>
+# <area>
+# <name>0.0.0.200</name>
+# <interface>
+# <name>ge-1/1/0.0</name>
+# </interface>
+# <interface>
+# <name>ge-2/2/0.0</name>
+# </interface>
+# </area>
+# </ospf3>
+# </protocols>
+# <routing-options>
+# <router-id>10.200.16.75</router-id>
+# </routing-options>
+# </configuration>
+# <database-status-information>
+# <database-status>
+# <user>rohit</user>
+# <terminal>pts/0</terminal>
+# <pid>38210</pid>
+# <start-time junos:seconds="1601354977">2020-09-29 04:49:37 UTC</start-time>
+# <idle-time junos:seconds="546">00:09:06</idle-time>
+# <edit-path>[edit]</edit-path>
+# </database-status>
+# </database-status-information>
+# </data>
+# </rpc-reply>
+
+- name: Parsed the device configuration to get output commands
+ junipernetworks.junos.junos_ospfv3:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "parsed": [
+# {
+# "areas": [
+# {
+# "area_id": "0.0.0.100",
+# "interfaces": [
+# {
+# "flood_reduction": true,
+# "metric": 5,
+# "name": "so-0/0/0.0",
+# "passive": true,
+# "priority": 3
+# }
+# ],
+# "stub": {
+# "default_metric": 200,
+# "set": true
+# }
+# },
+# {
+# "area_id": "0.0.0.200",
+# "interfaces": [
+# {
+# "name": "ge-1/1/0.0"
+# },
+# {
+# "name": "ge-2/2/0.0"
+# }
+# ]
+# }
+# ],
+# }
+# ]
+#
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ type: dict
+ 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: 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: ['<nc:protocols
+ xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ <nc:ospf3 delete=\"delete\"/>
+ <nc:ospf3>
+ <nc:area>
+ <nc:name>0.0.0.100</nc:name>
+ <nc:interface>
+ <nc:name>so-0/0/0.0</nc:name>
+ <nc:priority>3</nc:priority>
+ <nc:flood-reduction/>
+ <nc:metric>5</nc:metric>
+ <nc:passive/>
+ </nc:interface>
+ <nc:stub>
+ <nc:default-metric>200</nc:default-metric>
+ </nc:stub>
+ </nc:area>
+ <nc:area>
+ <nc:name>0.0.0.200</nc:name>
+ <nc:interface>
+ <nc:name>ge-1/1/0.0</nc:name>
+ </nc:interface>
+ <nc:interface>
+ <nc:name>ge-2/2/0.0</nc:name>
+ </nc:interface>
+ </nc:area>
+ </nc:ospf3>
+</nc:protocols>",
+ "
+<nc:routing-options
+ xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ <nc:router-id delete=\"delete\"/>
+ <nc:router-id>10.200.16.75</nc:router-id>
+</nc:routing-options>', 'xml 2', 'xml 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.ospfv3.ospfv3 import (
+ Ospfv3Args,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.ospfv3.ospfv3 import (
+ Ospfv3,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ module = AnsibleModule(
+ argument_spec=Ospfv3Args.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+ result = Ospfv3(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_package.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_package.py
new file mode 100644
index 000000000..0cffb4ddb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_package.py
@@ -0,0 +1,218 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_package
+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
+version_added: 1.0.0
+extends_documentation_fragment:
+- junipernetworks.junos.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
+ type: path
+ 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.
+ type: str
+ 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.
+ 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
+ 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
+ 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
+ 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
+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
+ junipernetworks.junos.junos_package:
+ src: junos-vsrx-12.1X46-D10.2-domestic.tgz
+
+- name: install local package on remote device without rebooting
+ junipernetworks.junos.junos_package:
+ src: junos-vsrx-12.1X46-D10.2-domestic.tgz
+ reboot: no
+
+- name: install local package on remote device with jumpost
+ junipernetworks.junos.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_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ 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),
+ 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"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ 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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_ping.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_ping.py
new file mode 100644
index 000000000..4c373474c
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_ping.py
@@ -0,0 +1,290 @@
+#!/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
+
+
+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(ansible.netcommon.net_ping) module.
+- For Windows targets, use the M(ansible.windows.win_ping) module instead.
+- For targets running Python, use the M(ansible.builtin.ping) module instead.
+version_added: 1.0.0
+extends_documentation_fragment:
+- junipernetworks.junos.junos
+author:
+- Nilashish Chakraborty (@NilashishC)
+options:
+ dest:
+ description:
+ - The IP Address or hostname (resolvable by the device) of the remote node.
+ type: str
+ required: true
+ df_bit:
+ description:
+ - Determines whether to set the DF bit.
+ type: bool
+ default: false
+ rapid:
+ description:
+ - Determines whether to send the packets rapidly.
+ type: bool
+ default: false
+ 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).
+ type: str
+ interface:
+ description:
+ - The source interface to use while sending the ping packet(s).
+ type: str
+ 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.
+ type: str
+ choices:
+ - absent
+ - present
+ default: present
+notes:
+- For a general purpose network module, see the M(ansible.netcommon.net_ping) module.
+- For Windows targets, use the M(ansible.windows.win_ping) module instead.
+- For targets running Python, use the M(ansible.builtin.ping) module instead.
+- This module works only with connection C(network_cli).
+"""
+
+EXAMPLES = """
+- name: Test reachability to 10.10.10.10
+ junipernetworks.junos.junos_ping:
+ dest: 10.10.10.10
+
+- name: Test reachability to 10.20.20.20 using source and size set
+ junipernetworks.junos.junos_ping:
+ dest: 10.20.20.20
+ size: 1024
+ ttl: 128
+
+- name: Test unreachability to 10.30.30.30 using interval
+ junipernetworks.junos.junos_ping:
+ dest: 10.30.30.30
+ interval: 3
+ state: absent
+
+- name: Test reachability to 10.40.40.40 setting count and interface
+ junipernetworks.junos.junos_ping:
+ dest: 10.40.40.40
+ interface: fxp0
+ count: 20
+ size: 512
+
+- name: Test reachability to 10.50.50.50 using do-not-fragment and rapid
+ junipernetworks.junos.junos_ping:
+ dest: 10.50.50.50
+ df_bit: True
+ rapid: True
+"""
+
+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_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ 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),
+ df_bit=dict(type="bool", default=False),
+ rapid=dict(type="bool", default=False),
+ 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",
+ ),
+ )
+
+ module = AnsibleModule(argument_spec=argument_spec)
+
+ count = module.params["count"]
+ dest = module.params["dest"]
+ df_bit = module.params["df_bit"]
+ rapid = module.params["rapid"]
+ 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,
+ df_bit,
+ rapid,
+ )
+ 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,
+ df_bit=False,
+ rapid=False,
+):
+ 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))
+
+ if df_bit:
+ cmd += " do-not-fragment"
+
+ if rapid:
+ cmd += " rapid"
+
+ 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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_prefix_lists.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_prefix_lists.py
new file mode 100644
index 000000000..40b101f44
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_prefix_lists.py
@@ -0,0 +1,682 @@
+#!/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_prefix_lists
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+ANSIBLE_METADATA = {
+ "metadata_version": "1.1",
+ "status": ["preview"],
+ "supported_by": "network",
+}
+
+DOCUMENTATION = """
+---
+module: junos_prefix_lists
+version_added: 2.1.0
+short_description: Manage prefix-lists attributes of interfaces on Junos devices.
+description: Manage prefix-lists attributes of interfaces on Junos network devices.
+author: Rohit Thakur (@rohitthakur2590)
+requirements:
+ - ncclient (>=v0.6.4)
+ - xmltodict (>=0.12.0)
+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,https://docs.ansible.com/ansible/latest/network/user_guide/platform_junos.html).
+ - Tested against JunOS v18.4R1
+options:
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show policy-options).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ config:
+ description: The provided link BGP address family dictionary.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify the name of the prefix-list.
+ type: str
+ required: true
+ address_prefixes:
+ description: Specify address prefixes.
+ type: list
+ elements: str
+ dynamic_db:
+ description: Enable object to exist in dynamic DB.
+ type: bool
+ state:
+ description:
+ - The state the configuration should be left in.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - parsed
+ - gathered
+ - rendered
+ default: merged
+"""
+EXAMPLES = """
+# Using merged
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show policy-options
+#
+# [edit]
+
+- name: Merge Junos prefix lists
+ junipernetworks.junos.junos_prefix_lists:
+ config:
+ - name: Internal
+ address_prefixes:
+ - 172.16.1.32
+ - 172.16.3.32
+ - name: Test1
+ dynamic_db: true
+ - name: Test2
+ address_prefixes:
+ - 172.16.2.32
+ - 172.16.7.32
+ - 172.16.9.32
+ state: merged
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+# "before": []
+# "commands": [
+# "<nc:policy-options xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# "<nc:prefix-list><nc:name>Internal</nc:name><nc:prefix-list-item><nc:name>172.16.1.32</nc:name>"
+# "</nc:prefix-list-item><nc:prefix-list-item><nc:name>172.16.3.32</nc:name>"
+# "</nc:prefix-list-item></nc:prefix-list><nc:prefix-list><nc:name>Test1</nc:name>"
+# "<nc:dynamic-db/></nc:prefix-list><nc:prefix-list><nc:name>Test2</nc:name>"
+# "<nc:prefix-list-item><nc:name>172.16.2.32</nc:name></nc:prefix-list-item>"
+# "<nc:prefix-list-item><nc:name>172.16.7.32</nc:name></nc:prefix-list-item>"
+# "<nc:prefix-list-item><nc:name>172.16.9.32</nc:name></nc:prefix-list-item>"
+# "</nc:prefix-list></nc:policy-options>"
+# ]
+#
+# "after": [
+# {
+# "address_prefixes": [
+# "172.16.1.32/32",
+# "172.16.3.32/32"
+# ],
+# "name": "Internal"
+# },
+# {
+# "dynamic_db": true,
+# "name": "Test1"
+# },
+# {
+# "address_prefixes": [
+# "172.16.2.32/32",
+# "172.16.7.32/32",
+# "172.16.9.32/32"
+# ],
+# "name": "Test2"
+# }
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show policy-options
+# prefix-list Internal {
+# 172.16.1.32/32;
+# 172.16.3.32/32;
+# }
+# prefix-list Test1 {
+# dynamic-db;
+# }
+# prefix-list Test2 {
+# 172.16.2.32/32;
+# 172.16.7.32/32;
+# 172.16.9.32/32;
+# }
+#
+# Using gathered
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show policy-options
+# prefix-list Internal {
+# 172.16.1.32/32;
+# 172.16.3.32/32;
+# }
+# prefix-list Test1 {
+# dynamic-db;
+# }
+# prefix-list Test2 {
+# 172.16.2.32/32;
+# 172.16.7.32/32;
+# 172.16.9.32/32;
+# }
+
+- name: Gather Junos prefix-lists
+ junipernetworks.junos.junos_prefix_lists:
+ state: gathered
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+# "gathered": [
+# {
+# "address_prefixes": [
+# "172.16.1.32/32",
+# "172.16.3.32/32"
+# ],
+# "name": "Internal"
+# },
+# {
+# "dynamic_db": true,
+# "name": "Test1"
+# },
+# {
+# "address_prefixes": [
+# "172.16.2.32/32",
+# "172.16.7.32/32",
+# "172.16.9.32/32"
+# ],
+# "name": "Test2"
+# }
+# ]
+#
+# Using replaced
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show policy-options
+# prefix-list Internal {
+# 172.16.1.32/32;
+# 172.16.3.32/32;
+# }
+# prefix-list Test1 {
+# dynamic-db;
+# }
+# prefix-list Test2 {
+# 172.16.2.32/32;
+# 172.16.7.32/32;
+# 172.16.9.32/32;
+# }
+- name: Replace existing Junos prefix-lists configuration with provided config
+ junipernetworks.junos.junos_prefix_lists:
+ config:
+ - name: Test2
+ address_prefixes:
+ - 172.16.4.32
+ - 172.16.8.32
+ - 172.16.9.32"
+ state: replaced
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+# "before": [
+# {
+# "address_prefixes": [
+# "172.16.1.32/32",
+# "172.16.3.32/32"
+# ],
+# "name": "Internal"
+# },
+# {
+# "dynamic_db": true,
+# "name": "Test1"
+# },
+# {
+# "address_prefixes": [
+# "172.16.2.32/32",
+# "172.16.7.32/32",
+# "172.16.9.32/32"
+# ],
+# "name": "Test2"
+# }
+# ]
+# "commands": [
+# "<nc:policy-options xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# "<nc:prefix-list delete=\"delete\"><nc:name>Test2</nc:name></nc:prefix-list>"
+# "<nc:prefix-list><nc:name>Test2</nc:name><nc:prefix-list-item><nc:name>172.16.4.32</nc:name>"
+# "</nc:prefix-list-item><nc:prefix-list-item><nc:name>172.16.8.32</nc:name>"
+# "</nc:prefix-list-item><nc:prefix-list-item><nc:name>172.16.9.32</nc:name>"
+# "</nc:prefix-list-item></nc:prefix-list></nc:policy-options>"
+# ]
+#
+# "after": [
+# {
+# "address_prefixes": [
+# "172.16.1.32/32",
+# "172.16.3.32/32"
+# ],
+# "name": "Internal"
+# },
+# {
+# "dynamic_db": true,
+# "name": "Test1"
+# },
+# {
+# "address_prefixes": [
+# "172.16.4.32/32",
+# "172.16.8.32/32",
+# "172.16.9.32/32"
+# ],
+# "name": "Test2"
+# }
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show policy-options
+# prefix-list Internal {
+# 172.16.1.32/32;
+# 172.16.3.32/32;
+# }
+# prefix-list Test1 {
+# dynamic-db;
+# }
+# prefix-list Test2 {
+# 172.16.4.32/32;
+# 172.16.8.32/32;
+# 172.16.9.32/32;
+# }
+# Using overridden
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show policy-options
+# prefix-list Internal {
+# 172.16.1.32/32;
+# 172.16.3.32/32;
+# }
+# prefix-list Test1 {
+# dynamic-db;
+# }
+# prefix-list Test2 {
+# 172.16.4.32/32;
+# 172.16.8.32/32;
+# 172.16.9.32/32;
+# }
+- name: Override Junos prefix-lists configuration with provided configuration
+ junipernetworks.junos.junos_prefix_lists:
+ config:
+ - name: Test2
+ address_prefixes:
+ - 172.16.4.32/28
+ - 172.16.8.32/28
+ - 172.16.9.32/28
+ state: overridden
+
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+# "before": [
+# {
+# "address_prefixes": [
+# "172.16.1.32/32",
+# "172.16.3.32/32"
+# ],
+# "name": "Internal"
+# },
+# {
+# "dynamic_db": true,
+# "name": "Test1"
+# },
+# {
+# "address_prefixes": [
+# "172.16.4.32/32",
+# "172.16.8.32/32",
+# "172.16.9.32/32"
+# ],
+# "name": "Test2"
+# }
+# ]
+# "commands": [
+# "<nc:policy-options xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# "<nc:prefix-list delete=\"delete\"><nc:name>Internal</nc:name>"
+# "</nc:prefix-list><nc:prefix-list delete=\"delete\"><nc:name>Test1</nc:name>"
+# "</nc:prefix-list><nc:prefix-list delete=\"delete\"><nc:name>Test2</nc:name>"
+# "</nc:prefix-list><nc:prefix-list><nc:name>Test2</nc:name><nc:prefix-list-item>"
+# "<nc:name>172.16.4.32/28</nc:name></nc:prefix-list-item><nc:prefix-list-item>"
+# "<nc:name>172.16.8.32/28</nc:name></nc:prefix-list-item><nc:prefix-list-item>"
+# "<nc:name>172.16.9.32/28</nc:name></nc:prefix-list-item></nc:prefix-list></nc:policy-options>"
+# ]
+#
+# "after": [
+# {
+# "address_prefixes": [
+# "172.16.4.32/28",
+# "172.16.8.32/28",
+# "172.16.9.32/28"
+# ],
+# "name": "Test2"
+# }
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show policy-options
+# prefix-list Test2 {
+# 172.16.4.32/28;
+# 172.16.8.32/28;
+# 172.16.9.32/28;
+# }
+# Using deleted
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show policy-options
+# prefix-list Internal {
+# 172.16.1.32/32;
+# 172.16.3.32/32;
+# }
+# prefix-list Test1 {
+# dynamic-db;
+# }
+# prefix-list Test2 {
+# 172.16.2.32/32;
+# 172.16.7.32/32;
+# 172.16.9.32/32;
+# }
+
+- name: Delete provided prefix-lists
+ junipernetworks.junos.junos_prefix_lists:
+ config:
+ - name: "Test1"
+ - name: "Test2"
+ state: deleted
+# ------------------------
+# Module Execution Results
+# ------------------------
+#
+# "before": [
+# {
+# "address_prefixes": [
+# "172.16.1.32/32",
+# "172.16.3.32/32"
+# ],
+# "name": "Internal"
+# },
+# {
+# "dynamic_db": true,
+# "name": "Test1"
+# },
+# {
+# "address_prefixes": [
+# "172.16.2.32/32",
+# "172.16.7.32/32",
+# "172.16.9.32/32"
+# ],
+# "name": "Test2"
+# }
+# ]
+# "commands": [
+# "<nc:policy-options xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# "<nc:prefix-list delete=\"delete\"><nc:name>Test1</nc:name></nc:prefix-list>"
+# "<nc:prefix-list delete=\"delete\"><nc:name>Test2</nc:name></nc:prefix-list></nc:policy-options>"
+# ]
+#
+# "after": [
+# {
+# "address_prefixes": [
+# "172.16.1.32/32",
+# "172.16.3.32/32"
+# ],
+# "name": "Internal"
+# }
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show policy-options
+# prefix-list Internal {
+# 172.16.1.32/32;
+# 172.16.3.32/32;
+# }
+#
+# Using deleted without specifying config
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show policy-options
+# prefix-list Internal {
+# 172.16.1.32/32;
+# 172.16.3.32/32;
+# }
+# prefix-list Test1 {
+# dynamic-db;
+# }
+# prefix-list Test2 {
+# 172.16.2.32/32;
+# 172.16.7.32/32;
+# 172.16.9.32/32;
+# }
+
+- name: Delete complete Junos prefix-lists configuration
+ junipernetworks.junos.junos_prefix_lists:
+ state: deleted
+
+# ------------------------
+# Module Execution Results
+# ------------------------
+#
+# "before": [
+# {
+# "address_prefixes": [
+# "172.16.1.32/32",
+# "172.16.3.32/32"
+# ],
+# "name": "Internal"
+# },
+# {
+# "dynamic_db": true,
+# "name": "Test1"
+# },
+# {
+# "address_prefixes": [
+# "172.16.2.32/32",
+# "172.16.7.32/32",
+# "172.16.9.32/32"
+# ],
+# "name": "Test2"
+# }
+# ]
+# "commands": ["<nc:policy-options xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# "<nc:prefix-list delete=\"delete\"/></nc:policy-options>"
+# ]
+#
+# "after": []
+# After state
+# -----------
+#
+# vagrant@vsrx# show policy-options
+#
+# [edit]
+
+#
+# Using parsed
+# parsed.cfg
+# ------------
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <version>18.4R1-S2.4</version>
+# <policy-options>
+# <prefix-list>
+# <name>64510</name>
+# </prefix-list>
+# <prefix-list>
+# <name>64500</name>
+# <dynamic-db/>
+# <prefix-list-item>
+# <name>172.16.1.16/28</name>
+# </prefix-list-item>
+# <prefix-list-item>
+# <name>172.16.1.32/28</name>
+# </prefix-list-item>
+# </prefix-list>
+# </policy-options>
+# </configuration>
+# </rpc-reply>
+- name: Parse running prefix-lists configuration
+ junipernetworks.junos.junos_prefix_lists:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "parsed": [
+# {
+# "name": "64510"
+# },
+# {
+# "address_prefixes": [
+# "172.16.1.16/28",
+# "172.16.1.32/28"
+# ],
+# "dynamic_db": true,
+# "name": "64500"
+# }
+# ]
+#
+#
+# Using rendered
+#
+- name: Render the xml for provided configuration
+ junipernetworks.junos.junos_prefix_lists:
+ config:
+ - name: Internal
+ address_prefixes:
+ - 172.16.1.32
+ - 172.16.3.32
+ - name: Test1
+ dynamic_db: true
+ - name: Test2
+ address_prefixes:
+ - 172.16.2.32
+ - 172.16.7.32
+ - 172.16.9.32
+ state: rendered
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "rendered": "<nc:policy-options xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# "<nc:prefix-list><nc:name>Internal</nc:name><nc:prefix-list-item><nc:name>172.16.1.32</nc:name>"
+# "</nc:prefix-list-item><nc:prefix-list-item><nc:name>172.16.3.32</nc:name></nc:prefix-list-item>"
+# "</nc:prefix-list><nc:prefix-list><nc:name>Test1</nc:name><nc:dynamic-db/></nc:prefix-list>"
+# "<nc:prefix-list><nc:name>Test2</nc:name><nc:prefix-list-item><nc:name>172.16.2.32</nc:name>"
+# "</nc:prefix-list-item><nc:prefix-list-item><nc:name>172.16.7.32</nc:name></nc:prefix-list-item>"
+# "<nc:prefix-list-item><nc:name>172.16.9.32</nc:name></nc:prefix-list-item>"
+# "</nc:prefix-list></nc:policy-options>"
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: list
+after:
+ description: The resulting configuration model invocation.
+ 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: ['<nc:policy-options xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ "<nc:prefix-list delete=\"delete\"/></nc:policy-options>"', 'xml 2', 'command 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.prefix_lists.prefix_lists import (
+ Prefix_listsArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.prefix_lists.prefix_lists import (
+ Prefix_lists,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ module = AnsibleModule(
+ argument_spec=Prefix_listsArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+ result = Prefix_lists(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_routing_instances.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_routing_instances.py
new file mode 100644
index 000000000..1b7c1c995
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_routing_instances.py
@@ -0,0 +1,766 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2021 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_routing_instances
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+ANSIBLE_METADATA = {
+ "metadata_version": "1.1",
+ "status": ["preview"],
+ "supported_by": "network",
+}
+
+DOCUMENTATION = """
+---
+module: junos_routing_instances
+version_added: 2.1.0
+short_description: Manage routing instances on Junos devices.
+description: Manage routing instances on Junos network devices.
+author: Rohit Thakur (@rohitthakur2590)
+requirements:
+ - ncclient (>=v0.6.4)
+ - xmltodict (>=0.12.0)
+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:
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show routing-instances).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ config:
+ description: The provided Routing instance configuration list.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify routing instance name.
+ type: str
+ connector_id_advertise:
+ description: Advertise connector-id attribute.
+ type: bool
+ description:
+ description: Specify text description of routing instance.
+ type: str
+ egress_protection:
+ description: Egress instance protection dictionary.
+ type: dict
+ suboptions:
+ context_identifier:
+ description: Specify context identifier.
+ type: str
+ protector:
+ description: Enable Edge Protector functionality for this VPN.
+ type: bool
+ instance_role:
+ description: Primary role of L2Backhaul-vpn router.
+ type: str
+ choices: ['access', 'nni']
+ type:
+ description: Specify instance type.
+ type: str
+ choices:
+ - evpn
+ - evpn-vpws
+ - forwarding
+ - l2backhaul-vpn
+ - l2vpn
+ - layer2-control
+ - mac-vrf
+ - mpls-forwarding
+ - mpls-internet-multicast
+ - no-forwarding
+ - virtual-router
+ - vpls
+ - vrf
+ interfaces:
+ description: Interface name for this routing instance.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify name of the interface.
+ type: str
+ protect_interface:
+ description: Specify name of the protected interface.
+ type: str
+ l2vpn_id:
+ description: Layer-2 vpn-id for this instance.
+ type: str
+ no_irb_layer_2_copy:
+ description: Disable transmission of layer-2 copy of packets of irb routing-interface.
+ type: bool
+ no_normalization:
+ description: Disable vlan id normalization for interfaces.
+ type: bool
+ no_local_switching:
+ description: Disable vlan id normalization for interfaces.
+ type: bool
+ no_vrf_advertise:
+ description: Disable vlan id normalization for interfaces.
+ type: bool
+ no_vrf_propagate_ttl:
+ description: Disable TTL propagation from IP to MPLS (on push) and MPLS to IP (on pop).
+ type: bool
+ qualified_bum_pruning_mode:
+ description: Enable BUM pruning for VPLS instance.
+ type: bool
+ route_distinguisher:
+ description: Route distinguisher for this instance
+ type: str
+ routing_interface:
+ description: Routing interface name for this routing-instance.
+ type: list
+ elements: str
+ vrf_imports:
+ description: Import policy for VRF instance RIBs.
+ type: list
+ elements: str
+ vrf_exports:
+ description: Export policy for VRF instance RIBs.
+ type: list
+ elements: str
+ state:
+ description:
+ - The state the configuration should be left in.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - parsed
+ - gathered
+ - rendered
+ default: merged
+"""
+EXAMPLES = """
+# Using merged
+#
+# Before state
+# ------------
+#
+# admin# show routing-instances
+#
+# [edit]
+# vagrant@vsrx# show policy-options
+# policy-statement test-policy {
+# term t1 {
+# then reject;
+# }
+# }
+# policy-statement test-policy-1 {
+# term t1 {
+# then reject;
+# }
+# }
+
+- name: Merge Junos BGP address family configuration
+ junipernetworks.junos.junos_routing_instances:
+ config:
+ - name: "test"
+ type: "vrf"
+ route_distinguisher: "10.58.255.1:37"
+ vrf_imports:
+ - "test-policy"
+ vrf_exports:
+ - "test-policy"
+ - "test-policy-1"
+ interfaces:
+ - name: "sp-0/0/0.0"
+ - name: "gr-0/0/0.0"
+ connector_id_advertise: true
+ - name: "forwardinst"
+ type: "forwarding"
+ description: "Configured by Ansible Content Team"
+ state: merged
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+# After state
+# -----------
+#
+# admin# show routing-instances
+# forwardinst {
+# description "Configured by Ansible Content Team";
+# instance-type forwarding;
+# }
+# test {
+# instance-type vrf;
+# interface gr-0/0/0.0; ## 'gr-0/0/0.0' is not defined
+# interface sp-0/0/0.0; ## 'sp-0/0/0.0' is not defined
+# route-distinguisher 10.58.255.1:37;
+# vrf-import test-policy;
+# vrf-export [ test-policy test-policy-1 ];
+# connector-id-advertise;
+# }
+#
+# Using gathered
+#
+# Before state
+# ------------
+#
+# admin# show routing-instances
+#
+# [edit]
+# admin# show routing-instances
+# forwardinst {
+# description "Configured by Ansible Content Team";
+# instance-type forwarding;
+# }
+# test {
+# instance-type vrf;
+# interface gr-0/0/0.0; ## 'gr-0/0/0.0' is not defined
+# interface sp-0/0/0.0; ## 'sp-0/0/0.0' is not defined
+# route-distinguisher 10.58.255.1:37;
+# vrf-import test-policy;
+# vrf-export [ test-policy test-policy-1 ];
+# connector-id-advertise;
+# }
+- name: Gather Junos routing-instances
+ junipernetworks.junos.junos_routing_instances:
+ state: gathered
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+# "gathered": [
+# {
+# "description": "Configured by Ansible Content Team",
+# "name": "forwardinst",
+# "type": "forwarding"
+# },
+# {
+# "connector_id_advertise": true,
+# "interfaces": [
+# {
+# "name": "gr-0/0/0.0"
+# },
+# {
+# "name": "sp-0/0/0.0"
+# }
+# ],
+# "name": "test",
+# "route_distinguisher": "10.58.255.1:37",
+# "type": "vrf",
+# "vrf_exports": [
+# "test-policy",
+# "test-policy-1"
+# ],
+# "vrf_imports": [
+# "test-policy"
+# ]
+# }
+# ]
+#
+# Using replaced
+#
+# Before state
+# ------------
+#
+# admin# show routing-instances
+# forwardinst {
+# description "Configured by Ansible Content Team";
+# instance-type forwarding;
+# }
+# test {
+# instance-type vrf;
+# interface gr-0/0/0.0; ## 'gr-0/0/0.0' is not defined
+# interface sp-0/0/0.0; ## 'sp-0/0/0.0' is not defined
+# route-distinguisher 10.58.255.1:37;
+# vrf-import test-policy;
+# vrf-export [ test-policy test-policy-1 ];
+# connector-id-advertise;
+# }
+
+- name: Replace existing Junos routing instance config with provided config
+ junipernetworks.junos.junos_routing_instances:
+ config:
+ address_family:
+ - name: "test"
+ type: "vrf"
+ route_distinguisher: "10.57.255.1:37"
+ vrf_imports:
+ - "test-policy"
+ vrf_exports:
+ - "test-policy"
+ interfaces:
+ - name: "sp-0/0/0.0"
+ - name: "gr-0/0/0.0"
+ connector_id_advertise: false
+ description: "Configured by Ansible Content Team"
+ state: replaced
+
+# After state
+# -----------
+#
+# admin@vsrx# show routing-instances
+# forwardinst {
+# description "Configured by Ansible Content Team";
+# instance-type forwarding;
+# }
+# test {
+# description "Configured by Ansible Content Team";
+# instance-type vrf;
+# interface gr-0/0/0.0; ## 'gr-0/0/0.0' is not defined
+# interface sp-0/0/0.0; ## 'sp-0/0/0.0' is not defined
+# route-distinguisher 10.57.255.1:37;
+# vrf-import test-policy;
+# vrf-export test-policy;
+# }
+
+# Using overridden
+#
+# Before state
+# ------------
+#
+# admin@vsrx# show routing-instances
+# forwardinst {
+# description "Configured by Ansible Content Team";
+# instance-type forwarding;
+# }
+# test {
+# description "Configured by Ansible Content Team";
+# instance-type vrf;
+# interface gr-0/0/0.0; ## 'gr-0/0/0.0' is not defined
+# interface sp-0/0/0.0; ## 'sp-0/0/0.0' is not defined
+# route-distinguisher 10.57.255.1:37;
+# vrf-import test-policy;
+# vrf-export test-policy;
+# }
+
+- name: Override Junos routing-instances configuration
+ junipernetworks.junos.junos_routing_instances:
+ config:
+ - name: "test"
+ type: "vrf"
+ route_distinguisher: "10.58.255.1:37"
+ vrf_imports:
+ - "test-policy"
+ vrf_exports:
+ - "test-policy"
+ - "test-policy-1"
+ interfaces:
+ - name: "sp-0/0/0.0"
+ - name: "gr-0/0/0.0"
+ connector_id_advertise: true
+ - name: "forwardinst"
+ type: "forwarding"
+ description: "Configured by Ansible Content Team"
+ - name: "vtest1"
+ type: "virtual-router"
+ state: overridden
+
+# After state
+# -----------
+#
+# admin@vsrx# show routing-instances
+# forwardinst {
+# description "Configured by Ansible Content Team";
+# instance-type forwarding;
+# }
+# test {
+# instance-type vrf;
+# interface gr-0/0/0.0; ## 'gr-0/0/0.0' is not defined
+# interface sp-0/0/0.0; ## 'sp-0/0/0.0' is not defined
+# route-distinguisher 10.58.255.1:37;
+# vrf-import test-policy;
+# vrf-export [ test-policy test-policy-1 ];
+# connector-id-advertise;
+# }
+# vtest1 {
+# instance-type virtual-router;
+# }
+
+
+# Using deleted
+#
+# Before state
+# ------------
+#
+# admin@vsrx# show routing-instances
+# forwardinst {
+# description "Configured by Ansible Content Team";
+# instance-type forwarding;
+# }
+# test {
+# instance-type vrf;
+# interface gr-0/0/0.0; ## 'gr-0/0/0.0' is not defined
+# interface sp-0/0/0.0; ## 'sp-0/0/0.0' is not defined
+# route-distinguisher 10.58.255.1:37;
+# vrf-import test-policy;
+# vrf-export [ test-policy test-policy-1 ];
+# connector-id-advertise;
+# }
+
+- name: Delete provided junos routing-instamce
+ junipernetworks.junos.junos_routing_instances:
+ config:
+ - name: "test"
+ state: deleted
+
+# After state
+# -----------
+#
+# admin@vsrx# show routing-instances
+# forwardinst {
+# description "Configured by Ansible Content Team";
+# instance-type forwarding;
+# }
+
+# Using deleted without config
+#
+# Before state
+# ------------
+#
+# admin@vsrx# show routing-instances
+# forwardinst {
+# description "Configured by Ansible Content Team";
+# instance-type forwarding;
+# }
+# test {
+# instance-type vrf;
+# interface gr-0/0/0.0; ## 'gr-0/0/0.0' is not defined
+# interface sp-0/0/0.0; ## 'sp-0/0/0.0' is not defined
+# route-distinguisher 10.58.255.1:37;
+# vrf-import test-policy;
+# vrf-export [ test-policy test-policy-1 ];
+# connector-id-advertise;
+# }
+# vtest1 {
+# instance-type virtual-router;
+# }
+
+- name: Delete complete Junos routing-instances config
+ junipernetworks.junos.junos_routing_instances:
+ config:
+ state: deleted
+
+# After state
+# -----------
+#
+# admin@vsrx# show routing-instances
+#
+# [edit]
+
+- name: Gather Junos BGP address family config
+ junipernetworks.junos.junos_routing_instances:
+ config:
+ state: gathered
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+# "gathered": {
+# "address_family": [
+# {
+# "af_type": [
+# {
+# "accepted_prefix_limit": {
+# "idle_timeout_value": 2001,
+# "limit_threshold": 98,
+# "maximum": 20
+# },
+# "damping": true,
+# "defer_initial_multipath_build": {
+# "maximum_delay": 2
+# },
+# "type": "signaling"
+# }
+# ],
+# "afi": "evpn"
+# },
+# {
+# "af_type": [
+# {
+# "accepted_prefix_limit": {
+# "idle_timeout_value": 2000,
+# "limit_threshold": 99,
+# "maximum": 20
+# },
+# "damping": true,
+# "defer_initial_multipath_build": {
+# "maximum_delay": 2
+# },
+# "delay_route_advertisements": {
+# "max_delay_route_age": 20,
+# "max_delay_routing_uptime": 32000,
+# "min_delay_inbound_convergence": 32000,
+# "min_delay_routing_uptime": 23000
+# },
+# "graceful_restart_forwarding_state_bit": "from-fib",
+# "type": "any"
+# },
+# {
+# "legacy_redirect_ip_action": {
+# "receive": true,
+# "send": true
+# },
+# "loops": 4,
+# "no_install": true,
+# "output_queue_priority_expedited": true,
+# "secondary_independent_resolution": true,
+# "type": "flow"
+# },
+# {
+# "entropy_label": {
+# "no_next_hop_validation": true
+# },
+# "explicit_null": {
+# "connected_only": true
+# },
+# "per_group_label": true,
+# "per_prefix_label": true,
+# "prefix_limit": {
+# "forever": true,
+# "limit_threshold": 99,
+# "maximum": 20
+# },
+# "resolve_vpn": true,
+# "rib": "inet.3",
+# "route_refresh_priority_priority": 3,
+# "type": "labeled-unicast"
+# },
+# {
+# "extended_nexthop": true,
+# "extended_nexthop_color": true,
+# "local_ipv4_address": "9.9.9.9",
+# "type": "unicast"
+# }
+# ],
+# "afi": "inet"
+# }
+# ]
+# }
+#
+# Using parsed
+# parsed.cfg
+# ------------
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <version>18.4R1-S2.4</version>
+# <routing-instances>
+# <instance>
+# <name>forwardinst</name>
+# <description>Configured by Ansible Content Team</description>
+# <instance-type>forwarding</instance-type>
+# </instance>
+# <instance>
+# <name>test</name>
+# <instance-type>vrf</instance-type>
+# <interface>
+# <name>gr-0/0/0.0</name>
+# </interface>
+# <interface>
+# <name>sp-0/0/0.0</name>
+# </interface>
+# <route-distinguisher>
+# <rd-type>10.58.255.1:37</rd-type>
+# </route-distinguisher>
+# <vrf-import>test-policy</vrf-import>
+# <vrf-export>test-policy</vrf-export>
+# <vrf-export>test-policy-1</vrf-export>
+# <connector-id-advertise/>
+# </instance>
+# </routing-instances>
+# </configuration>
+# </rpc-reply>
+
+- name: Parse routing instance running config
+ junipernetworks.junos.junos_routing_instances:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "parsed": [
+# {
+# "description": "Configured by Ansible Content Team",
+# "name": "forwardinst",
+# "type": "forwarding"
+# },
+# {
+# "connector_id_advertise": true,
+# "interfaces": [
+# {
+# "name": "gr-0/0/0.0"
+# },
+# {
+# "name": "sp-0/0/0.0"
+# }
+# ],
+# "name": "test",
+# "route_distinguisher": "10.58.255.1:37",
+# "type": "vrf",
+# "vrf_exports": [
+# "test-policy",
+# "test-policy-1"
+# ],
+# "vrf_imports": [
+# "test-policy"
+# ]
+# }
+# ]
+#
+#
+# Using rendered
+#
+#
+- name: Render the xml for provided configuration
+ junipernetworks.junos.junos_routing_instances:
+ config:
+ - name: "test"
+ type: "vrf"
+ route_distinguisher: "10.58.255.1:37"
+ vrf_imports:
+ - "test-policy"
+ vrf_exports:
+ - "test-policy"
+ - "test-policy-1"
+ interfaces:
+ - name: "sp-0/0/0.0"
+ - name: "gr-0/0/0.0"
+ connector_id_advertise: true
+ - name: "forwardinst"
+ type: "forwarding"
+ description: "Configured by Ansible Content Team"
+ state: rendered
+
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "rendered": "<nc:routing-instances xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# <nc:instance><nc:name>test</nc:name><nc:connector-id-advertise/><nc:instance-type>vrf</nc:instance-type>
+# <nc:interface><nc:name>sp-0/0/0.0</nc:name></nc:interface><nc:interface><nc:name>gr-0/0/0.0</nc:name></nc:interface>
+# <nc:route-distinguisher><nc:rd-type>10.58.255.1:37</nc:rd-type></nc:route-distinguisher>
+# <nc:vrf-import>test-policy</nc:vrf-import><nc:vrf-export>test-policy</nc:vrf-export>
+# <nc:vrf-export>test-policy-1</nc:vrf-export></nc:instance>
+# <nc:instance><nc:name>forwardinst</nc:name><nc:description>Configured by Ansible Content Team</nc:description>
+# <nc:instance-type>forwarding</nc:instance-type></nc:instance></nc:routing-instances>"
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: list
+after:
+ description: The resulting configuration model invocation.
+ 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: ['<nc:routing-instances
+ xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ <nc:instance>
+ <nc:name>test</nc:name>
+ <nc:connector-id-advertise/>
+ <nc:instance-type>vrf</nc:instance-type>
+ <nc:interface>
+ <nc:name>sp-0/0/0.0</nc:name>
+ </nc:interface>
+ <nc:interface>
+ <nc:name>gr-0/0/0.0</nc:name>
+ </nc:interface>
+ <nc:route-distinguisher>
+ <nc:rd-type>10.58.255.1:37</nc:rd-type>
+ </nc:route-distinguisher>
+ <nc:vrf-import>test-policy</nc:vrf-import>
+ <nc:vrf-export>test-policy</nc:vrf-export>
+ <nc:vrf-export>test-policy-1</nc:vrf-export>
+ </nc:instance>
+ </routing-instances>
+ </configuration>
+ </rpc-reply>', 'xml2', 'xml 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.routing_instances.routing_instances import (
+ Routing_instancesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.routing_instances.routing_instances import (
+ Routing_instances,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ module = AnsibleModule(
+ argument_spec=Routing_instancesArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+ result = Routing_instances(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_routing_options.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_routing_options.py
new file mode 100644
index 000000000..c1935b4d1
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_routing_options.py
@@ -0,0 +1,402 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2021 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_routing_options
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+---
+module: junos_routing_options
+version_added: 2.8.0
+short_description: Manage routing-options configuration on Junos devices.
+description: This module manages routing-options configuration on devices running Junos.
+author: Rohit Thakur (@rohitthakur2590)
+requirements:
+ - ncclient (>=v0.6.4)
+ - xmltodict (>=0.12.0)
+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,https://docs.ansible.com/ansible/latest/network/user_guide/platform_junos.html).
+ - Tested against JunOS v18.4R1
+options:
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show system routing-options).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ config:
+ description: A dictionary of routing-options configuration.
+ type: dict
+ suboptions:
+ autonomous_system:
+ description: Specify Autonomous system number.
+ type: dict
+ suboptions:
+ as_number:
+ description: Specify Autonomous system number.
+ type: str
+ required: true
+ loops:
+ description: Specify maximum number of times this AS can be in an AS path.
+ type: int
+ asdot_notation:
+ description: Enable AS-Dot notation to display true 4 byte AS numbers.
+ type: bool
+ router_id:
+ description: Specify Router identifier.
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in.
+ - Refer to examples for more details.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - deleted
+ - overridden
+ - parsed
+ - gathered
+ - rendered
+ default: merged
+"""
+EXAMPLES = """
+# Using merged
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show system routing-options
+#
+- name: Merge provided NTP configuration into running configuration.
+ junipernetworks.junos.junos_routing_options:
+ config:
+ autonomous_system:
+ as_number: 2
+ asdot_notation: true
+ state: merged
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "autonomous_system": {
+# "as_number": "2",
+# "asdot_notation": true
+# }
+# },
+# "before": {},
+# "changed": true,
+# "commands": [
+# "<nc:routing-options xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:autonomous-system>2<nc:asdot-notation/></nc:autonomous-system></nc:routing-options>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show routing-options
+# autonomous-system 2 asdot-notation;
+#
+#
+# Using Replaced
+# Before state
+# ------------
+#
+# vagrant@vsrx# show routing-options
+# autonomous-system 2 asdot-notation;
+
+- name: Replaced running routing-options configuration with provided configuration
+ junipernetworks.junos.junos_routing_options:
+ config:
+ autonomous_system:
+ as_number: 2
+ asdot_notation: true
+ router_id: "1.1.1.1"
+ state: replaced
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "autonomous_system": {
+# "as_number": "2",
+# "asdot_notation": true
+# },
+# "router_id": "1.1.1.1"
+# },
+# "before": {
+# "autonomous_system": {
+# "as_number": "2",
+# "asdot_notation": true
+# }
+# },
+# "changed": true,
+# "commands": [
+# "<nc:routing-options xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:autonomous-system delete=\"delete\"/><nc:autonomous-system>2<nc:asdot-notation/>"
+# "</nc:autonomous-system><nc:router-id>1.1.1.1</nc:router-id></nc:routing-options>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show routing-options
+# router-id 1.1.1.1;
+# autonomous-system 2 asdot-notation;
+
+
+# Using overridden
+#
+# vagrant@vsrx# show routing-options
+# autonomous-system 2 asdot-notation;
+
+- name: Override running routing-options configuration with provided configuration
+ junipernetworks.junos.junos_routing_options:
+ config:
+ autonomous_system:
+ as_number: 2
+ asdot_notation: true
+ router_id: "1.1.1.1"
+ state: overridden
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "autonomous_system": {
+# "as_number": "2",
+# "asdot_notation": true
+# },
+# "router_id": "1.1.1.1"
+# },
+# "before": {
+# "autonomous_system": {
+# "as_number": "2",
+# "asdot_notation": true
+# }
+# },
+# "changed": true,
+# "commands": [
+# "<nc:routing-options xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:autonomous-system delete=\"delete\"/><nc:autonomous-system>2<nc:asdot-notation/>"
+# "</nc:autonomous-system><nc:router-id>1.1.1.1</nc:router-id></nc:routing-options>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show routing-options
+# router-id 1.1.1.1;
+# autonomous-system 2 asdot-notation;
+#
+# Using deleted
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show routing-options
+# router-id 1.1.1.1;
+# autonomous-system 2 asdot-notation;
+#
+- name: Delete running routing-options configuration
+ junipernetworks.junos.junos_routing_options:
+ config:
+ state: deleted
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {},
+# "before": {
+# "autonomous_system": {
+# "as_number": "2",
+# "asdot_notation": true
+# },
+# "router_id": "1.1.1.1"
+# },
+# "changed": true,
+# "commands": [
+# "<nc:routing-options xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:autonomous-system delete=\"delete\"/><nc:router-id delete=\"delete\"/></nc:routing-options>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show routing-options
+#
+# [edit]
+# Using gathered
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show routing-options
+# router-id 1.1.1.1;
+# autonomous-system 2 asdot-notation;
+
+- name: Gather running routing-options configuration
+ junipernetworks.junos.junos_routing_options:
+ state: gathered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "gathered": {
+# "autonomous_system": {
+# "as_number": "2",
+# "asdot_notation": true
+# },
+# "router_id": "1.1.1.1"
+# },
+# "changed": false,
+# Using rendered
+#
+# Before state
+# ------------
+#
+- name: Render xml for provided facts.
+ junipernetworks.junos.junos_routing_options:
+ config:
+ autonomous_system:
+ as_number: 2
+ asdot_notation: true
+ loops: 4
+ router_id: 12.12.12.12
+ state: rendered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "rendered": [
+# "<nc:routing-options xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+# "<nc:autonomous-system>2<nc:loops>4</nc:loops><nc:asdot-notation/></nc:autonomous-system>
+# "<nc:router-id>12.12.12.12</nc:router-id></nc:routing-options>"
+# ]
+#
+# Using parsed
+# parsed.cfg
+# ------------
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <version>18.4R1-S2.4</version>
+# <routing-options>
+# <router-id>12.12.12.12</router-id>
+# <autonomous-system>
+# <as-number>2</as-number>
+# <loops>4</loops>
+# <asdot-notation/>
+# </autonomous-system>
+# </routing-options>
+# </configuration>
+# </rpc-reply>
+#
+- name: Parse routing-options running config
+ junipernetworks.junos.junos_routing_options:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "parsed": {
+# "autonomous_system": {
+# "as_number": "2",
+# "asdot_notation": true,
+# "loops": 4
+# },
+# "router_id": "12.12.12.12"
+# }
+#
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+after:
+ description: The resulting configuration model invocation.
+ returned: when changed
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ['<nc:autonomous-system delete=\"delete\"/><nc:router-id delete=\"delete\"/></nc:routing-options>']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.routing_options.routing_options import (
+ Routing_optionsArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.routing_options.routing_options import (
+ Routing_options,
+)
+
+
+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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ module = AnsibleModule(
+ argument_spec=Routing_optionsArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+
+ result = Routing_options(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_rpc.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_rpc.py
new file mode 100644
index 000000000..9fda891c3
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_rpc.py
@@ -0,0 +1,177 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_rpc
+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.
+version_added: 1.0.0
+extends_documentation_fragment:
+- junipernetworks.junos.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.
+ type: str
+ 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.
+ type: dict
+ 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.
+ type: dict
+ 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
+ type: str
+ choices: ["xml", "json", "text"]
+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
+ junipernetworks.junos.junos_rpc:
+ rpc: get-interface-information
+ args:
+ interface-name: em0
+ media: true
+
+- name: get system information
+ junipernetworks.junos.junos_rpc:
+ rpc: get-system-information
+
+- name: load configuration
+ junipernetworks.junos.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.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.netconf import (
+ exec_rpc,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ tostring,
+)
+
+
+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"]),
+ )
+
+ 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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_scp.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_scp.py
new file mode 100644
index 000000000..34657ae8d
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_scp.py
@@ -0,0 +1,172 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_scp
+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.
+version_added: 1.0.0
+extends_documentation_fragment:
+- junipernetworks.junos.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
+ type: list
+ elements: path
+ dest:
+ description:
+ - The C(dest) argument specifies the path in which to receive the files.
+ type: path
+ 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
+ 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
+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
+ junipernetworks.junos.junos_scp:
+ src: test.tgz
+
+- name: upload local file to tmp directory on remote device
+ junipernetworks.junos.junos_scp:
+ src: test.tgz
+ dest: /tmp/
+
+- name: download file from remote device
+ junipernetworks.junos.junos_scp:
+ src: test.tgz
+ remote_src: true
+
+- name: ssh config file path for jumphost config
+ junipernetworks.junos.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._text import to_native
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ get_device,
+)
+
+
+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, elements="path"),
+ 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"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+
+ 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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_security_policies.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_security_policies.py
new file mode 100644
index 000000000..bf8c4f6ee
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_security_policies.py
@@ -0,0 +1,2707 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2022 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_security_policies
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+ANSIBLE_METADATA = {
+ "metadata_version": "1.1",
+ "status": ["preview"],
+ "supported_by": "network",
+}
+
+DOCUMENTATION = """
+---
+module: junos_security_policies
+version_added: 2.9.0
+short_description: Create and manage security policies on Juniper JUNOS devices
+description: This module provides declarative creation and management of security policies on Juniper JUNOS devices
+author: Pranav Bhatt (@pranav-bhatt)
+requirements:
+ - ncclient (>=v0.6.4)
+ - xmltodict (>=0.12.0)
+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,https://docsansiblecom/ansible/latest/network/user_guide/platform_junoshtml)
+ - Tested against JunOS v18.4R1
+options:
+ config:
+ description: A dictionary of security policies
+ type: dict
+ suboptions:
+ from_zones:
+ description:
+ - List of security zones from which the traffic originates from
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - The name of the security zone from which the traffic originates from
+ type: str
+ to_zones:
+ description:
+ - List of destination security zones of the traffic
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - The name of the destination security zone of the traffic
+ type: str
+ policies: &policy_attributes
+ description:
+ - List of policies defined for the associated category
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Name of the policy
+ type: str
+ description:
+ description:
+ - Description of the security policy
+ type: str
+ scheduler_name:
+ description:
+ - Name of the scheduler to run this policy
+ type: str
+ match:
+ description: Configure security policy match criteria
+ type: dict
+ suboptions:
+ application:
+ description:
+ - Specify the IP or remote procedure call (RPC) application or set of applications to be used as match criteria
+ type: dict
+ suboptions:
+ names:
+ description: Name of the predefined or custom application or application set used as match criteria
+ type: list
+ elements: str
+ any:
+ description: Match any predefined or custom applications or application sets
+ type: bool
+ dynamic_application:
+ description:
+ - Specify the dynamic applications or dynamic application groups used as match criteria within a security policy
+ type: dict
+ suboptions:
+ names:
+ description: Specify dynamic applications or dynamic application groups
+ type: list
+ elements: str
+ any:
+ description:
+ - Configuring the dynamic application as any installs the policy with the application as a wildcard (default)
+ type: bool
+ none:
+ description:
+ - Configuring the dynamic application as none ignores classification results from AppID and does not use the
+ dynamic application in security policy lookups
+ type: bool
+ destination_address:
+ description:
+ - Define the matching criteria You can specify one or more IP addresses, address sets, or wildcard addresses
+ type: dict
+ suboptions:
+ addresses:
+ description:
+ - IP address, IP address set, or address book entry, or wildcard address (represented as ABCD/wildcard_mask)
+ type: list
+ elements: str
+ any:
+ description: Any IPv4 or IPv6 address
+ type: bool
+ any_ipv4:
+ description: Any IPv4 address
+ type: bool
+ any_ipv6:
+ description: Any IPv6 address
+ type: bool
+ destination_address_excluded:
+ description:
+ - Exclude destination addresses
+ type: bool
+ source_address:
+ description:
+ - Define the matching criteria You can specify one or more IP addresses, address sets, or wildcard addresses
+ type: dict
+ suboptions:
+ addresses:
+ description:
+ - IP address, IP address set, or address book entry, or wildcard address (represented as ABCD/wildcard_mask)
+ type: list
+ elements: str
+ any:
+ description: Any IPv4 or IPv6 address
+ type: bool
+ any_ipv4:
+ description: Any IPv4 address
+ type: bool
+ any_ipv6:
+ description: Any IPv6 address
+ type: bool
+ source_address_excluded:
+ description:
+ - Exclude source addresses
+ type: bool
+ source_identity:
+ description:
+ - Identifies users and roles to be used as match criteria for a policy
+ type: dict
+ suboptions:
+ names:
+ description: A list of specific users and roles
+ type: list
+ elements: str
+ any:
+ description:
+ - Any user or role, as well as the keywords authenticated_user, unauthenticated_user,
+ and unknown_user
+ type: bool
+ authenticated_user:
+ description: All users and roles that have been authenticated
+ type: bool
+ unauthenticated_user:
+ description:
+ - Any user or role that does not have an IP_address mapped to authentication sources and the authentication source
+ is up and running
+ type: bool
+ unknown_user:
+ description:
+ - Any user or role that does not have an IP address mapped to authentication sources, because the
+ authentication source is disconnected from the SRX Series device
+ type: bool
+ source_end_user_profile:
+ description: Source end user profile name
+ type: str
+ url_category:
+ description: URL category
+ type: dict
+ suboptions:
+ names:
+ description:
+ - Names of url category to match
+ type: list
+ elements: str
+ any:
+ description:
+ - Apply to any url category
+ type: bool
+ none:
+ description:
+ - Do not apply to the url category
+ type: bool
+ from_zone:
+ description: Identify a single source zone or multiple source zones to be used as a match criteria for a policy
+ type: dict
+ suboptions:
+ names:
+ description: Name of single or multiple source zone
+ type: list
+ elements: str
+ any:
+ description: Match any zone
+ type: bool
+ junos_host:
+ description:
+ - junos-host
+ type: bool
+ to_zone:
+ description: Identify a single destination zone or multiple destination zones to be used as a match criteria for a policy
+ type: dict
+ suboptions:
+ names:
+ description: Name of single or multiple destination zone
+ type: list
+ elements: str
+ any:
+ description: Match any zone
+ type: bool
+ junos_host:
+ description:
+ - junos-host
+ type: bool
+ then:
+ description: Specify the policy action to be performed when packets match the defined criteria
+ type: dict
+ suboptions:
+ count:
+ description:
+ - Enable a count, in bytes or kilobytes, of all network traffic the policy allows to pass through the device
+ in both directions; the originating traffic from the client to the server (from the from_zone to the to_zone),
+ and the return traffic from the server to the originating client
+ type: bool
+ deny:
+ description: Block the service at the firewall The device drops the packets
+ type: bool
+ reject:
+ description:
+ - Block the service at the firewall The device drops the packet and sends a TCP reset (RST) segment to the
+ source host for TCP traffic and an ICMP "destination unreachable, port unreachable"
+ message (type 3, code 3) for UDP traffic
+ type: dict
+ suboptions:
+ enable:
+ description:
+ - Enable rejection of packets based on match criteria
+ type: bool
+ profile:
+ description:
+ - You can chose to provide a notification to the clients or redirect client request to an informative
+ Web page when a policy blocks HTTP or HTTPS traffic with a deny or reject action
+ type: str
+ ssl_proxy:
+ description:
+ - You can apply a redirect SSL proxy profile when a policy blocks HTTPS traffic with a reject action
+ When you apply am SSL proxy profile, SSL proxy decrypts the traffic and application
+ identification functionality identifies the application
+ type: dict
+ suboptions:
+ enable:
+ description:
+ - Enable SSL proxy
+ type: bool
+ profile_name:
+ description: Name of SSL proxy profile
+ type: str
+ log:
+ description:
+ - Log traffic information for a specific policy Traffic information is logged when a
+ session begins (session_init) or closes (session_close)
+ type: dict
+ suboptions:
+ session_init:
+ description:
+ - Enable logging on session initialization time
+ type: bool
+ session_close:
+ description:
+ - Enable logging on session close time
+ type: bool
+ permit:
+ description: Block the service at the firewall The device drops the packets
+ type: dict
+ suboptions:
+ application_services:
+ description:
+ - Enable application services within a security policy
+ type: dict
+ suboptions:
+ advanced_anti_malware_policy:
+ description:
+ - Specify advanced_anti_malware policy name
+ type: str
+ application_firewalls:
+ description:
+ - Specify the rule sets configured as part of application firewall to be applied to the permitted traffic
+ type: list
+ elements: dict
+ suboptions:
+ rule_set:
+ description:
+ - name of rule set to use
+ type: str
+ application_traffic_control_rule_set:
+ description:
+ - Specify the rule set configured as part of AppQoS, application_aware quality of service,
+ to be applied to the permitted traffic
+ type: str
+ gprs_gtp_profile:
+ description:
+ - Specify GPRS tunneling protocol profile name
+ type: str
+ gprs_sctp_profile:
+ description:
+ - Specify GPRS stream control protocol profile name
+ type: str
+ icap_redirect:
+ description:
+ - Specify icap redirect profile name
+ type: str
+ idp:
+ description:
+ - Intrusion Detection and Prevention (IDP)
+ type: bool
+ idp_policy:
+ description:
+ - Specify IDP policy name
+ type: str
+ packet_capture:
+ description:
+ - Option to enable or disable packet capture
+ type: bool
+ redirect_wx:
+ description:
+ - Specify the WX redirection needed for the packets that arrive from the LAN
+ type: bool
+ reverse_redirect_wx:
+ description:
+ - Specify the WX redirection needed for the reverse flow of the packets that arrive from the WAN
+ type: bool
+ security_intelligence_policy:
+ description:
+ - Specify security_intelligence policy name
+ type: str
+ security_intelligence:
+ description: Specify the security intelligence feed post action
+ type: dict
+ suboptions:
+ add_destination_identity_to_feed:
+ description: Add destination user identity to the security feed
+ type: str
+ add_destination_ip_to_feed:
+ description: Add the destination IP address to the security feed
+ type: str
+ add_source_ip_to_feed:
+ description: Add the source IP address to the security feed
+ type: str
+ add_source_identity_to_feed:
+ description: Add source user identity to the security feed
+ type: str
+ ssl_proxy:
+ description: You can apply a redirect SSL proxy profile when a policy blocks HTTPS traffic with a reject action
+ type: dict
+ suboptions:
+ enable:
+ description:
+ - Enable SSL proxy
+ type: bool
+ profile_name:
+ description: Name of SSL proxy profile
+ type: str
+ uac_policy:
+ description:
+ - Enable Unified Access Control (UAC) for the security policy
+ type: dict
+ suboptions:
+ enable:
+ description:
+ - Enable Unified Access Control (UAC)
+ type: bool
+ captive_portal:
+ description:
+ - Specify the preconfigured security policy for captive portal on the Junos OS Enforcer to enable the
+ captive portal feature
+ type: str
+ utm_policy:
+ description:
+ - Specify UTM policy name
+ type: str
+ destination_address:
+ description:
+ - Specify whether the traffic permitted by the security policy is limited to packets
+ where the destination IP address has been translated by means of a destination NAT rule
+ or to packets where the destination IP address has not been translated
+ choices:
+ - drop-translated
+ - drop-untranslated
+ type: str
+ firewall_authentication:
+ description: Configure firewall authentication methods
+ type: dict
+ suboptions:
+ pass_through:
+ description:
+ - Configure pass-through firewall user authentication
+ type: dict
+ suboptions:
+ access_profile:
+ description:
+ - Specify the name of the access profile
+ type: str
+ client_match:
+ description:
+ - Specify the name of the users or user groups in a profile who are allowed access by this policy
+ type: str
+ ssl_termination_profile:
+ description:
+ - Specify the SSL termination profile used for SSL offloading
+ type: str
+ web_redirect:
+ description:
+ - Enable redirecting an HTTP request to the device and redirecting the client system to a
+ webpage for authentication
+ type: bool
+ web_redirect_to_https:
+ description:
+ - Redirect unauthenticated HTTP requests to the internal HTTPS Web server of the device
+ type: bool
+ auth_only_browser:
+ description:
+ - Configure firewall authentication to ignore non-browser HTTP/HTTPS traffic
+ type: bool
+ auth_user_agent:
+ description:
+ - Specify a user-agent value to be used to verify that the user's browser traffic is HTTP/HTTPS traffic
+ type: str
+ push_to_identity_management:
+ description: enables pushing to identity management devices
+ type: bool
+ user_firewall:
+ description:
+ - Configure user role firewall authentication, and map the source IP address to the username and its
+ associated roles (groups)
+ type: dict
+ suboptions:
+ access_profile:
+ description:
+ - Specify the name of the access profile to be used for authentication
+ type: str
+ domain:
+ description:
+ - Specify the name of the domain where firewall authentication occurs in the event that the
+ Windows Management Instrumentation client (WMIC) is not available to get
+ IP_to_user mapping for the integrated user firewall feature
+ type: str
+ ssl_termination_profile:
+ description:
+ - For HTTPS traffic, specify the name of the SSL termination profile used for SSL offloading
+ type: str
+ web_redirect:
+ description:
+ - Enable webpage redirection
+ type: bool
+ web_redirect_to_https:
+ description:
+ - Enable redirection to HTTPS
+ type: bool
+ auth_only_browser:
+ description:
+ - Configure firewall authentication to ignore non-browser HTTP/HTTPS traffic
+ type: bool
+ auth_user_agent:
+ description:
+ - Specify a user-agent value to be used to verify that the user's browser traffic is HTTP/HTTPS traffic
+ type: str
+ web_authentication:
+ description:
+ - Specify that the policy allows access to users or user groups who have previously been authenticated by
+ Web authentication
+ type: list
+ elements: str
+ tcp_options:
+ description:
+ - Specify the TCP options for each policy You can configure sync and sequence checks for each policy
+ based on your requirements, and, because each policy has two directions, you can configure a
+ TCP MSS value for both directions or for just one direction
+ type: dict
+ suboptions:
+ initial_tcp_mss:
+ description:
+ - Configure the TCP maximum segment size (MSS) for packets that arrive at the
+ ingress interface (initial direction), match a specific policy, and for which a session is created
+ type: int
+ reverse_tcp_mss:
+ description:
+ - Configure the TCP maximum segment size (MSS) for packets that match a specific policy and travel in the
+ reverse direction of a session
+ type: int
+ sequence_check_required:
+ description:
+ - Enable sequence check per policy The sequence_check_required value overrides the global value no_sequence_check
+ type: bool
+ syn_check_required:
+ description:
+ - Enable sync check per policy The syn_check_required value overrides the global value no_syn_check
+ type: bool
+ window_scale:
+ description:
+ - Enable window_scale per policy
+ type: bool
+ tunnel:
+ description: Encapsulate outgoing IP packets and decapsulate incoming IP packets
+ type: dict
+ suboptions:
+ ipsec_vpn:
+ description:
+ - name of the ipsec policy
+ type: str
+ pair_policy:
+ description:
+ - name of the pair policy
+ type: str
+ global:
+ description:
+ - List of global security policies
+ type: dict
+ suboptions:
+ policies: *policy_attributes
+ running_config:
+ description:
+ - This option is used only with state I(parsed)
+ - The value of this option should be the output received from the JunOS device
+ by executing the command B(show configuration security policies)
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result For state I(rendered) active connection to remote host is
+ not required
+ - The state I(replaced) will replace the running configuration with the provided
+ configuration
+ - The state I(replaced) and state I(overridden) have the same behaviour
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result The value of C(running_config)
+ option should be the same format as the output of command
+ I(show security policies detail) executed on device For state I(parsed) active
+ connection to remote host is not required
+ type: str
+"""
+EXAMPLES = """
+# Using merged
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx> show security policies
+# Default policy: deny-all
+# Pre ID default policy: permit-all
+# Global policies:
+# Policy: test_glob, State: enabled, Index: 4, Scope Policy: 0, Sequence number: 1
+# From zones: any
+# To zones: any
+# Source addresses: any-ipv4
+# Destination addresses: any-ipv4
+# Applications: any
+# Action: deny
+#
+# vagrant@vsrx> show security zones
+#
+# Security zone: one
+# Send reset for non-SYN session TCP packets: Off
+# Policy configurable: Yes
+# Interfaces bound: 1
+# Interfaces:
+# ge-0/0/0.0
+#
+# Security zone: three
+# Send reset for non-SYN session TCP packets: Off
+# Policy configurable: Yes
+# Interfaces bound: 1
+# Interfaces:
+# ge-0/0/2.0
+#
+# Security zone: two
+# Send reset for non-SYN session TCP packets: Off
+# Policy configurable: Yes
+# Interfaces bound: 1
+# Interfaces:
+# ge-0/0/1.0
+#
+# Security zone: junos-host
+# Send reset for non-SYN session TCP packets: Off
+# Policy configurable: Yes
+# Interfaces bound: 0
+# Interfaces:
+#
+- junipernetworks.junos.junos_security_policies:
+ config:
+ from_zones:
+ - name: one
+ to_zones:
+ - name: two
+ policies:
+ - match:
+ application:
+ names:
+ - junos-dhcp-relay
+ - junos-finger
+ destination_address:
+ addresses:
+ - a2
+ - a4
+ destination_address_excluded: true
+ dynamic_application:
+ names:
+ - any
+ source_address:
+ addresses:
+ - a1
+ - a3
+ source_address_excluded: true
+ source_end_user_profile: test_end_user_profile
+ source_identity:
+ unknown_user: true
+ url_category:
+ names:
+ - Enhanced_Web_Chat
+ name: test_policy_1
+ then:
+ count: true
+ deny: true
+ log: session-close
+ - match:
+ application:
+ any: true
+ destination_address:
+ any_ipv6: true
+ source_address:
+ addresses:
+ - a1
+ name: test_policy_2
+ then:
+ reject:
+ enable: true
+ profile: test_dyn_app
+ ssl_proxy:
+ enable: true
+ profile_name: SECURITY-SSL-PROXY
+ - name: three
+ policies:
+ - match:
+ application:
+ any: true
+ destination_address:
+ addresses:
+ - a2
+ source_address:
+ addresses:
+ - a1
+ name: test_policy_3
+ then:
+ permit:
+ application_services:
+ application_traffic_control_rule_set: test_traffic_control
+ gprs_gtp_profile: gtp1
+ icap_redirect: test_icap
+ reverse_redirect_wx: 'True'
+ uac_policy:
+ enable: true
+ firewall_authentication:
+ push_to_identity_management: true
+ web_authentication:
+ - FWClient1
+ tcp_options:
+ initial_tcp_mss: 64
+ window_scale: true
+ global:
+ policies:
+ - match:
+ application:
+ any: true
+ destination_address:
+ any_ipv6: true
+ source_address:
+ any_ipv6: true
+ name: test_glob_1
+ then:
+ deny: true
+ - match:
+ application:
+ any: true
+ destination_address:
+ any_ipv6: true
+ source_address:
+ any_ipv6: true
+ name: test_glob_2
+ then:
+ deny: true
+ state: merged
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "from_zones": [
+# {
+# "name": "one",
+# "to_zones": [
+# {
+# "name": "two",
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "names": [
+# "junos-dhcp-relay",
+# "junos-finger"
+# ]
+# },
+# "destination_address": {
+# "addresses": [
+# "a2",
+# "a4"
+# ]
+# },
+# "destination_address_excluded": true,
+# "dynamic_application": {
+# "names": [
+# "any"
+# ]
+# },
+# "source_address": {
+# "addresses": [
+# "a1",
+# "a3"
+# ]
+# },
+# "source_address_excluded": true,
+# "source_end_user_profile": "test_end_user_profile",
+# "source_identity": {
+# "unknown_user": true
+# },
+# "url_category": {
+# "names": [
+# "Enhanced_Web_Chat"
+# ]
+# }
+# },
+# "name": "test_policy_1",
+# "then": {
+# "count": true,
+# "deny": true,
+# "log": "session-close"
+# }
+# },
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "addresses": [
+# "a1"
+# ]
+# }
+# },
+# "name": "test_policy_2",
+# "then": {
+# "reject": {
+# "enable": true,
+# "profile": "test_dyn_app",
+# "ssl_proxy": {
+# "enable": true,
+# "profile_name": "SECURITY-SSL-PROXY"
+# }
+# }
+# }
+# }
+# ]
+# },
+# {
+# "name": "three",
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "addresses": [
+# "a2"
+# ]
+# },
+# "source_address": {
+# "addresses": [
+# "a1"
+# ]
+# }
+# },
+# "name": "test_policy_3",
+# "then": {
+# "permit": {
+# "application_services": {
+# "application_traffic_control_rule_set": "test_traffic_control",
+# "gprs_gtp_profile": "gtp1",
+# "icap_redirect": "test_icap",
+# "reverse_redirect_wx": "True",
+# "uac_policy": {
+# "enable": true
+# }
+# },
+# "firewall_authentication": {
+# "push_to_identity_management": true,
+# "web_authentication": [
+# "FWClient1"
+# ]
+# },
+# "tcp_options": {
+# "initial_tcp_mss": 64,
+# "window_scale": true
+# }
+# }
+# }
+# }
+# ]
+# }
+# ]
+# }
+# ],
+# "global": {
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv4": true
+# },
+# "source_address": {
+# "any_ipv4": true
+# }
+# },
+# "name": "test_glob",
+# "then": {
+# "deny": true
+# }
+# },
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "any_ipv6": true
+# }
+# },
+# "name": "test_glob_1",
+# "then": {
+# "deny": true
+# }
+# },
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "any_ipv6": true
+# }
+# },
+# "name": "test_glob_2",
+# "then": {
+# "deny": true
+# }
+# }
+# ]
+# }
+# },
+# "before": {
+# "global": {
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv4": true
+# },
+# "source_address": {
+# "any_ipv4": true
+# }
+# },
+# "name": "test_glob",
+# "then": {
+# "deny": true
+# }
+# }
+# ]
+# }
+# },
+# "changed": true,
+# "commands": "<nc:security
+# xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+# <nc:policies>
+# <nc:policy>
+# <nc:from-zone-name>one</nc:from-zone-name>
+# <nc:to-zone-name>two</nc:to-zone-name>
+# <nc:policy>
+# <nc:name>test_policy_1</nc:name>
+# <nc:match>
+# <nc:source-address>a1</nc:source-address>
+# <nc:source-address>a3</nc:source-address>
+# <nc:source-address-excluded/>
+# <nc:destination-address>a2</nc:destination-address>
+# <nc:destination-address>a4</nc:destination-address>
+# <nc:destination-address-excluded/>
+# <nc:application>junos-dhcp-relay</nc:application>
+# <nc:application>junos-finger</nc:application>
+# <nc:source-end-user-profile>test_end_user_profile</nc:source-end-user-profile>
+# <nc:source-identity>unknown-user</nc:source-identity>
+# <nc:url-category>Enhanced_Web_Chat</nc:url-category>
+# <nc:dynamic-application>any</nc:dynamic-application>
+# </nc:match>
+# <nc:then>
+# <nc:deny/>
+# <nc:count></nc:count>
+# <nc:log>
+# <nc:session-close/>
+# </nc:log>
+# </nc:then>
+# </nc:policy>
+# <nc:policy>
+# <nc:name>test_policy_2</nc:name>
+# <nc:match>
+# <nc:source-address>a1</nc:source-address>
+# <nc:destination-address>any-ipv6</nc:destination-address>
+# <nc:application>any</nc:application>
+# </nc:match>
+# <nc:then>
+# <nc:reject>
+# <nc:profile>test_dyn_app</nc:profile>
+# <nc:ssl-proxy>
+# <nc:profile-name>SECURITY-SSL-PROXY</nc:profile-name>
+# </nc:ssl-proxy>
+# </nc:reject>
+# </nc:then>
+# </nc:policy>
+# </nc:policy>
+# <nc:policy>
+# <nc:from-zone-name>one</nc:from-zone-name>
+# <nc:to-zone-name>three</nc:to-zone-name>
+# <nc:policy>
+# <nc:name>test_policy_3</nc:name>
+# <nc:match>
+# <nc:source-address>a1</nc:source-address>
+# <nc:destination-address>a2</nc:destination-address>
+# <nc:application>any</nc:application>
+# </nc:match>
+# <nc:then>
+# <nc:permit>
+# <nc:application-services>
+# <nc:application-traffic-control>
+# <nc:rule-set>test_traffic_control</nc:rule-set>
+# </nc:application-traffic-control>
+# <nc:gprs-gtp-profile>gtp1</nc:gprs-gtp-profile>
+# <nc:icap-redirect>test_icap</nc:icap-redirect>
+# <nc:reverse-redirect-wx/>
+# <nc:uac-policy></nc:uac-policy>
+# </nc:application-services>
+# <nc:firewall-authentication>
+# <nc:push-to-identity-management/>
+# <nc:web-authentication>
+# <nc:client-match>FWClient1</nc:client-match>
+# </nc:web-authentication>
+# </nc:firewall-authentication>
+# <nc:tcp-options>
+# <nc:initial-tcp-mss>64</nc:initial-tcp-mss>
+# <nc:window-scale/>
+# </nc:tcp-options>
+# </nc:permit>
+# </nc:then>
+# </nc:policy>
+# </nc:policy>
+# <nc:global>
+# <nc:policy>
+# <nc:name>test_glob_1</nc:name>
+# <nc:match>
+# <nc:source-address>any-ipv6</nc:source-address>
+# <nc:destination-address>any-ipv6</nc:destination-address>
+# <nc:application>any</nc:application>
+# </nc:match>
+# <nc:then>
+# <nc:deny/>
+# </nc:then>
+# </nc:policy>
+# <nc:policy>
+# <nc:name>test_glob_2</nc:name>
+# <nc:match>
+# <nc:source-address>any-ipv6</nc:source-address>
+# <nc:destination-address>any-ipv6</nc:destination-address>
+# <nc:application>any</nc:application>
+# </nc:match>
+# <nc:then>
+# <nc:deny/>
+# </nc:then>
+# </nc:policy>
+# </nc:global>
+# </nc:policies>
+# </nc:security>
+# "
+# After state
+# -----------
+#
+# vagrant@vsrx> show security policies
+# Default policy: deny-all
+# Pre ID default policy: permit-all
+# From zone: one, To zone: two
+# Policy: test_policy_1, State: enabled, Index: 5, Scope Policy: 0, Sequence number: 1
+# Source addresses(excluded): a1, a3
+# Destination addresses(excluded): a2, a4
+# Source-end-user-profile: test_end_user_profile(1)
+# Applications: junos-dhcp-relay, junos-finger
+# Dynamic Applications: any
+# Url-category: Enhanced_Web_Chat
+# Source identities: unknown-user
+# Action: deny, log, count
+# Policy: test_policy_2, State: enabled, Index: 6, Scope Policy: 0, Sequence number: 2
+# Source addresses: a1
+# Destination addresses: any-ipv6
+# Applications: any
+# Action: reject
+# dynapp-redir-profile: test_dyn_app(1)
+# From zone: one, To zone: three
+# Policy: test_policy_3, State: enabled, Index: 7, Scope Policy: 0, Sequence number: 1
+# Source addresses: a1
+# Destination addresses: a2
+# Applications: any
+# Action: permit, firewall authentication, application services, unified access control
+# Application traffic control: test_traffic_control
+# Global policies:
+# Policy: test_glob, State: enabled, Index: 4, Scope Policy: 0, Sequence number: 1
+# From zones: any
+# To zones: any
+# Source addresses: any-ipv4
+# Destination addresses: any-ipv4
+# Applications: any
+# Action: deny
+# Policy: test_glob_1, State: enabled, Index: 8, Scope Policy: 0, Sequence number: 2
+# From zones: any
+# To zones: any
+# Source addresses: any-ipv6
+# Destination addresses: any-ipv6
+# Applications: any
+# Action: deny
+# Policy: test_glob_2, State: enabled, Index: 9, Scope Policy: 0, Sequence number: 3
+# From zones: any
+# To zones: any
+# Source addresses: any-ipv6
+# Destination addresses: any-ipv6
+# Applications: any
+# Action: deny
+
+
+# Using Replaced
+# Before state
+# ------------
+#
+# vagrant@vsrx> show security policies
+# Default policy: deny-all
+# Pre ID default policy: permit-all
+# From zone: one, To zone: two
+# Policy: test_policy_1, State: enabled, Index: 5, Scope Policy: 0, Sequence number: 1
+# Source addresses(excluded): a1, a3
+# Destination addresses(excluded): a2, a4
+# Source-end-user-profile: test_end_user_profile(1)
+# Applications: junos-dhcp-relay, junos-finger
+# Dynamic Applications: any
+# Url-category: Enhanced_Web_Chat
+# Source identities: unknown-user
+# Action: deny, log, count
+# Policy: test_policy_2, State: enabled, Index: 6, Scope Policy: 0, Sequence number: 2
+# Source addresses: a1
+# Destination addresses: any-ipv6
+# Applications: any
+# Action: reject
+# dynapp-redir-profile: test_dyn_app(1)
+# From zone: one, To zone: three
+# Policy: test_policy_3, State: enabled, Index: 7, Scope Policy: 0, Sequence number: 1
+# Source addresses: a1
+# Destination addresses: a2
+# Applications: any
+# Action: permit, firewall authentication, application services, unified access control
+# Application traffic control: test_traffic_control
+# Global policies:
+# Policy: test_glob, State: enabled, Index: 4, Scope Policy: 0, Sequence number: 1
+# From zones: any
+# To zones: any
+# Source addresses: any-ipv4
+# Destination addresses: any-ipv4
+# Applications: any
+# Action: deny
+# Policy: test_glob_1, State: enabled, Index: 8, Scope Policy: 0, Sequence number: 2
+# From zones: any
+# To zones: any
+# Source addresses: any-ipv6
+# Destination addresses: any-ipv6
+# Applications: any
+# Action: deny
+# Policy: test_glob_2, State: enabled, Index: 9, Scope Policy: 0, Sequence number: 3
+# From zones: any
+# To zones: any
+# Source addresses: any-ipv6
+# Destination addresses: any-ipv6
+# Applications: any
+# Action: deny
+#
+- junipernetworks.junos.junos_security_policies:
+ config:
+ global:
+ policies:
+ - description: test update
+ match:
+ application:
+ any: true
+ destination_address:
+ any_ipv6: true
+ source_address:
+ any: true
+ name: test_glob_3
+ then:
+ deny: true
+ state: replaced
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "global": {
+# "policies": [
+# {
+# "description": "test update",
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "any": true
+# }
+# },
+# "name": "test_glob_3",
+# "then": {
+# "deny": true
+# }
+# }
+# ]
+# }
+# },
+# "before": {
+# "from_zones": [
+# {
+# "name": "one",
+# "to_zones": [
+# {
+# "name": "two",
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "names": [
+# "junos-dhcp-relay",
+# "junos-finger"
+# ]
+# },
+# "destination_address": {
+# "addresses": [
+# "a2",
+# "a4"
+# ]
+# },
+# "destination_address_excluded": true,
+# "dynamic_application": {
+# "names": [
+# "any"
+# ]
+# },
+# "source_address": {
+# "addresses": [
+# "a1",
+# "a3"
+# ]
+# },
+# "source_address_excluded": true,
+# "source_end_user_profile": "test_end_user_profile",
+# "source_identity": {
+# "unknown_user": true
+# },
+# "url_category": {
+# "names": [
+# "Enhanced_Web_Chat"
+# ]
+# }
+# },
+# "name": "test_policy_1",
+# "then": {
+# "count": true,
+# "deny": true,
+# "log": "session-close"
+# }
+# },
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "addresses": [
+# "a1"
+# ]
+# }
+# },
+# "name": "test_policy_2",
+# "then": {
+# "reject": {
+# "enable": true,
+# "profile": "test_dyn_app",
+# "ssl_proxy": {
+# "enable": true,
+# "profile_name": "SECURITY-SSL-PROXY"
+# }
+# }
+# }
+# }
+# ]
+# },
+# {
+# "name": "three",
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "addresses": [
+# "a2"
+# ]
+# },
+# "source_address": {
+# "addresses": [
+# "a1"
+# ]
+# }
+# },
+# "name": "test_policy_3",
+# "then": {
+# "permit": {
+# "application_services": {
+# "application_traffic_control_rule_set": "test_traffic_control",
+# "gprs_gtp_profile": "gtp1",
+# "icap_redirect": "test_icap",
+# "reverse_redirect_wx": "True",
+# "uac_policy": {
+# "enable": true
+# }
+# },
+# "firewall_authentication": {
+# "push_to_identity_management": true,
+# "web_authentication": [
+# "FWClient1"
+# ]
+# },
+# "tcp_options": {
+# "initial_tcp_mss": 64,
+# "window_scale": true
+# }
+# }
+# }
+# }
+# ]
+# }
+# ]
+# }
+# ],
+# "global": {
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv4": true
+# },
+# "source_address": {
+# "any_ipv4": true
+# }
+# },
+# "name": "test_glob",
+# "then": {
+# "deny": true
+# }
+# },
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "any_ipv6": true
+# }
+# },
+# "name": "test_glob_1",
+# "then": {
+# "deny": true
+# }
+# },
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "any_ipv6": true
+# }
+# },
+# "name": "test_glob_2",
+# "then": {
+# "deny": true
+# }
+# }
+# ]
+# }
+# },
+# "changed": true,
+# "commands": "<nc:security
+# xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+# <nc:policies delete="delete"/>
+# <nc:policies>
+# <nc:global>
+# <nc:policy>
+# <nc:name>test_glob_3</nc:name>
+# <nc:description>test update</nc:description>
+# <nc:match>
+# <nc:source-address>any</nc:source-address>
+# <nc:destination-address>any-ipv6</nc:destination-address>
+# <nc:application>any</nc:application>
+# </nc:match>
+# <nc:then>
+# <nc:deny/>
+# </nc:then>
+# </nc:policy>
+# </nc:global>
+# </nc:policies>
+# </nc:security>"
+# }
+# After state
+# -----------
+#
+# vagrant@vsrx> show security policies
+# Default policy: deny-all
+# Pre ID default policy: permit-all
+# Global policies:
+# Policy: test_glob_3, State: enabled, Index: 10, Scope Policy: 0, Sequence number: 1
+# From zones: any
+# To zones: any
+# Source addresses: any
+# Destination addresses: any-ipv6
+# Applications: any
+# Action: deny
+
+
+# Using overridden
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx> show security policies
+# Default policy: deny-all
+# Pre ID default policy: permit-all
+# From zone: one, To zone: two
+# Policy: test_policy_1, State: enabled, Index: 5, Scope Policy: 0, Sequence number: 1
+# Source addresses(excluded): a1, a3
+# Destination addresses(excluded): a2, a4
+# Source-end-user-profile: test_end_user_profile(1)
+# Applications: junos-dhcp-relay, junos-finger
+# Dynamic Applications: any
+# Url-category: Enhanced_Web_Chat
+# Source identities: unknown-user
+# Action: deny, log, count
+# Policy: test_policy_2, State: enabled, Index: 6, Scope Policy: 0, Sequence number: 2
+# Source addresses: a1
+# Destination addresses: any-ipv6
+# Applications: any
+# Action: reject
+# dynapp-redir-profile: test_dyn_app(1)
+# From zone: one, To zone: three
+# Policy: test_policy_3, State: enabled, Index: 7, Scope Policy: 0, Sequence number: 1
+# Source addresses: a1
+# Destination addresses: a2
+# Applications: any
+# Action: permit, firewall authentication, application services, unified access control
+# Application traffic control: test_traffic_control
+# Global policies:
+# Policy: test_glob, State: enabled, Index: 4, Scope Policy: 0, Sequence number: 1
+# From zones: any
+# To zones: any
+# Source addresses: any-ipv4
+# Destination addresses: any-ipv4
+# Applications: any
+# Action: deny
+# Policy: test_glob_1, State: enabled, Index: 8, Scope Policy: 0, Sequence number: 2
+# From zones: any
+# To zones: any
+# Source addresses: any-ipv6
+# Destination addresses: any-ipv6
+# Applications: any
+# Action: deny
+# Policy: test_glob_2, State: enabled, Index: 9, Scope Policy: 0, Sequence number: 3
+# From zones: any
+# To zones: any
+# Source addresses: any-ipv6
+# Destination addresses: any-ipv6
+# Applications: any
+# Action: deny
+#
+- junipernetworks.junos.junos_security_policies:
+ config:
+ global:
+ policies:
+ - description: test update
+ match:
+ application:
+ any: true
+ destination_address:
+ any_ipv6: true
+ source_address:
+ any: true
+ name: test_glob_3
+ then:
+ deny: true
+ state: overridden
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "global": {
+# "policies": [
+# {
+# "description": "test update",
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "any": true
+# }
+# },
+# "name": "test_glob_3",
+# "then": {
+# "deny": true
+# }
+# }
+# ]
+# }
+# },
+# "before": {
+# "from_zones": [
+# {
+# "name": "one",
+# "to_zones": [
+# {
+# "name": "two",
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "names": [
+# "junos-dhcp-relay",
+# "junos-finger"
+# ]
+# },
+# "destination_address": {
+# "addresses": [
+# "a2",
+# "a4"
+# ]
+# },
+# "destination_address_excluded": true,
+# "dynamic_application": {
+# "names": [
+# "any"
+# ]
+# },
+# "source_address": {
+# "addresses": [
+# "a1",
+# "a3"
+# ]
+# },
+# "source_address_excluded": true,
+# "source_end_user_profile": "test_end_user_profile",
+# "source_identity": {
+# "unknown_user": true
+# },
+# "url_category": {
+# "names": [
+# "Enhanced_Web_Chat"
+# ]
+# }
+# },
+# "name": "test_policy_1",
+# "then": {
+# "count": true,
+# "deny": true,
+# "log": "session-close"
+# }
+# },
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "addresses": [
+# "a1"
+# ]
+# }
+# },
+# "name": "test_policy_2",
+# "then": {
+# "reject": {
+# "enable": true,
+# "profile": "test_dyn_app",
+# "ssl_proxy": {
+# "enable": true,
+# "profile_name": "SECURITY-SSL-PROXY"
+# }
+# }
+# }
+# }
+# ]
+# },
+# {
+# "name": "three",
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "addresses": [
+# "a2"
+# ]
+# },
+# "source_address": {
+# "addresses": [
+# "a1"
+# ]
+# }
+# },
+# "name": "test_policy_3",
+# "then": {
+# "permit": {
+# "application_services": {
+# "application_traffic_control_rule_set": "test_traffic_control",
+# "gprs_gtp_profile": "gtp1",
+# "icap_redirect": "test_icap",
+# "reverse_redirect_wx": "True",
+# "uac_policy": {
+# "enable": true
+# }
+# },
+# "firewall_authentication": {
+# "push_to_identity_management": true,
+# "web_authentication": [
+# "FWClient1"
+# ]
+# },
+# "tcp_options": {
+# "initial_tcp_mss": 64,
+# "window_scale": true
+# }
+# }
+# }
+# }
+# ]
+# }
+# ]
+# }
+# ],
+# "global": {
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv4": true
+# },
+# "source_address": {
+# "any_ipv4": true
+# }
+# },
+# "name": "test_glob",
+# "then": {
+# "deny": true
+# }
+# },
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "any_ipv6": true
+# }
+# },
+# "name": "test_glob_1",
+# "then": {
+# "deny": true
+# }
+# },
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "any_ipv6": true
+# }
+# },
+# "name": "test_glob_2",
+# "then": {
+# "deny": true
+# }
+# }
+# ]
+# }
+# },
+# "changed": true,
+# "commands": "<nc:security
+# xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+# <nc:policies delete="delete"/>
+# <nc:policies>
+# <nc:global>
+# <nc:policy>
+# <nc:name>test_glob_3</nc:name>
+# <nc:description>test update</nc:description>
+# <nc:match>
+# <nc:source-address>any</nc:source-address>
+# <nc:destination-address>any-ipv6</nc:destination-address>
+# <nc:application>any</nc:application>
+# </nc:match>
+# <nc:then>
+# <nc:deny/>
+# </nc:then>
+# </nc:policy>
+# </nc:global>
+# </nc:policies>
+# </nc:security>"
+# }
+# After state
+# -----------
+#
+# vagrant@vsrx> show security policies
+# Default policy: deny-all
+# Pre ID default policy: permit-all
+# Global policies:
+# Policy: test_glob_3, State: enabled, Index: 10, Scope Policy: 0, Sequence number: 1
+# From zones: any
+# To zones: any
+# Source addresses: any
+# Destination addresses: any-ipv6
+# Applications: any
+# Action: deny
+
+
+# Using deleted
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx> show security policies
+# Default policy: deny-all
+# Pre ID default policy: permit-all
+# Global policies:
+# Policy: test_glob_3, State: enabled, Index: 10, Scope Policy: 0, Sequence number: 1
+# From zones: any
+# To zones: any
+# Source addresses: any
+# Destination addresses: any-ipv6
+# Applications: any
+# Action: deny
+#
+- junipernetworks.junos.junos_security_policies:
+ config:
+ state: deleted
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+# "after": {},
+# "before": {
+# "global": {
+# "policies": [
+# {
+# "description": "test update",
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "any": true
+# }
+# },
+# "name": "test_glob_3",
+# "then": {
+# "deny": true
+# }
+# }
+# ]
+# }
+# },
+# "changed": true,
+# "commands": "<nc:security xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+# <nc:policies delete="delete"/></nc:security>"
+#
+# After state
+# -----------
+#
+# vagrant@vsrx> show security policies
+# Default policy: deny-all
+# Pre ID default policy: permit-all
+
+
+# Using parsed
+# parsed.cfg
+# ------------
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply>
+# <configuration>
+# <version>18.4R1-S3.1</version>
+# <services>
+# <ssl>
+# <termination>
+# <profile>
+# <name>test_ssl_term</name>
+# <server-certificate>SECURITY-cert</server-certificate>
+# </profile>
+# </termination>
+# <proxy>
+# <profile>
+# <name>SECURITY-SSL-PROXY</name>
+# <root-ca>SECURITY-cert</root-ca>
+# </profile>
+# </proxy>
+# </ssl>
+# <icap-redirect>
+# <profile>
+# <name>test_icap</name>
+# <server>
+# <name>test_icap_server</name>
+# <host>10.10.10.11</host>
+# </server>
+# </profile>
+# </icap-redirect>
+# <user-identification>
+# <device-information>
+# <end-user-profile>
+# <profile-name>
+# <name>test_end_user_profile</name>
+# <domain-name>test_domain</domain-name>
+# <attribute>
+# <name>device-identity</name>
+# <string>Windows</string>
+# </attribute>
+# </profile-name>
+# </end-user-profile>
+# </device-information>
+# </user-identification>
+# </services>
+# <security>
+# <address-book>
+# <name>global</name>
+# <address>
+# <name>a1</name>
+# <ip-prefix>200.0.113.0/24</ip-prefix>
+# </address>
+# <address>
+# <name>a2</name>
+# <ip-prefix>201.0.113.0/24</ip-prefix>
+# </address>
+# <address>
+# <name>a3</name>
+# <ip-prefix>202.0.113.0/24</ip-prefix>
+# </address>
+# <address>
+# <name>a4</name>
+# <ip-prefix>203.0.113.0/24</ip-prefix>
+# </address>
+# </address-book>
+# <dynamic-application>
+# <profile>
+# <name>test_dyn_app</name>
+# <redirect-message>
+# <type>
+# <custom-text>
+# <content>hello_world</content>
+# </custom-text>
+# </type>
+# </redirect-message>
+# </profile>
+# </dynamic-application>
+# <policies>
+# <policy>
+# <from-zone-name>one</from-zone-name>
+# <to-zone-name>two</to-zone-name>
+# <policy>
+# <name>test_policy_1</name>
+# <match>
+# <source-address>a1</source-address>
+# <source-address>a3</source-address>
+# <destination-address>a2</destination-address>
+# <destination-address>a4</destination-address>
+# <source-address-excluded />
+# <destination-address-excluded />
+# <application>junos-dhcp-relay</application>
+# <application>junos-finger</application>
+# <source-identity>authenticated-user</source-identity>
+# <source-identity>unknown-user</source-identity>
+# <source-end-user-profile>
+# <source-end-user-profile-name>test_end_user_profile</source-end-user-profile-name>
+# </source-end-user-profile>
+# <dynamic-application>any</dynamic-application>
+# <url-category>Enhanced_Web_Chat</url-category>
+# </match>
+# <then>
+# <deny />
+# <log>
+# <session-close />
+# </log>
+# <count></count>
+# </then>
+# </policy>
+# <policy>
+# <name>test_policy_2</name>
+# <match>
+# <source-address>a1</source-address>
+# <destination-address>any-ipv6</destination-address>
+# <application>any</application>
+# </match>
+# <then>
+# <reject>
+# <profile>test_dyn_app</profile>
+# <ssl-proxy>
+# <profile-name>SECURITY-SSL-PROXY</profile-name>
+# </ssl-proxy>
+# </reject>
+# </then>
+# </policy>
+# </policy>
+# <policy>
+# <from-zone-name>one</from-zone-name>
+# <to-zone-name>three</to-zone-name>
+# <policy>
+# <name>test_policy_3</name>
+# <match>
+# <source-address>a1</source-address>
+# <destination-address>a2</destination-address>
+# <application>any</application>
+# </match>
+# <then>
+# <permit>
+# <firewall-authentication>
+# <web-authentication>
+# <client-match>FWClient1</client-match>
+# </web-authentication>
+# <push-to-identity-management />
+# </firewall-authentication>
+# <destination-address>
+# <drop-untranslated />
+# </destination-address>
+# <application-services>
+# <gprs-gtp-profile>gtp1</gprs-gtp-profile>
+# <uac-policy></uac-policy>
+# <icap-redirect>test_icap</icap-redirect>
+# <application-traffic-control>
+# <rule-set>test_traffic_control</rule-set>
+# </application-traffic-control>
+# <reverse-redirect-wx />
+# </application-services>
+# <tcp-options>
+# <initial-tcp-mss>64</initial-tcp-mss>
+# <window-scale />
+# </tcp-options>
+# </permit>
+# </then>
+# </policy>
+# </policy>
+# <global>
+# <policy>
+# <name>test_glob_1</name>
+# <match>
+# <source-address>any-ipv6</source-address>
+# <destination-address>any-ipv6</destination-address>
+# <application>any</application>
+# </match>
+# <then>
+# <deny />
+# </then>
+# </policy>
+# <policy>
+# <name>test_glob_2</name>
+# <match>
+# <source-address>any-ipv6</source-address>
+# <destination-address>any-ipv6</destination-address>
+# <application>any</application>
+# </match>
+# <then>
+# <deny />
+# </then>
+# </policy>
+# </global>
+# </policies>
+# <zones>
+# <security-zone>
+# <name>one</name>
+# <interfaces>
+# <name>ge-0/0/0.0</name>
+# </interfaces>
+# </security-zone>
+# <security-zone>
+# <name>two</name>
+# <interfaces>
+# <name>ge-0/0/1.0</name>
+# </interfaces>
+# </security-zone>
+# <security-zone>
+# <name>three</name>
+# <interfaces>
+# <name>ge-0/0/2.0</name>
+# </interfaces>
+# </security-zone>
+# </zones>
+# <gprs>
+# <gtp>
+# <profile>
+# <name>gtp1</name>
+# </profile>
+# </gtp>
+# </gprs>
+# </security>
+# <interfaces>
+# <interface>
+# <name>ge-0/0/0</name>
+# <unit>
+# <name>0</name>
+# <family>
+# <inet>
+# <address>
+# <name>200.0.113.1/24</name>
+# </address>
+# </inet>
+# </family>
+# </unit>
+# </interface>
+# <interface>
+# <name>ge-0/0/1</name>
+# <unit>
+# <name>0</name>
+# <family>
+# <inet>
+# <address>
+# <name>201.0.113.1/24</name>
+# </address>
+# </inet>
+# </family>
+# </unit>
+# </interface>
+# <interface>
+# <name>ge-0/0/2</name>
+# <unit>
+# <name>0</name>
+# <family>
+# <inet>
+# <address>
+# <name>202.0.113.1/24</name>
+# </address>
+# </inet>
+# </family>
+# </unit>
+# </interface>
+# <interface>
+# <name>fxp0</name>
+# <unit>
+# <name>0</name>
+# <family>
+# <inet>
+# <dhcp></dhcp>
+# </inet>
+# </family>
+# </unit>
+# </interface>
+# </interfaces>
+# <class-of-service>
+# <application-traffic-control>
+# <rule-sets>
+# <name>test_traffic_control</name>
+# <rule>
+# <name>test_rule</name>
+# <match>
+# <application-known />
+# </match>
+# <then>
+# <log />
+# </then>
+# </rule>
+# </rule-sets>
+# </application-traffic-control>
+# </class-of-service>
+# <access>
+# <profile>
+# <name>WEBAUTH</name>
+# <client>
+# <name>FWClient1</name>
+# <firewall-user>
+# <password>$9$kq5Ftu1cSe</password>
+# </firewall-user>
+# </client>
+# </profile>
+# <firewall-authentication>
+# <web-authentication>
+# <default-profile>WEBAUTH</default-profile>
+# </web-authentication>
+# </firewall-authentication>
+# </access>
+# </configuration>
+# <database-status-information></database-status-information>
+# </rpc-reply>
+#
+- name: Parse NTP global running config
+ junipernetworks.junos.junos_security_policies:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+# "parsed": {
+# "from_zones": [
+# {
+# "name": "one",
+# "to_zones": [
+# {
+# "name": "two",
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "names": [
+# "junos-dhcp-relay",
+# "junos-finger"
+# ]
+# },
+# "destination_address": {
+# "addresses": [
+# "a2",
+# "a4"
+# ]
+# },
+# "destination_address_excluded": true,
+# "dynamic_application": {
+# "names": [
+# "any"
+# ]
+# },
+# "source_address": {
+# "addresses": [
+# "a1",
+# "a3"
+# ]
+# },
+# "source_address_excluded": true,
+# "source_end_user_profile": "test_end_user_profile",
+# "source_identity": {
+# "unknown_user": true
+# },
+# "url_category": {
+# "names": [
+# "Enhanced_Web_Chat"
+# ]
+# }
+# },
+# "name": "test_policy_1",
+# "then": {
+# "count": true,
+# "deny": true,
+# "log": "session-close"
+# }
+# },
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "addresses": [
+# "a1"
+# ]
+# }
+# },
+# "name": "test_policy_2",
+# "then": {
+# "reject": {
+# "enable": true,
+# "profile": "test_dyn_app",
+# "ssl_proxy": {
+# "enable": true,
+# "profile_name": "SECURITY-SSL-PROXY"
+# }
+# }
+# }
+# }
+# ]
+# },
+# {
+# "name": "three",
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "addresses": [
+# "a2"
+# ]
+# },
+# "source_address": {
+# "addresses": [
+# "a1"
+# ]
+# }
+# },
+# "name": "test_policy_3",
+# "then": {
+# "permit": {
+# "application_services": {
+# "application_traffic_control_rule_set": "test_traffic_control",
+# "gprs_gtp_profile": "gtp1",
+# "icap_redirect": "test_icap",
+# "reverse_redirect_wx": "True",
+# "uac_policy": {
+# "enable": true
+# }
+# },
+# "firewall_authentication": {
+# "push_to_identity_management": true,
+# "web_authentication": [
+# "FWClient1"
+# ]
+# },
+# "tcp_options": {
+# "initial_tcp_mss": 64,
+# "window_scale": true
+# }
+# }
+# }
+# }
+# ]
+# }
+# ]
+# }
+# ],
+# "global": {
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "any_ipv6": true
+# }
+# },
+# "name": "test_glob_1",
+# "then": {
+# "deny": true
+# }
+# },
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "any_ipv6": true
+# }
+# },
+# "name": "test_glob_2",
+# "then": {
+# "deny": true
+# }
+# }
+# ]
+# }
+# }
+
+
+# Using gathered
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx> show security policies
+# Default policy: deny-all
+# Pre ID default policy: permit-all
+# From zone: one, To zone: two
+# Policy: test_policy_1, State: enabled, Index: 4, Scope Policy: 0, Sequence number: 1
+# Source addresses(excluded): a1, a3
+# Destination addresses(excluded): a2, a4
+# Source-end-user-profile: test_end_user_profile(1)
+# Applications: junos-dhcp-relay, junos-finger
+# Dynamic Applications: any
+# Url-category: Enhanced_Web_Chat
+# Source identities: authenticated-user, unknown-user
+# Action: deny, log, count
+# Policy: test_policy_2, State: enabled, Index: 5, Scope Policy: 0, Sequence number: 2
+# Source addresses: a1
+# Destination addresses: any-ipv6
+# Applications: any
+# Action: reject
+# dynapp-redir-profile: test_dyn_app(1)
+# From zone: one, To zone: three
+# Policy: test_policy_3, State: enabled, Index: 6, Scope Policy: 0, Sequence number: 1
+# Source addresses: a1
+# Destination addresses: a2
+# Applications: any
+# Action: permit, drop-untranslated, firewall authentication, application services, unified access control
+# Application traffic control: test_traffic_control
+# Global policies:
+# Policy: test_glob_1, State: enabled, Index: 7, Scope Policy: 0, Sequence number: 1
+# From zones: any
+# To zones: any
+# Source addresses: any-ipv6
+# Destination addresses: any-ipv6
+# Applications: any
+# Action: deny
+# Policy: test_glob_2, State: enabled, Index: 8, Scope Policy: 0, Sequence number: 2
+# From zones: any
+# To zones: any
+# Source addresses: any-ipv6
+# Destination addresses: any-ipv6
+# Applications: any
+# Action: deny
+#
+- junipernetworks.junos.junos_security_policies:
+ state: gathered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+# "changed": false,
+# "gathered": {
+# "from_zones": [
+# {
+# "name": "one",
+# "to_zones": [
+# {
+# "name": "two",
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "names": [
+# "junos-dhcp-relay",
+# "junos-finger"
+# ]
+# },
+# "destination_address": {
+# "addresses": [
+# "a2",
+# "a4"
+# ]
+# },
+# "destination_address_excluded": true,
+# "dynamic_application": {
+# "names": [
+# "any"
+# ]
+# },
+# "source_address": {
+# "addresses": [
+# "a1",
+# "a3"
+# ]
+# },
+# "source_address_excluded": true,
+# "source_end_user_profile": "test_end_user_profile",
+# "source_identity": {
+# "unknown_user": true
+# },
+# "url_category": {
+# "names": [
+# "Enhanced_Web_Chat"
+# ]
+# }
+# },
+# "name": "test_policy_1",
+# "then": {
+# "count": true,
+# "deny": true,
+# "log": "session-close"
+# }
+# },
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "addresses": [
+# "a1"
+# ]
+# }
+# },
+# "name": "test_policy_2",
+# "then": {
+# "reject": {
+# "enable": true,
+# "profile": "test_dyn_app",
+# "ssl_proxy": {
+# "enable": true,
+# "profile_name": "SECURITY-SSL-PROXY"
+# }
+# }
+# }
+# }
+# ]
+# },
+# {
+# "name": "three",
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "addresses": [
+# "a2"
+# ]
+# },
+# "source_address": {
+# "addresses": [
+# "a1"
+# ]
+# }
+# },
+# "name": "test_policy_3",
+# "then": {
+# "permit": {
+# "application_services": {
+# "application_traffic_control_rule_set": "test_traffic_control",
+# "gprs_gtp_profile": "gtp1",
+# "icap_redirect": "test_icap",
+# "reverse_redirect_wx": "True",
+# "uac_policy": {
+# "enable": true
+# }
+# },
+# "firewall_authentication": {
+# "push_to_identity_management": true,
+# "web_authentication": [
+# "FWClient1"
+# ]
+# },
+# "tcp_options": {
+# "initial_tcp_mss": 64,
+# "window_scale": true
+# }
+# }
+# }
+# }
+# ]
+# }
+# ]
+# }
+# ],
+# "global": {
+# "policies": [
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "any_ipv6": true
+# }
+# },
+# "name": "test_glob_1",
+# "then": {
+# "deny": true
+# }
+# },
+# {
+# "match": {
+# "application": {
+# "any": true
+# },
+# "destination_address": {
+# "any_ipv6": true
+# },
+# "source_address": {
+# "any_ipv6": true
+# }
+# },
+# "name": "test_glob_2",
+# "then": {
+# "deny": true
+# }
+# }
+# ]
+# }
+# }
+# }
+
+
+# Using rendered
+#
+# Before state
+# ------------
+#
+- junipernetworks.junos.junos_security_policies:
+ config:
+ global:
+ policies:
+ - description: test update
+ match:
+ application:
+ any: true
+ destination_address:
+ any_ipv6: true
+ source_address:
+ any: true
+ name: test_glob_3
+ then:
+ deny: true
+ state: rendered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "rendered": "<nc:security
+# xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+# <nc:policies>
+# <nc:global>
+# <nc:policy>
+# <nc:name>test_glob_3</nc:name>
+# <nc:description>test update</nc:description>
+# <nc:match>
+# <nc:source-address>any</nc:source-address>
+# <nc:destination-address>any-ipv6</nc:destination-address>
+# <nc:application>any</nc:application>
+# </nc:match>
+# <nc:then>
+# <nc:deny/>
+# </nc:then>
+# </nc:policy>
+# </nc:global>
+# </nc:policies>
+# </nc:security>"
+
+
+"""
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when state is I(merged), I(replaced), I(overridden) or I(deleted)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when state is I(merged), I(replaced), I(overridden) or I(deleted)
+ type: list
+ sample:
+ - "<rpc-reply>
+ <configuration>
+ <security>
+ <policies>
+ <global>
+ <policy>
+ <name>test_glob_1</name>
+ <match>
+ <source-address>any-ipv6</source-address>
+ <destination-address>any-ipv6</destination-address>
+ <application>any</application>
+ </match>
+ <then>
+ <deny />
+ </then>
+ </policy>
+ </global>
+ </policies>
+ </security>
+ </configuration>
+ </rpc-reply>"
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when state is I(rendered)
+ type: dict
+ sample:
+ - "<rpc-reply>
+ <configuration>
+ <security>
+ <policies>
+ <global>
+ <policy>
+ <name>test_glob_1</name>
+ <match>
+ <source-address>any-ipv6</source-address>
+ <destination-address>any-ipv6</destination-address>
+ <application>any</application>
+ </match>
+ <then>
+ <deny />
+ </then>
+ </policy>
+ </global>
+ </policies>
+ </security>
+ </configuration>
+ </rpc-reply>"
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when state is I(gathered)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when state is I(parsed)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.security_policies.security_policies import (
+ Security_policiesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.security_policies.security_policies import (
+ Security_policies,
+)
+
+
+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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+
+ module = AnsibleModule(
+ argument_spec=Security_policiesArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+
+ result = Security_policies(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_security_policies_global.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_security_policies_global.py
new file mode 100644
index 000000000..19cbe091a
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_security_policies_global.py
@@ -0,0 +1,994 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2022 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_security_policies_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_security_policies_global
+version_added: 2.9.0
+short_description: Manage global security policy settings on Juniper JUNOS devices
+description: This module provides declarative management of global security policy settings on Juniper JUNOS devices
+author: Pranav Bhatt (@pranav-bhatt)
+requirements:
+ - ncclient (>=v0.6.4)
+ - xmltodict (>=0.12.0)
+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,https://docs.ansible.com/ansible/latest/network/user_guide/platform_junos.html).
+- Tested against JunOS v18.4R1
+options:
+ config:
+ description: A dictionary of security policies
+ type: dict
+ suboptions:
+ default_policy:
+ description:
+ - Configure the default security policy that defines the actions the device takes on a packet that does not match any user-defined policy.
+ choices:
+ - deny-all
+ - permit-all
+ type: str
+ policy_rematch:
+ description:
+ - Enable the device to reevaluate an active session when its associated security policy is modified. The session remains open if it still matches
+ the policy that allowed the session initially.
+ type: dict
+ suboptions:
+ enable:
+ description:
+ - Enable the device to reevaluate an active session when its associated security policy is modified.
+ The session remains open if it still matches the policy that allowed the session initially.
+ type: bool
+ extensive:
+ description:
+ - When a policy is modified or deleted, extensive option checks if any suitable policy permit to keep these sessions alive.
+ type: bool
+ policy_stats:
+ description:
+ - Configure policies statistics.
+ type: dict
+ suboptions:
+ enable:
+ description:
+ - Enable policies statistics.
+ type: bool
+ system_wide:
+ description:
+ - Configure systemwide policies statistics.
+ type: bool
+ pre_id_default_policy_action:
+ description:
+ - Configures default policy actions that occur prior to dynamic application identification (AppID) when the packet matches the criteria.
+ type: dict
+ suboptions:
+ log:
+ description:
+ - Specifies the log details at session close time and session initialization time.
+ type: dict
+ suboptions:
+ session_init:
+ description:
+ - Enable logging on session initialization time
+ type: bool
+ session_close:
+ description:
+ - Enable logging on session close time
+ type: bool
+ session_timeout:
+ description:
+ - When you update a session, the session timeout is configured, which specifies the session timeout details in seconds.
+ type: dict
+ suboptions:
+ icmp:
+ description:
+ - Timeout value for ICMP sessions (seconds)
+ type: int
+ icmp6:
+ description:
+ - Timeout value for ICMP6 sessions (seconds)
+ type: int
+ ospf:
+ description:
+ - Timeout value for OSPF sessions (seconds)
+ type: int
+ others:
+ description:
+ - Timeout value for other sessions (seconds)
+ type: int
+ tcp:
+ description:
+ - Timeout value for TCP sessions (seconds)
+ type: int
+ udp:
+ description:
+ - Timeout value for UDP sessions (seconds)
+ type: int
+ traceoptions:
+ description: A dictionary of security policies
+ type: dict
+ suboptions:
+ file:
+ description: A dictionary to configure the trace file options
+ type: dict
+ suboptions:
+ files:
+ description:
+ - Maximum number of trace files
+ type: int
+ match:
+ description: Refine the output to include lines that contain the regular expression.
+ type: str
+ size:
+ description: The maximum tracefile size
+ type: str
+ world_readable:
+ description: The world_readable option enables any user to read the file.
+ type: bool
+ no_world_readable:
+ description: Log files can be accessed only by the user who configures the tracing operation.
+ type: bool
+ flag:
+ description:
+ - Trace operation to perform.
+ choices:
+ - all
+ - configuration
+ - compilation
+ - ipc
+ - lookup
+ - routing-socket
+ - rules
+ type: str
+ no_remote_trace:
+ description: Disable remote tracing.
+ type: bool
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the JunOS device
+ by executing the command B(show security policies).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ behaviour for this module.
+ - The state I(replaced) will replace the running configuration with the provided
+ configuration
+ - The state I(replaced) and state I(overridden) have the same behaviour
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command
+ I(show security policies detail) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+"""
+EXAMPLES = """
+# Using merged
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show security policies
+# default-policy {
+# permit-all;
+# }
+#
+- name: Update the running configuration with provided configuration
+ junipernetworks.junos.junos_security_policies_global:
+ config:
+ policy_rematch:
+ enable: true
+ policy_stats:
+ enable: true
+ pre_id_default_policy_action:
+ log:
+ session_init: true
+ session_timeout:
+ icmp: 10
+ others: 10
+ traceoptions:
+ file:
+ files: 4
+ match: /[A-Z]*/gm
+ size: 10k
+ no_world_readable: true
+ flag: all
+ no_remote_trace: true
+ state: merged
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "default_policy": "permit-all",
+# "policy_rematch": {
+# "enable": true,
+# "extensive": true
+# },
+# "policy_stats": {
+# "enable": true,
+# "system_wide": true
+# },
+# "pre_id_default_policy_action": {
+# "log": {
+# "session_init": true
+# },
+# "session_timeout": {
+# "icmp": 10,
+# "others": 10
+# }
+# },
+# "traceoptions": {
+# "file": {
+# "files": 3,
+# "match": "/[A-Z]*/gm",
+# "no_world_readable": true,
+# "size": "10k"
+# },
+# "flag": "all",
+# "no_remote_trace": true
+# }
+# },
+# "before": {},
+# "changed": true,
+# "commands": "<nc:security xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"><nc:policies>
+# <nc:policy-rematch> <nc:extensive/></nc:policy-rematch><nc:policy-stats>
+# <nc:system-wide>enable</nc:system-wide></nc:policy-stats><nc:pre-id-default-policy>
+# <nc:then><nc:log><nc:session-init/></nc:log><nc:session-timeout><nc:icmp>10</nc:icmp>
+# <nc:others>10</nc:others></nc:session-timeout></nc:then></nc:pre-id-default-policy>
+# <nc:traceoptions><nc:file><nc:files>3</nc:files><nc:match>/[A-Z]*/gm</nc:match>
+# <nc:size>10k</nc:size><nc:no-world-readable/></nc:file><nc:flag><nc:name>all
+# </nc:name></nc:flag><nc:no-remote-trace/></nc:traceoptions></nc:policies></nc:security>"
+# After state
+# -----------
+#
+# vagrant@vsrx# show security policies
+# traceoptions {
+# no-remote-trace;
+# file size 10k files 4 no-world-readable match "/[A-Z]*/gm";
+# flag all;
+# }
+# default-policy {
+# permit-all;
+# }
+# policy-rematch extensive;
+# policy-stats;
+# pre-id-default-policy {
+# then {
+# log {
+# session-init;
+# }
+# session-timeout {
+# icmp 10;
+# others 10;
+# }
+# }
+# }
+#
+#
+# Using Replaced
+# Before state
+# ------------
+#
+# vagrant@vsrx# show security policies
+# traceoptions {
+# no-remote-trace;
+# file size 10k files 4 no-world-readable match "/[A-Z]*/gm";
+# flag all;
+# }
+# default-policy {
+# permit-all;
+# }
+# policy-rematch extensive;
+# policy-stats;
+# pre-id-default-policy {
+# then {
+# log {
+# session-init;
+# }
+# session-timeout {
+# icmp 10;
+# others 10;
+# }
+# }
+# }
+
+- name: Replace the running configuration with provided configuration
+ junipernetworks.junos.junos_security_policies_global:
+ config:
+ default_policy: deny-all
+ policy_rematch:
+ enable: true
+ policy_stats:
+ enable: true
+ pre_id_default_policy_action:
+ log:
+ session_init: true
+ session_timeout:
+ icmp: 10
+ others: 10
+ traceoptions:
+ file:
+ files: 4
+ match: /[A-Z]*/gm
+ size: 10k
+ no_world_readable: true
+ flag: all
+ no_remote_trace: true
+ state: replaced
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "default_policy": "deny-all",
+# "policy_rematch": {
+# "enable": true
+# },
+# "policy_stats": {
+# "enable": true
+# },
+# "pre_id_default_policy_action": {
+# "log": {
+# "session_init": true
+# },
+# "session_timeout": {
+# "icmp": 10,
+# "others": 10
+# }
+# },
+# "traceoptions": {
+# "file": {
+# "files": 4,
+# "match": "/[A-Z]*/gm",
+# "no_world_readable": true,
+# "size": "10k"
+# },
+# "flag": "all",
+# "no_remote_trace": true
+# }
+# },
+# "before": {
+# "default_policy": "permit-all",
+# "policy_rematch": {
+# "enable": true,
+# "extensive": true
+# },
+# "policy_stats": {
+# "enable": true
+# },
+# "pre_id_default_policy_action": {
+# "log": {
+# "session_init": true
+# },
+# "session_timeout": {
+# "icmp": 10,
+# "others": 10
+# }
+# },
+# "traceoptions": {
+# "file": {
+# "files": 4,
+# "match": "/[A-Z]*/gm",
+# "no_world_readable": true,
+# "size": "10k"
+# },
+# "flag": "all",
+# "no_remote_trace": true
+# }
+# },
+# "changed": true,
+# "commands": "<nc:security xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+# <nc:policies delete="delete"/><nc:policies><nc:default-policy><nc:deny-all/></nc:default-policy>
+# <nc:policy-rematch> </nc:policy-rematch><nc:policy-stats> </nc:policy-stats><nc:pre-id-default-policy>
+# <nc:then><nc:log><nc:session-init/></nc:log><nc:session-timeout><nc:icmp>10</nc:icmp><nc:others>10
+# </nc:others></nc:session-timeout></nc:then></nc:pre-id-default-policy><nc:traceoptions><nc:file>
+# <nc:files>4</nc:files><nc:match>/[A-Z]*/gm</nc:match><nc:size>10k</nc:size><nc:no-world-readable/>
+# </nc:file><nc:flag><nc:name>all</nc:name></nc:flag><nc:no-remote-trace/></nc:traceoptions></nc:policies>
+# </nc:security>"
+#
+# After state
+# -----------
+#
+# vagrant@vsrx# show security policies
+# traceoptions {
+# no-remote-trace;
+# file size 10k files 4 no-world-readable match "/[A-Z]*/gm";
+# flag all;
+# }
+# default-policy {
+# deny-all;
+# }
+# policy-rematch;
+# policy-stats;
+# pre-id-default-policy {
+# then {
+# log {
+# session-init;
+# }
+# session-timeout {
+# icmp 10;
+# others 10;
+# }
+# }
+# }
+
+# Using overridden
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show security policies
+# traceoptions {
+# no-remote-trace;
+# file size 10k files 4 no-world-readable match "/[A-Z]*/gm";
+# flag all;
+# }
+# default-policy {
+# permit-all;
+# }
+# policy-rematch extensive;
+# policy-stats;
+# pre-id-default-policy {
+# then {
+# log {
+# session-init;
+# }
+# session-timeout {
+# icmp 10;
+# others 10;
+# }
+# }
+# }
+
+- name: Replace the running configuration with provided configuration
+ junipernetworks.junos.junos_security_policies_global:
+ config:
+ default_policy: deny-all
+ policy_rematch:
+ enable: true
+ policy_stats:
+ enable: true
+ pre_id_default_policy_action:
+ log:
+ session_init: true
+ session_timeout:
+ icmp: 10
+ others: 10
+ traceoptions:
+ file:
+ files: 4
+ match: /[A-Z]*/gm
+ size: 10k
+ no_world_readable: true
+ flag: all
+ no_remote_trace: true
+ state: overridden
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "default_policy": "deny-all",
+# "policy_rematch": {
+# "enable": true
+# },
+# "policy_stats": {
+# "enable": true
+# },
+# "pre_id_default_policy_action": {
+# "log": {
+# "session_init": true
+# },
+# "session_timeout": {
+# "icmp": 10,
+# "others": 10
+# }
+# },
+# "traceoptions": {
+# "file": {
+# "files": 4,
+# "match": "/[A-Z]*/gm",
+# "no_world_readable": true,
+# "size": "10k"
+# },
+# "flag": "all",
+# "no_remote_trace": true
+# }
+# },
+# "before": {
+# "default_policy": "permit-all",
+# "policy_rematch": {
+# "enable": true,
+# "extensive": true
+# },
+# "policy_stats": {
+# "enable": true
+# },
+# "pre_id_default_policy_action": {
+# "log": {
+# "session_init": true
+# },
+# "session_timeout": {
+# "icmp": 10,
+# "others": 10
+# }
+# },
+# "traceoptions": {
+# "file": {
+# "files": 4,
+# "match": "/[A-Z]*/gm",
+# "no_world_readable": true,
+# "size": "10k"
+# },
+# "flag": "all",
+# "no_remote_trace": true
+# }
+# },
+# "changed": true,
+# "commands": "<nc:security xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+# <nc:policies delete="delete"/><nc:policies><nc:default-policy><nc:deny-all/></nc:default-policy>
+# <nc:policy-rematch> </nc:policy-rematch><nc:policy-stats> </nc:policy-stats><nc:pre-id-default-policy>
+# <nc:then><nc:log><nc:session-init/></nc:log><nc:session-timeout><nc:icmp>10</nc:icmp><nc:others>10
+# </nc:others></nc:session-timeout></nc:then></nc:pre-id-default-policy><nc:traceoptions><nc:file>
+# <nc:files>4</nc:files><nc:match>/[A-Z]*/gm</nc:match><nc:size>10k</nc:size><nc:no-world-readable/>
+# </nc:file><nc:flag><nc:name>all</nc:name></nc:flag><nc:no-remote-trace/></nc:traceoptions></nc:policies>
+# </nc:security>"
+#
+# After state
+# -----------
+#
+# vagrant@vsrx# show security policies
+# traceoptions {
+# no-remote-trace;
+# file size 10k files 4 no-world-readable match "/[A-Z]*/gm";
+# flag all;
+# }
+# default-policy {
+# deny-all;
+# }
+# policy-rematch;
+# policy-stats;
+# pre-id-default-policy {
+# then {
+# log {
+# session-init;
+# }
+# session-timeout {
+# icmp 10;
+# others 10;
+# }
+# }
+# }
+#
+# Using deleted
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show security policies
+# traceoptions {
+# no-remote-trace;
+# file size 10k files 4 no-world-readable match "/[A-Z]*/gm";
+# flag all;
+# }
+# default-policy {
+# deny-all;
+# }
+# policy-rematch;
+# policy-stats;
+# pre-id-default-policy {
+# then {
+# log {
+# session-init;
+# }
+# session-timeout {
+# icmp 10;
+# others 10;
+# }
+# }
+# }
+#
+- name: Delete the running configuration
+ junipernetworks.junos.junos_security_policies_global:
+ config:
+ state: deleted
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {},
+# "before": {
+# "default_policy": "deny-all",
+# "policy_rematch": {
+# "enable": true
+# },
+# "policy_stats": {
+# "enable": true
+# },
+# "pre_id_default_policy_action": {
+# "log": {
+# "session_init": true
+# },
+# "session_timeout": {
+# "icmp": 10,
+# "others": 10
+# }
+# },
+# "traceoptions": {
+# "file": {
+# "files": 4,
+# "match": "/[A-Z]*/gm",
+# "no_world_readable": true,
+# "size": "10k"
+# },
+# "flag": "all",
+# "no_remote_trace": true
+# }
+# },
+# "changed": true,
+# "commands": "<nc:security xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+# <nc:policies delete="delete"/></nc:security>"
+#
+# After state
+# -----------
+#
+# vagrant@vsrx# show security policies
+#
+#
+# Using gathered
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show security policies
+# traceoptions {
+# no-remote-trace;
+# file size 10k files 4 no-world-readable match "/[A-Z]*/gm";
+# flag all;
+# }
+# default-policy {
+# deny-all;
+# }
+# policy-rematch;
+# policy-stats;
+# pre-id-default-policy {
+# then {
+# log {
+# session-init;
+# }
+# session-timeout {
+# icmp 10;
+# others 10;
+# }
+# }
+# }
+#
+- name: Gather the running configuration
+ junipernetworks.junos.junos_security_policies_global:
+ config:
+ state: gathered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "gathered": {
+# "default_policy": "deny-all",
+# "policy_rematch": {
+# "enable": true
+# },
+# "policy_stats": {
+# "enable": true
+# },
+# "pre_id_default_policy_action": {
+# "log": {
+# "session_init": true
+# },
+# "session_timeout": {
+# "icmp": 10,
+# "others": 10
+# }
+# },
+# "traceoptions": {
+# "file": {
+# "files": 4,
+# "match": "/[A-Z]*/gm",
+# "no_world_readable": true,
+# "size": "10k"
+# },
+# "flag": "all",
+# "no_remote_trace": true
+# }
+# }
+#
+# Using rendered
+#
+# Before state
+# ------------
+#
+- name: Render the provided configuration
+ junipernetworks.junos.junos_security_policies_global:
+ config:
+ default_policy: deny-all
+ policy_rematch:
+ enable: true
+ policy_stats:
+ enable: true
+ pre_id_default_policy_action:
+ log:
+ session_init: true
+ session_timeout:
+ icmp: 10
+ others: 10
+ traceoptions:
+ file:
+ files: 4
+ match: /[A-Z]*/gm
+ size: 10k
+ no_world_readable: true
+ flag: all
+ no_remote_trace: true
+ state: replaced
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "rendered": "<nc:security xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"><nc:policies>
+# <nc:default-policy><nc:deny-all/></nc:default-policy><nc:policy-rematch> </nc:policy-rematch>
+# <nc:policy-stats> </nc:policy-stats><nc:pre-id-default-policy><nc:then><nc:log><nc:session-init/>
+# </nc:log><nc:session-timeout><nc:icmp>10</nc:icmp><nc:others>10</nc:others></nc:session-timeout>
+# </nc:then></nc:pre-id-default-policy><nc:traceoptions><nc:file><nc:files>4</nc:files>
+# <nc:match>/[A-Z]*/gm</nc:match><nc:size>10k</nc:size><nc:no-world-readable/></nc:file><nc:flag>
+# <nc:name>all</nc:name></nc:flag><nc:no-remote-trace/></nc:traceoptions></nc:policies>
+# </nc:security>"
+#
+# Using parsed
+# parsed.cfg
+# ------------
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <version>18.4R1-S2.4</version>
+# <security>
+# <policies>
+# <traceoptions>
+# <no-remote-trace />
+# <file>
+# <size>10k</size>
+# <files>3</files>
+# <no-world-readable />
+# <match>/[A-Z]*/gm</match>
+# </file>
+# <flag>
+# <name>all</name>
+# </flag>
+# </traceoptions>
+# <default-policy>
+# <permit-all />
+# </default-policy>
+# <policy-rematch>
+# <extensive />
+# </policy-rematch>
+# <policy-stats>
+# <system-wide>enable</system-wide>
+# </policy-stats>
+# <pre-id-default-policy>
+# <then>
+# <log>
+# <session-init />
+# </log>
+# <session-timeout>
+# <icmp>10</icmp>
+# <others>10</others>
+# </session-timeout>
+# </then>
+# </pre-id-default-policy>
+# </policies>
+# </security>
+# </configuration>
+# </rpc-reply>
+#
+#
+- name: Parse security policies global running config
+ junipernetworks.junos.junos_security_policies_global:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "parsed": {
+# "default_policy": "permit-all",
+# "policy_rematch": {
+# "enable": true,
+# "extensive": true
+# },
+# "policy_stats": {
+# "enable": true,
+# "system_wide": true
+# },
+# "pre_id_default_policy_action": {
+# "log": {
+# "session_init": true
+# },
+# "session_timeout": {
+# "icmp": 10,
+# "others": 10
+# }
+# },
+# "traceoptions": {
+# "file": {
+# "files": 3,
+# "match": "/[A-Z]*/gm",
+# "no_world_readable": true,
+# "size": "10k"
+# },
+# "flag": "all",
+# "no_remote_trace": true
+# }
+# }
+#
+#
+"""
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when state is I(merged), I(replaced), I(overridden), I(deleted)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when state is I(merged), I(replaced), I(overridden) or I(deleted)
+ type: list
+ sample:
+ - "<rpc-reply>
+ <configuration>
+ <security>
+ <policies>
+ <default-policy>
+ <permit-all />
+ </default-policy>
+ </policies>
+ </security>
+ </configuration>
+ </rpc-reply>"
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when state is I(rendered)
+ type: dict
+ sample:
+ - "<rpc-reply>
+ <configuration>
+ <security>
+ <policies>
+ <default-policy>
+ <permit-all />
+ </default-policy>
+ </policies>
+ </security>
+ </configuration>
+ </rpc-reply>"
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when state is I(gathered)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when state is I(parsed)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.security_policies_global.security_policies_global import (
+ Security_policies_globalArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.security_policies_global.security_policies_global import (
+ Security_policies_global,
+)
+
+
+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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+
+ module = AnsibleModule(
+ argument_spec=Security_policies_globalArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+
+ result = Security_policies_global(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_security_zones.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_security_zones.py
new file mode 100644
index 000000000..36032cbca
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_security_zones.py
@@ -0,0 +1,2001 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2022 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_security_zones
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+ANSIBLE_METADATA = {
+ "metadata_version": "1.1",
+ "status": ["preview"],
+ "supported_by": "network",
+}
+
+DOCUMENTATION = """
+---
+module: junos_security_zones
+version_added: 2.9.0
+short_description: Manage security zones on Juniper JUNOS devices
+description: This module provides declarative management of security zones on Juniper JUNOS devices
+author: Pranav Bhatt (@pranav-bhatt)
+requirements:
+ - ncclient (>=v0.6.4)
+ - xmltodict (>=0.12.0)
+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,https://docs.ansible.com/ansible/latest/network/user_guide/platform_junos.html).
+- Tested against JunOS v18.4R1
+options:
+ config:
+ description: Dictionary of security zone parameters
+ type: dict
+ suboptions:
+ functional_zone_management:
+ description:
+ - Functional zone to configure host for out of band management interfaces
+ type: dict
+ suboptions:
+ description:
+ description:
+ - Text description of zone
+ type: str
+ host_inbound_traffic: &host_inbound_traffic
+ description:
+ - Allowed system services & protocols
+ type: dict
+ suboptions:
+ protocols:
+ description:
+ - Protocol type of incoming traffic to accept
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Type of incoming protocol to accept
+ type: str
+ except:
+ description:
+ - Disallow the specified protocol traffic
+ type: bool
+ system_services:
+ description:
+ - Type of incoming system-service traffic to accept
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Type of incoming system-service traffic to accept
+ type: str
+ except:
+ description:
+ - Disallow the specified incoming system-service traffic
+ type: bool
+ interfaces: &interfaces
+ description:
+ - Interfaces that are part of this zone
+ type: list
+ elements: str
+ screen: &screen
+ description:
+ - Name of ids option object applied to the zone
+ type: str
+ zones:
+ description:
+ - Security zones
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Name of the security zone
+ type: str
+ address_book:
+ description:
+ - Address book entries
+ type: dict
+ suboptions:
+ addresses:
+ description:
+ - Define security addresses
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Name of address
+ type: str
+ ip_prefix:
+ description:
+ - Numeric IPv4 or IPv6 address with prefix
+ type: str
+ description:
+ description:
+ - Text description of address
+ type: str
+ dns_name:
+ description:
+ - DNS address name
+ type: dict
+ suboptions:
+ name:
+ description:
+ - Fully qualified hostname
+ type: str
+ ipv4_only:
+ description:
+ - IPv4 dns address
+ type: bool
+ ipv6_only:
+ description:
+ - IPv6 dns address
+ type: bool
+ range_address:
+ description:
+ - Address range
+ type: dict
+ suboptions:
+ from:
+ description:
+ - Start of address range
+ type: str
+ to:
+ description:
+ - End of address range
+ type: str
+ wildcard_address:
+ description:
+ - Numeric IPv4 wildcard address with in the form of a.d.d.r/netmask
+ type: str
+ address_sets:
+ description:
+ - Define security address sets
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Name of address set
+ type: str
+ addresses:
+ description:
+ - Addresses to be included in this set
+ type: list
+ elements: str
+ address_sets:
+ description:
+ - Define an address-set name
+ type: list
+ elements: str
+ description:
+ description:
+ - Text description of address set
+ type: str
+ advance_policy_based_routing_profile:
+ description:
+ - Enable Advance Policy Based Routing on this zone
+ type: str
+ advanced_connection_tracking:
+ description:
+ - Enable Advance Policy Based Routing on this zone
+ type: dict
+ suboptions:
+ mode:
+ description:
+ - Set connection tracking mode
+ type: str
+ choices:
+ - allow-any-host
+ - allow-target-host
+ - allow-target-host-port
+ timeout:
+ description:
+ - Timeout value in seconds for advanced-connection-tracking table for this zone
+ type: int
+ track_all_policies_to_this_zone:
+ description:
+ - Mandate all policies with to-zone set to this zone to do connection track table lookup
+ type: bool
+ application_tracking:
+ description:
+ - Enable Application tracking support for this zone
+ type: bool
+ description:
+ description:
+ - Text description of zone
+ type: str
+ enable_reverse_reroute:
+ description:
+ - Enable Reverse route lookup when there is change in ingress interface
+ type: bool
+ host_inbound_traffic: *host_inbound_traffic
+ interfaces: *interfaces
+ screen: *screen
+ source_identity_log:
+ description:
+ - Show user and group info in session log for this zone
+ type: bool
+ tcp_rst:
+ description:
+ - Send RST for NON-SYN packet not matching TCP session
+ type: bool
+ unidirectional_session_refreshing:
+ description:
+ - Enable unidirectional session refreshing on this zone
+ type: bool
+
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the JunOS device
+ by executing the command B(show security policies).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ behaviour for this module.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command
+ I(show security policies detail) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+"""
+EXAMPLES = """# Using merged
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show security zones
+#
+# [edit]
+# vagrant@vsrx# show security zones
+#
+- name: Merge the provided configuration with the exisiting running configuration
+ junipernetworks.junos.junos_security_zones: &merged
+ config:
+ functional_zone_management:
+ description: test description
+ host_inbound_traffic:
+ protocols:
+ - name: all
+ - name: bgp
+ except: true
+ system_services:
+ - name: all
+ - except: true
+ name: dhcp
+ interfaces:
+ - ge-0/0/1.0
+ - ge-0/0/2.0
+ screen: test_screen
+ security_zones:
+ - address_book:
+ address_sets:
+ - addresses:
+ - test_adr1
+ - test_adr2
+ name: test_adrset1
+ - addresses:
+ - test_adr3
+ - test_adr4
+ name: test_adrset2
+ - address_sets:
+ - test_adrset1
+ - test_adrset2
+ addresses:
+ - test_adr5
+ description: test description
+ name: test_adrset3
+ addresses:
+ - description: test desc
+ ip_prefix: 10.0.0.0/24
+ name: test_adr1
+ - dns_name:
+ ipv6_only: true
+ name: 1.1.1.1
+ name: test_adr2
+ - name: test_adr3
+ range_address:
+ from: 10.2.0.1
+ to: 10.2.0.2
+ - name: test_adr4
+ wildcard_address: 10.3.0.1/24
+ - description: test desc
+ ip_prefix: 10.1.0.0/24
+ name: test_adr5
+ advance_policy_based_routing_profile: test_profile
+ application_tracking: true
+ description: test description
+ enable_reverse_reroute: true
+ host_inbound_traffic:
+ protocols:
+ - name: all
+ - except: true
+ name: bgp
+ system_services:
+ - name: all
+ - except: true
+ name: dhcp
+ interfaces:
+ - ge-0/0/3.0
+ - ge-0/0/4.0
+ name: test_sec_zone1
+ screen: test_screen
+ source_identity_log: true
+ tcp_rst: true
+ state: merged
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "functional_zone_management": {
+# "description": "test description",
+# "host_inbound_traffic": {
+# "protocols": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "bgp"
+# }
+# ],
+# "system_services": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "dhcp"
+# }
+# ]
+# },
+# "interfaces": [
+# "ge-0/0/1.0",
+# "ge-0/0/2.0"
+# ],
+# "screen": "test_screen"
+# },
+# "security_zones": [
+# {
+# "address_book": {
+# "address_sets": [
+# {
+# "addresses": [
+# "test_adr1",
+# "test_adr2"
+# ],
+# "name": "test_adrset1"
+# },
+# {
+# "addresses": [
+# "test_adr3",
+# "test_adr4"
+# ],
+# "name": "test_adrset2"
+# },
+# {
+# "address_sets": [
+# "test_adrset1",
+# "test_adrset2"
+# ],
+# "addresses": [
+# "test_adr5"
+# ],
+# "description": "test description",
+# "name": "test_adrset3"
+# }
+# ],
+# "addresses": [
+# {
+# "description": "test desc",
+# "ip_prefix": "10.0.0.0/24",
+# "name": "test_adr1"
+# },
+# {
+# "dns_name": {
+# "ipv6_only": true,
+# "name": "1.1.1.1"
+# },
+# "name": "test_adr2"
+# },
+# {
+# "name": "test_adr3",
+# "range_address": {
+# "from": "10.2.0.1",
+# "to": "10.2.0.2"
+# }
+# },
+# {
+# "name": "test_adr4",
+# "wildcard_address": "10.3.0.1/24"
+# },
+# {
+# "description": "test desc",
+# "ip_prefix": "10.1.0.0/24",
+# "name": "test_adr5"
+# }
+# ]
+# },
+# "advance_policy_based_routing_profile": "test_profile",
+# "application_tracking": true,
+# "description": "test description",
+# "enable_reverse_reroute": true,
+# "host_inbound_traffic": {
+# "protocols": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "bgp"
+# }
+# ],
+# "system_services": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "dhcp"
+# }
+# ]
+# },
+# "interfaces": [
+# "ge-0/0/3.0",
+# "ge-0/0/4.0"
+# ],
+# "name": "test_sec_zone1",
+# "screen": "test_screen",
+# "source_identity_log": true,
+# "tcp_rst": true
+# }
+# ]
+# },
+# "before": {},
+# "changed": true,
+# "commands":
+# '<nc:security xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><nc:zones><nc:functional-zone><nc:management><nc:description>t'
+# 'est description</nc:description><nc:host-inbound-traffic><nc:protocols><nc:name>all</nc:name></nc:protocols><nc:protocols><nc:na'
+# 'me>bgp</nc:name><nc:except/></nc:protocols><nc:system-services><nc:name>all</nc:name></nc:system-services><nc:system-services><n'
+# 'c:name>dhcp</nc:name><nc:except/></nc:system-services></nc:host-inbound-traffic><nc:interfaces><nc:name>ge-0/0/1.0</nc:name></nc'
+# ':interfaces><nc:interfaces><nc:name>ge-0/0/2.0</nc:name></nc:interfaces><nc:screen>test_screen</nc:screen></nc:management></nc:f'
+# 'unctional-zone><nc:security-zone><nc:name>test_sec_zone1</nc:name><nc:address-book><nc:address><nc:name>test_adr1</nc:name><nc:i'
+# 'p-prefix>10.0.0.0/24</nc:ip-prefix><nc:description>test desc</nc:description></nc:address><nc:address><nc:name>test_adr2</nc:nam'
+# 'e><nc:dns-name><nc:name>1.1.1.1</nc:name><nc:ipv6-only/></nc:dns-name></nc:address><nc:address><nc:name>test_adr3</nc:name><nc:r'
+# 'ange-address><nc:name>10.2.0.1</nc:name><nc:to><nc:range-high>10.2.0.2</nc:range-high></nc:to></nc:range-address></nc:address><n'
+# 'c:address><nc:name>test_adr4</nc:name><nc:wildcard-address><nc:name>10.3.0.1/24</nc:name></nc:wildcard-address></nc:address><nc:'
+# 'address><nc:name>test_adr5</nc:name><nc:ip-prefix>10.1.0.0/24</nc:ip-prefix><nc:description>test desc</nc:description></nc:addre'
+# 'ss><nc:address-set><nc:name>test_adrset1</nc:name><nc:address><nc:name>test_adr1</nc:name></nc:address><nc:address><nc:name>test'
+# '_adr2</nc:name></nc:address></nc:address-set><nc:address-set><nc:name>test_adrset2</nc:name><nc:address><nc:name>test_adr3</nc:n'
+# 'ame></nc:address><nc:address><nc:name>test_adr4</nc:name></nc:address></nc:address-set><nc:address-set><nc:name>test_adrset3</nc'
+# ':name><nc:address><nc:name>test_adr5</nc:name></nc:address><nc:address-set><nc:name>test_adrset1</nc:name></nc:address-set><nc:a'
+# 'ddress-set><nc:name>test_adrset2</nc:name></nc:address-set><nc:description>test description</nc:description></nc:address-set></n'
+# 'c:address-book><nc:advance-policy-based-routing-profile><nc:profile>test_profile</nc:profile></nc:advance-policy-based-routing-p'
+# 'rofile><nc:application-tracking/><nc:description>test description</nc:description><nc:enable-reverse-reroute/><nc:host-inbound-t'
+# 'raffic><nc:protocols><nc:name>all</nc:name></nc:protocols><nc:protocols><nc:name>bgp</nc:name><nc:except/></nc:protocols><nc:sys'
+# 'tem-services><nc:name>all</nc:name></nc:system-services><nc:system-services><nc:name>dhcp</nc:name><nc:except/></nc:system-servi'
+# 'ces></nc:host-inbound-traffic><nc:interfaces><nc:name>ge-0/0/3.0</nc:name></nc:interfaces><nc:interfaces><nc:name>ge-0/0/4.0</nc'
+# ':name></nc:interfaces><nc:screen>test_screen</nc:screen><nc:source-identity-log/><nc:tcp-rst/></nc:security-zone></nc:zones></nc'
+# ':security>'
+
+# After state
+# -----------
+#
+# vagrant@vsrx# show system ntp
+# functional-zone management {
+# interfaces {
+# ge-0/0/1.0;
+# ge-0/0/2.0;
+# }
+# screen test_screen;
+# host-inbound-traffic {
+# system-services {
+# all;
+# dhcp {
+# except;
+# }
+# }
+# protocols {
+# all;
+# bgp {
+# except;
+# }
+# }
+# }
+# description "test description";
+# }
+# security-zone test_sec_zone1 {
+# description "test description";
+# tcp-rst;
+# address-book {
+# address test_adr1 {
+# description "test desc";
+# 10.0.0.0/24;
+# }
+# address test_adr2 {
+# dns-name 1.1.1.1 {
+# ipv6-only;
+# }
+# }
+# address test_adr3 {
+# range-address 10.2.0.1 {
+# to {
+# 10.2.0.2;
+# }
+# }
+# }
+# address test_adr4 {
+# wildcard-address 10.3.0.1/24;
+# }
+# address test_adr5 {
+# description "test desc";
+# 10.1.0.0/24;
+# }
+# address-set test_adrset1 {
+# address test_adr1;
+# address test_adr2;
+# }
+# address-set test_adrset2 {
+# address test_adr3;
+# address test_adr4;
+# }
+# address-set test_adrset3 {
+# description "test description";
+# address test_adr5;
+# address-set test_adrset1;
+# address-set test_adrset2;
+# }
+# }
+# screen test_screen;
+# host-inbound-traffic {
+# system-services {
+# all;
+# dhcp {
+# except;
+# }
+# }
+# protocols {
+# all;
+# bgp {
+# except;
+# }
+# }
+# }
+# interfaces {
+# ge-0/0/3.0;
+# ge-0/0/4.0;
+# }
+# application-tracking;
+# source-identity-log;
+# advance-policy-based-routing-profile {
+# test_profile;
+# }
+# enable-reverse-reroute;
+# }
+#
+#
+# Using Replaced
+# Before state
+# ------------
+#
+# vagrant@vsrx# show security zones
+# functional-zone management {
+# interfaces {
+# ge-0/0/1.0;
+# ge-0/0/2.0;
+# }
+# screen test_screen;
+# host-inbound-traffic {
+# system-services {
+# all;
+# dhcp {
+# except;
+# }
+# }
+# protocols {
+# all;
+# bgp {
+# except;
+# }
+# }
+# }
+# description "test description";
+# }
+# security-zone test_sec_zone1 {
+# description "test description";
+# tcp-rst;
+# address-book {
+# address test_adr1 {
+# description "test desc";
+# 10.0.0.0/24;
+# }
+# address test_adr2 {
+# dns-name 1.1.1.1 {
+# ipv6-only;
+# }
+# }
+# address test_adr3 {
+# range-address 10.2.0.1 {
+# to {
+# 10.2.0.2;
+# }
+# }
+# }
+# address test_adr4 {
+# wildcard-address 10.3.0.1/24;
+# }
+# address test_adr5 {
+# description "test desc";
+# 10.1.0.0/24;
+# }
+# address-set test_adrset1 {
+# address test_adr1;
+# address test_adr2;
+# }
+# address-set test_adrset2 {
+# address test_adr3;
+# address test_adr4;
+# }
+# address-set test_adrset3 {
+# description "test description";
+# address test_adr5;
+# address-set test_adrset1;
+# address-set test_adrset2;
+# }
+# }
+# screen test_screen;
+# host-inbound-traffic {
+# system-services {
+# all;
+# dhcp {
+# except;
+# }
+# }
+# protocols {
+# all;
+# bgp {
+# except;
+# }
+# }
+# }
+# interfaces {
+# ge-0/0/3.0;
+# ge-0/0/4.0;
+# }
+# application-tracking;
+# source-identity-log;
+# advance-policy-based-routing-profile {
+# test_profile;
+# }
+# enable-reverse-reroute;
+# }
+#
+#
+
+- name: Replaced running security zones configuration with provided configuration
+ junipernetworks.junos.junos_security_zones:
+ config:
+ functional_zone_management:
+ description: test description
+ host_inbound_traffic:
+ protocols:
+ - name: all
+ - name: bgp
+ except: true
+ system_services:
+ - name: all
+ - except: true
+ name: dhcp
+ interfaces:
+ - ge-0/0/1.0
+ - ge-0/0/2.0
+ screen: test_screen
+ state: replaced
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "functional_zone_management": {
+# "description": "test description",
+# "host_inbound_traffic": {
+# "protocols": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "bgp"
+# }
+# ],
+# "system_services": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "dhcp"
+# }
+# ]
+# },
+# "interfaces": [
+# "ge-0/0/1.0",
+# "ge-0/0/2.0"
+# ],
+# "screen": "test_screen"
+# }
+# },
+# "before": {
+# "functional_zone_management": {
+# "description": "test description",
+# "host_inbound_traffic": {
+# "protocols": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "bgp"
+# }
+# ],
+# "system_services": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "dhcp"
+# }
+# ]
+# },
+# "interfaces": [
+# "ge-0/0/1.0",
+# "ge-0/0/2.0"
+# ],
+# "screen": "test_screen"
+# },
+# "security_zones": [
+# {
+# "address_book": {
+# "address_sets": [
+# {
+# "addresses": [
+# "test_adr1",
+# "test_adr2"
+# ],
+# "name": "test_adrset1"
+# },
+# {
+# "addresses": [
+# "test_adr3",
+# "test_adr4"
+# ],
+# "name": "test_adrset2"
+# },
+# {
+# "address_sets": [
+# "test_adrset1",
+# "test_adrset2"
+# ],
+# "addresses": [
+# "test_adr5"
+# ],
+# "description": "test description",
+# "name": "test_adrset3"
+# }
+# ],
+# "addresses": [
+# {
+# "description": "test desc",
+# "ip_prefix": "10.0.0.0/24",
+# "name": "test_adr1"
+# },
+# {
+# "dns_name": {
+# "ipv6_only": true,
+# "name": "1.1.1.1"
+# },
+# "name": "test_adr2"
+# },
+# {
+# "name": "test_adr3",
+# "range_address": {
+# "from": "10.2.0.1",
+# "to": "10.2.0.2"
+# }
+# },
+# {
+# "name": "test_adr4",
+# "wildcard_address": "10.3.0.1/24"
+# },
+# {
+# "description": "test desc",
+# "ip_prefix": "10.1.0.0/24",
+# "name": "test_adr5"
+# }
+# ]
+# },
+# "advance_policy_based_routing_profile": "test_profile",
+# "application_tracking": true,
+# "description": "test description",
+# "enable_reverse_reroute": true,
+# "host_inbound_traffic": {
+# "protocols": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "bgp"
+# }
+# ],
+# "system_services": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "dhcp"
+# }
+# ]
+# },
+# "interfaces": [
+# "ge-0/0/3.0",
+# "ge-0/0/4.0"
+# ],
+# "name": "test_sec_zone1",
+# "screen": "test_screen",
+# "source_identity_log": true,
+# "tcp_rst": true
+# }
+# ]
+# },
+# "changed": true,
+# "commands":
+# '<nc:security xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><nc:zones delete=\"delete\"/><nc:zones><nc:functional-zone><nc'
+# ':management><nc:description>test description</nc:description><nc:host-inbound-traffic><nc:protocols><nc:name>all</nc:name></nc:p'
+# 'rotocols><nc:protocols><nc:name>bgp</nc:name><nc:except/></nc:protocols><nc:system-services><nc:name>all</nc:name></nc:system-se'
+# 'rvices><nc:system-services><nc:name>dhcp</nc:name><nc:except/></nc:system-services></nc:host-inbound-traffic><nc:interfaces><nc:'
+# 'name>ge-0/0/1.0</nc:name></nc:interfaces><nc:interfaces><nc:name>ge-0/0/2.0</nc:name></nc:interfaces><nc:screen>test_screen</nc:'
+# 'screen></nc:management></nc:functional-zone></nc:zones></nc:security>'
+#
+#
+# After state
+# -----------
+#
+# vagrant@vsrx# show system ntp
+# functional-zone management {
+# interfaces {
+# ge-0/0/1.0;
+# ge-0/0/2.0;
+# }
+# screen test_screen;
+# host-inbound-traffic {
+# system-services {
+# all;
+# dhcp {
+# except;
+# }
+# }
+# protocols {
+# all;
+# bgp {
+# except;
+# }
+# }
+# }
+# description "test description";
+# }
+#
+#
+# Using overridden
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show security zones
+# functional-zone management {
+# interfaces {
+# ge-0/0/1.0;
+# ge-0/0/2.0;
+# }
+# screen test_screen;
+# host-inbound-traffic {
+# system-services {
+# all;
+# dhcp {
+# except;
+# }
+# }
+# protocols {
+# all;
+# bgp {
+# except;
+# }
+# }
+# }
+# description "test description";
+# }
+# security-zone test_sec_zone1 {
+# description "test description";
+# tcp-rst;
+# address-book {
+# address test_adr1 {
+# description "test desc";
+# 10.0.0.0/24;
+# }
+# address test_adr2 {
+# dns-name 1.1.1.1 {
+# ipv6-only;
+# }
+# }
+# address test_adr3 {
+# range-address 10.2.0.1 {
+# to {
+# 10.2.0.2;
+# }
+# }
+# }
+# address test_adr4 {
+# wildcard-address 10.3.0.1/24;
+# }
+# address test_adr5 {
+# description "test desc";
+# 10.1.0.0/24;
+# }
+# address-set test_adrset1 {
+# address test_adr1;
+# address test_adr2;
+# }
+# address-set test_adrset2 {
+# address test_adr3;
+# address test_adr4;
+# }
+# address-set test_adrset3 {
+# description "test description";
+# address test_adr5;
+# address-set test_adrset1;
+# address-set test_adrset2;
+# }
+# }
+# screen test_screen;
+# host-inbound-traffic {
+# system-services {
+# all;
+# dhcp {
+# except;
+# }
+# }
+# protocols {
+# all;
+# bgp {
+# except;
+# }
+# }
+# }
+# interfaces {
+# ge-0/0/3.0;
+# ge-0/0/4.0;
+# }
+# application-tracking;
+# source-identity-log;
+# advance-policy-based-routing-profile {
+# test_profile;
+# }
+# enable-reverse-reroute;
+# }
+#
+#
+
+- name: Override running security zones configuration with provided configuration
+ junipernetworks.junos.junos_security_zones:
+ config:
+ functional_zone_management:
+ description: test description
+ host_inbound_traffic:
+ protocols:
+ - name: all
+ - name: bgp
+ except: true
+ system_services:
+ - name: all
+ - except: true
+ name: dhcp
+ interfaces:
+ - ge-0/0/1.0
+ - ge-0/0/2.0
+ screen: test_screen
+ state: overridden
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "functional_zone_management": {
+# "description": "test description",
+# "host_inbound_traffic": {
+# "protocols": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "bgp"
+# }
+# ],
+# "system_services": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "dhcp"
+# }
+# ]
+# },
+# "interfaces": [
+# "ge-0/0/1.0",
+# "ge-0/0/2.0"
+# ],
+# "screen": "test_screen"
+# }
+# },
+# "before": {
+# "functional_zone_management": {
+# "description": "test description",
+# "host_inbound_traffic": {
+# "protocols": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "bgp"
+# }
+# ],
+# "system_services": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "dhcp"
+# }
+# ]
+# },
+# "interfaces": [
+# "ge-0/0/1.0",
+# "ge-0/0/2.0"
+# ],
+# "screen": "test_screen"
+# },
+# "security_zones": [
+# {
+# "address_book": {
+# "address_sets": [
+# {
+# "addresses": [
+# "test_adr1",
+# "test_adr2"
+# ],
+# "name": "test_adrset1"
+# },
+# {
+# "addresses": [
+# "test_adr3",
+# "test_adr4"
+# ],
+# "name": "test_adrset2"
+# },
+# {
+# "address_sets": [
+# "test_adrset1",
+# "test_adrset2"
+# ],
+# "addresses": [
+# "test_adr5"
+# ],
+# "description": "test description",
+# "name": "test_adrset3"
+# }
+# ],
+# "addresses": [
+# {
+# "description": "test desc",
+# "ip_prefix": "10.0.0.0/24",
+# "name": "test_adr1"
+# },
+# {
+# "dns_name": {
+# "ipv6_only": true,
+# "name": "1.1.1.1"
+# },
+# "name": "test_adr2"
+# },
+# {
+# "name": "test_adr3",
+# "range_address": {
+# "from": "10.2.0.1",
+# "to": "10.2.0.2"
+# }
+# },
+# {
+# "name": "test_adr4",
+# "wildcard_address": "10.3.0.1/24"
+# },
+# {
+# "description": "test desc",
+# "ip_prefix": "10.1.0.0/24",
+# "name": "test_adr5"
+# }
+# ]
+# },
+# "advance_policy_based_routing_profile": "test_profile",
+# "application_tracking": true,
+# "description": "test description",
+# "enable_reverse_reroute": true,
+# "host_inbound_traffic": {
+# "protocols": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "bgp"
+# }
+# ],
+# "system_services": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "dhcp"
+# }
+# ]
+# },
+# "interfaces": [
+# "ge-0/0/3.0",
+# "ge-0/0/4.0"
+# ],
+# "name": "test_sec_zone1",
+# "screen": "test_screen",
+# "source_identity_log": true,
+# "tcp_rst": true
+# }
+# ]
+# },
+# "changed": true,
+# "commands":
+# '<nc:security xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><nc:zones delete=\"delete\"/><nc:zones><nc:functional-zone><nc'
+# ':management><nc:description>test description</nc:description><nc:host-inbound-traffic><nc:protocols><nc:name>all</nc:name></nc:p'
+# 'rotocols><nc:protocols><nc:name>bgp</nc:name><nc:except/></nc:protocols><nc:system-services><nc:name>all</nc:name></nc:system-se'
+# 'rvices><nc:system-services><nc:name>dhcp</nc:name><nc:except/></nc:system-services></nc:host-inbound-traffic><nc:interfaces><nc:'
+# 'name>ge-0/0/1.0</nc:name></nc:interfaces><nc:interfaces><nc:name>ge-0/0/2.0</nc:name></nc:interfaces><nc:screen>test_screen</nc:'
+# 'screen></nc:management></nc:functional-zone></nc:zones></nc:security>'
+#
+#
+# After state
+# -----------
+#
+# vagrant@vsrx# show system ntp
+# functional-zone management {
+# interfaces {
+# ge-0/0/1.0;
+# ge-0/0/2.0;
+# }
+# screen test_screen;
+# host-inbound-traffic {
+# system-services {
+# all;
+# dhcp {
+# except;
+# }
+# }
+# protocols {
+# all;
+# bgp {
+# except;
+# }
+# }
+# }
+# description "test description";
+# }
+#
+#
+# Using deleted
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show security zones
+# functional-zone management {
+# interfaces {
+# ge-0/0/1.0;
+# ge-0/0/2.0;
+# }
+# screen test_screen;
+# host-inbound-traffic {
+# system-services {
+# all;
+# dhcp {
+# except;
+# }
+# }
+# protocols {
+# all;
+# bgp {
+# except;
+# }
+# }
+# }
+# description "test description";
+# }
+#
+#
+- name: Delete running security zones configuration
+ junipernetworks.junos.junos_security_zones:
+ config:
+ state: deleted
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {},
+# "before": {
+# "functional_zone_management": {
+# "description": "test description",
+# "host_inbound_traffic": {
+# "protocols": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "bgp"
+# }
+# ],
+# "system_services": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "dhcp"
+# }
+# ]
+# },
+# "interfaces": [
+# "ge-0/0/1.0",
+# "ge-0/0/2.0"
+# ],
+# "screen": "test_screen"
+# }
+# },
+# "changed": true,
+# "commands":
+# "<nc:security xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:zones delete=\"delete\"/></nc:security>"
+#
+#
+# After state
+# -----------
+#
+# vagrant@vsrx# show security zones
+#
+# [edit]
+# Using gathered
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show system ntp
+# functional-zone management {
+# interfaces {
+# ge-0/0/1.0;
+# ge-0/0/2.0;
+# }
+# screen test_screen;
+# host-inbound-traffic {
+# system-services {
+# all;
+# dhcp {
+# except;
+# }
+# }
+# protocols {
+# all;
+# bgp {
+# except;
+# }
+# }
+# }
+# description "test description";
+# }
+# security-zone test_sec_zone1 {
+# description "test description";
+# tcp-rst;
+# address-book {
+# address test_adr1 {
+# description "test desc";
+# 10.0.0.0/24;
+# }
+# address test_adr2 {
+# dns-name 1.1.1.1 {
+# ipv6-only;
+# }
+# }
+# address test_adr3 {
+# range-address 10.2.0.1 {
+# to {
+# 10.2.0.2;
+# }
+# }
+# }
+# address test_adr4 {
+# wildcard-address 10.3.0.1/24;
+# }
+# address test_adr5 {
+# description "test desc";
+# 10.1.0.0/24;
+# }
+# address-set test_adrset1 {
+# address test_adr1;
+# address test_adr2;
+# }
+# address-set test_adrset2 {
+# address test_adr3;
+# address test_adr4;
+# }
+# address-set test_adrset3 {
+# description "test description";
+# address test_adr5;
+# address-set test_adrset1;
+# address-set test_adrset2;
+# }
+# }
+# screen test_screen;
+# host-inbound-traffic {
+# system-services {
+# all;
+# dhcp {
+# except;
+# }
+# }
+# protocols {
+# all;
+# bgp {
+# except;
+# }
+# }
+# }
+# interfaces {
+# ge-0/0/3.0;
+# ge-0/0/4.0;
+# }
+# application-tracking;
+# source-identity-log;
+# advance-policy-based-routing-profile {
+# test_profile;
+# }
+# enable-reverse-reroute;
+# }
+- name: Gather running security zones configuration
+ junipernetworks.junos.junos_security_zones:
+ state: gathered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "gathered": {
+# "functional_zone_management": {
+# "description": "test description",
+# "host_inbound_traffic": {
+# "protocols": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "bgp"
+# }
+# ],
+# "system_services": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "dhcp"
+# }
+# ]
+# },
+# "interfaces": [
+# "ge-0/0/1.0",
+# "ge-0/0/2.0"
+# ],
+# "screen": "test_screen"
+# },
+# "security_zones": [
+# {
+# "address_book": {
+# "address_sets": [
+# {
+# "addresses": [
+# "test_adr1",
+# "test_adr2"
+# ],
+# "name": "test_adrset1"
+# },
+# {
+# "addresses": [
+# "test_adr3",
+# "test_adr4"
+# ],
+# "name": "test_adrset2"
+# },
+# {
+# "address_sets": [
+# "test_adrset1",
+# "test_adrset2"
+# ],
+# "addresses": [
+# "test_adr5"
+# ],
+# "description": "test description",
+# "name": "test_adrset3"
+# }
+# ],
+# "addresses": [
+# {
+# "description": "test desc",
+# "ip_prefix": "10.0.0.0/24",
+# "name": "test_adr1"
+# },
+# {
+# "dns_name": {
+# "ipv6_only": true,
+# "name": "1.1.1.1"
+# },
+# "name": "test_adr2"
+# },
+# {
+# "name": "test_adr3",
+# "range_address": {
+# "from": "10.2.0.1",
+# "to": "10.2.0.2"
+# }
+# },
+# {
+# "name": "test_adr4",
+# "wildcard_address": "10.3.0.1/24"
+# },
+# {
+# "description": "test desc",
+# "ip_prefix": "10.1.0.0/24",
+# "name": "test_adr5"
+# }
+# ]
+# },
+# "advance_policy_based_routing_profile": "test_profile",
+# "application_tracking": true,
+# "description": "test description",
+# "enable_reverse_reroute": true,
+# "host_inbound_traffic": {
+# "protocols": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "bgp"
+# }
+# ],
+# "system_services": [
+# {
+# "name": "all"
+# },
+# {
+# "except": true,
+# "name": "dhcp"
+# }
+# ]
+# },
+# "interfaces": [
+# "ge-0/0/3.0",
+# "ge-0/0/4.0"
+# ],
+# "name": "test_sec_zone1",
+# "screen": "test_screen",
+# "source_identity_log": true,
+# "tcp_rst": true
+# }
+# ]
+# }
+# "changed": false,
+#
+#
+# Using rendered
+#
+# Before state
+# ------------
+#
+- name: Render xml for provided facts.
+ junipernetworks.junos.junos_security_zones:
+ config:
+ functional_zone_management:
+ description: test description
+ host_inbound_traffic:
+ protocols:
+ - name: all
+ - name: bgp
+ except: true
+ system_services:
+ - name: all
+ - except: true
+ name: dhcp
+ interfaces:
+ - ge-0/0/1.0
+ - ge-0/0/2.0
+ screen: test_screen
+ security_zones:
+ - address_book:
+ address_sets:
+ - addresses:
+ - test_adr1
+ - test_adr2
+ name: test_adrset1
+ - addresses:
+ - test_adr3
+ - test_adr4
+ name: test_adrset2
+ - address_sets:
+ - test_adrset1
+ - test_adrset2
+ addresses:
+ - test_adr5
+ description: test description
+ name: test_adrset3
+ addresses:
+ - description: test desc
+ ip_prefix: 10.0.0.0/24
+ name: test_adr1
+ - dns_name:
+ ipv6_only: true
+ name: 1.1.1.1
+ name: test_adr2
+ - name: test_adr3
+ range_address:
+ from: 10.2.0.1
+ to: 10.2.0.2
+ - name: test_adr4
+ wildcard_address: 10.3.0.1/24
+ - description: test desc
+ ip_prefix: 10.1.0.0/24
+ name: test_adr5
+ advance_policy_based_routing_profile: test_profile
+ application_tracking: true
+ description: test description
+ enable_reverse_reroute: true
+ host_inbound_traffic:
+ protocols:
+ - name: all
+ - except: true
+ name: bgp
+ system_services:
+ - name: all
+ - except: true
+ name: dhcp
+ interfaces:
+ - ge-0/0/3.0
+ - ge-0/0/4.0
+ name: test_sec_zone1
+ screen: test_screen
+ source_identity_log: true
+ tcp_rst: true
+ state: rendered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "rendered":
+# '<nc:security xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><nc:zones><nc:functional-zone><nc:management><nc:description>t'
+# 'est description</nc:description><nc:host-inbound-traffic><nc:protocols><nc:name>all</nc:name></nc:protocols><nc:protocols><nc:na'
+# 'me>bgp</nc:name><nc:except/></nc:protocols><nc:system-services><nc:name>all</nc:name></nc:system-services><nc:system-services><n'
+# 'c:name>dhcp</nc:name><nc:except/></nc:system-services></nc:host-inbound-traffic><nc:interfaces><nc:name>ge-0/0/1.0</nc:name></nc'
+# ':interfaces><nc:interfaces><nc:name>ge-0/0/2.0</nc:name></nc:interfaces><nc:screen>test_screen</nc:screen></nc:management></nc:f'
+# 'unctional-zone><nc:security-zone><nc:name>test_sec_zone1</nc:name><nc:address-book><nc:address><nc:name>test_adr1</nc:name><nc:i'
+# 'p-prefix>10.0.0.0/24</nc:ip-prefix><nc:description>test desc</nc:description></nc:address><nc:address><nc:name>test_adr2</nc:nam'
+# 'e><nc:dns-name><nc:name>1.1.1.1</nc:name><nc:ipv6-only/></nc:dns-name></nc:address><nc:address><nc:name>test_adr3</nc:name><nc:r'
+# 'ange-address><nc:name>10.2.0.1</nc:name><nc:to><nc:range-high>10.2.0.2</nc:range-high></nc:to></nc:range-address></nc:address><n'
+# 'c:address><nc:name>test_adr4</nc:name><nc:wildcard-address><nc:name>10.3.0.1/24</nc:name></nc:wildcard-address></nc:address><nc:'
+# 'address><nc:name>test_adr5</nc:name><nc:ip-prefix>10.1.0.0/24</nc:ip-prefix><nc:description>test desc</nc:description></nc:addre'
+# 'ss><nc:address-set><nc:name>test_adrset1</nc:name><nc:address><nc:name>test_adr1</nc:name></nc:address><nc:address><nc:name>test'
+# '_adr2</nc:name></nc:address></nc:address-set><nc:address-set><nc:name>test_adrset2</nc:name><nc:address><nc:name>test_adr3</nc:n'
+# 'ame></nc:address><nc:address><nc:name>test_adr4</nc:name></nc:address></nc:address-set><nc:address-set><nc:name>test_adrset3</nc'
+# ':name><nc:address><nc:name>test_adr5</nc:name></nc:address><nc:address-set><nc:name>test_adrset1</nc:name></nc:address-set><nc:a'
+# 'ddress-set><nc:name>test_adrset2</nc:name></nc:address-set><nc:description>test description</nc:description></nc:address-set></n'
+# 'c:address-book><nc:advance-policy-based-routing-profile><nc:profile>test_profile</nc:profile></nc:advance-policy-based-routing-p'
+# 'rofile><nc:application-tracking/><nc:description>test description</nc:description><nc:enable-reverse-reroute/><nc:host-inbound-t'
+# 'raffic><nc:protocols><nc:name>all</nc:name></nc:protocols><nc:protocols><nc:name>bgp</nc:name><nc:except/></nc:protocols><nc:sys'
+# 'tem-services><nc:name>all</nc:name></nc:system-services><nc:system-services><nc:name>dhcp</nc:name><nc:except/></nc:system-servi'
+# 'ces></nc:host-inbound-traffic><nc:interfaces><nc:name>ge-0/0/3.0</nc:name></nc:interfaces><nc:interfaces><nc:name>ge-0/0/4.0</nc'
+# ':name></nc:interfaces><nc:screen>test_screen</nc:screen><nc:source-identity-log/><nc:tcp-rst/></nc:security-zone></nc:zones></nc'
+# ':security>'
+#
+# Using parsed
+# parsed.cfg
+# ------------
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <version>18.4R1-S2.4</version>
+# <security>
+# <zones>
+# <functional-zone>
+# <management>
+# <description>test description</description>
+# <host-inbound-traffic>
+# <protocols>
+# <name>all</name>
+# </protocols>
+# <protocols>
+# <name>bgp</name>
+# <except />
+# </protocols>
+# <system-services>
+# <name>all</name>
+# </system-services>
+# <system-services>
+# <name>dhcp</name>
+# <except />
+# </system-services>
+# </host-inbound-traffic>
+# <interfaces>
+# <name>ge-0/0/1.0</name>
+# </interfaces>
+# <interfaces>
+# <name>ge-0/0/2.0</name>
+# </interfaces>
+# <screen>test_screen</screen>
+# </management>
+# </functional-zone>
+# <security-zone>
+# <name>test_sec_zone1</name>
+# <address-book>
+# <address>
+# <name>test_adr1</name>
+# <ip-prefix>10.0.0.0/24</ip-prefix>
+# <description>test desc</description>
+# </address>
+# <address>
+# <name>test_adr2</name>
+# <dns-name>
+# <name>1.1.1.1</name>
+# <ipv6-only />
+# </dns-name>
+# </address>
+# <address>
+# <name>test_adr3</name>
+# <range-address>
+# <name>10.2.0.1</name>
+# <to>
+# <range-high>10.2.0.2</range-high>
+# </to>
+# </range-address>
+# </address>
+# <address>
+# <name>test_adr4</name>
+# <wildcard-address>
+# <name>10.3.0.1/24</name>
+# </wildcard-address>
+# </address>
+# <address>
+# <name>test_adr5</name>
+# <ip-prefix>10.1.0.0/24</ip-prefix>
+# <description>test desc</description>
+# </address>
+# <address-set>
+# <name>test_adrset1</name>
+# <address>
+# <name>test_adr1</name>
+# </address>
+# <address>
+# <name>test_adr2</name>
+# </address>
+# </address-set>
+# <address-set>
+# <name>test_adrset2</name>
+# <address>
+# <name>test_adr3</name>
+# </address>
+# <address>
+# <name>test_adr4</name>
+# </address>
+# </address-set>
+# <address-set>
+# <name>test_adrset3</name>
+# <address>
+# <name>test_adr5</name>
+# </address>
+# <address-set>
+# <name>test_adrset1</name>
+# </address-set>
+# <address-set>
+# <name>test_adrset2</name>
+# </address-set>
+# <description>test description</description>
+# </address-set>
+# </address-book>
+# <advance-policy-based-routing-profile>
+# <profile>test_profile</profile>
+# </advance-policy-based-routing-profile>
+# <application-tracking />
+# <description>test description</description>
+# <enable-reverse-reroute />
+# <host-inbound-traffic>
+# <protocols>
+# <name>all</name>
+# </protocols>
+# <protocols>
+# <name>bgp</name>
+# <except />
+# </protocols>
+# <system-services>
+# <name>all</name>
+# </system-services>
+# <system-services>
+# <name>dhcp</name>
+# <except />
+# </system-services>
+# </host-inbound-traffic>
+# <interfaces>
+# <name>ge-0/0/3.0</name>
+# </interfaces>
+# <interfaces>
+# <name>ge-0/0/4.0</name>
+# </interfaces>
+# <screen>test_screen</screen>
+# <source-identity-log />
+# <tcp-rst />
+# </security-zone>
+# </zones>
+# </security>
+# </configuration>
+# </rpc-reply>
+#
+- name: Parse security zones running config
+ junipernetworks.junos.junos_security_zones:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "parsed": {
+# "functional_zone_management": {
+# "description": "test description 2",
+# "host_inbound_traffic": {
+# "protocols": [{"name": "all"}, {"except": True, "name": "bgp"}, {"except": True, "name": "bfd"}],
+# "system_services": [{"name": "all"}, {"except": True, "name": "dhcp"}, {"except": True, "name": "dhcpv6"}],
+# },
+# "interfaces": ["ge-0/0/1.0", "ge-0/0/2.0"],
+# "screen": "test_screen",
+# },
+# "security_zones": [
+# {
+# "address_book": {
+# "address_sets": [
+# {"addresses": ["test_adr1", "test_adr2"], "name": "test_adrset1"},
+# {"addresses": ["test_adr3", "test_adr4"], "name": "test_adrset2"},
+# {
+# "address_sets": ["test_adrset1", "test_adrset2"],
+# "addresses": ["test_adr5"],
+# "description": "test description",
+# "name": "test_adrset3",
+# },
+# ],
+# "addresses": [
+# {"description": "test desc", "ip_prefix": "10.0.0.0/24", "name": "test_adr1"},
+# {"dns_name": {"ipv6_only": True, "name": "1.1.1.1"}, "name": "test_adr2"},
+# {"name": "test_adr3", "range_address": {"from": "10.2.0.1", "to": "10.2.0.2"}},
+# {"name": "test_adr4", "wildcard_address": "10.3.0.1/24"},
+# {"description": "test desc", "ip_prefix": "10.1.0.0/24", "name": "test_adr5"},
+# ],
+# },
+# "advance_policy_based_routing_profile": "test_profile",
+# "application_tracking": True,
+# "description": "test description",
+# "enable_reverse_reroute": True,
+# "host_inbound_traffic": {
+# "protocols": [{"name": "all"}, {"except": True, "name": "bgp"}],
+# "system_services": [{"name": "all"}, {"except": True, "name": "dhcp"}],
+# },
+# "interfaces": ["ge-0/0/3.0", "ge-0/0/4.0"],
+# "name": "test_sec_zone1",
+# "screen": "test_screen",
+# "source_identity_log": True,
+# "tcp_rst": True,
+# },
+# {"name": "test_sec_zone2", "source_identity_log": True, "tcp_rst": True},
+# ],
+# }
+#
+#
+"""
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when state is I(merged), I(replaced), I(overridden), I(deleted) or I(purged)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when state is I(merged), I(replaced), I(overridden), I(deleted) or I(purged)
+ type: list
+ sample:
+ - "<rpc-reply>
+ <configuration>
+ <security>
+ <policies>
+ <global>
+ <policy>
+ <name>test_glob_1</name>
+ <match>
+ <source-address>any-ipv6</source-address>
+ <destination-address>any-ipv6</destination-address>
+ <application>any</application>
+ </match>
+ <then>
+ <deny />
+ </then>
+ </policy>
+ </global>
+ </policies>
+ </security>
+ </configuration>
+ </rpc-reply>"
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when state is I(rendered)
+ type: dict
+ sample:
+ - "<rpc-reply>
+ <configuration>
+ <security>
+ <policies>
+ <global>
+ <policy>
+ <name>test_glob_1</name>
+ <match>
+ <source-address>any-ipv6</source-address>
+ <destination-address>any-ipv6</destination-address>
+ <application>any</application>
+ </match>
+ <then>
+ <deny />
+ </then>
+ </policy>
+ </global>
+ </policies>
+ </security>
+ </configuration>
+ </rpc-reply>"
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when state is I(gathered)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when state is I(parsed)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.security_zones.security_zones import (
+ Security_zonesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.security_zones.security_zones import (
+ Security_zones,
+)
+
+
+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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+
+ module = AnsibleModule(
+ argument_spec=Security_zonesArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+
+ result = Security_zones(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_snmp_server.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_snmp_server.py
new file mode 100644
index 000000000..491298327
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_snmp_server.py
@@ -0,0 +1,1584 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2021 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_snmp_server
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+ANSIBLE_METADATA = {
+ "metadata_version": "1.1",
+ "status": ["preview"],
+ "supported_by": "network",
+}
+
+DOCUMENTATION = """
+---
+module: junos_snmp_server
+version_added: 2.9.0
+short_description: Manage SNMP server configuration on Junos devices.
+description: This module manages SNMP server configuration on devices running Junos.
+author: Rohit Thakur (@rohitthakur2590)
+requirements:
+ - ncclient (>=v0.6.4)
+ - xmltodict (>=0.12.0)
+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,https://docs.ansible.com/ansible/latest/network/user_guide/platform_junos.html).
+ - Tested against JunOS v18.4R1
+options:
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show system snmp).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ config:
+ description: A dictionary of SNMP server configuration.
+ type: dict
+ suboptions:
+ arp:
+ description: Specify JVision arp setting.
+ type: dict
+ suboptions:
+ set:
+ description: Set JVision arp.
+ type: bool
+ host_name_resolution:
+ description: Enable host name resolution.
+ type: bool
+ client_lists:
+ description: Specify client list.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify client list name.
+ type: str
+ addresses:
+ description: Specify list of addresses/prefixes.
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description: Specify address or prefix.
+ type: str
+ restrict:
+ description: Deny access.
+ type: bool
+ routing_instance_access: &routing_instance_access
+ description: SNMP routing-instance options.
+ type: dict
+ suboptions:
+ set:
+ description: Set routing_instance_access.
+ type: bool
+ access_lists:
+ description: Allow/Deny SNMP access to routing-instances.
+ type: list
+ elements: str
+ communities:
+ description: Specify list of community string.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify name of the community.
+ type: str
+ authorization:
+ description: Specify Authorization type.
+ type: str
+ choices: ["read-only", "read-write"]
+ client_list_name: &client_list_name
+ description: Specify the name of client list or prefix list.
+ type: str
+ clients: &clients
+ description: Specify List of source address prefix ranges to accept.
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description: Specify address or prefix.
+ type: str
+ restrict:
+ description: Deny access.
+ type: bool
+ routing_instances: &routing_instances
+ description: Use routing-instance name for v1/v2c clients.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify routing-instances.
+ type: str
+ client_list_name: *client_list_name
+ clients: *clients
+ logical_system: &logical_system
+ description: Use logical-system name for v1/v2c clients.
+ type: list
+ elements: str
+ view:
+ description: Specify view name.
+ type: str
+ contact:
+ description: Specify contact information for administrator.
+ type: str
+ customization:
+ description: Customize SNMP behaviour based on knob.
+ type: dict
+ suboptions:
+ ether_stats_ifd_only:
+ description: To stop exposing IFLs as part of etherStatsTable.
+ type: bool
+ description:
+ description: System description.
+ type: str
+ engine_id:
+ description: Specify SNMPv3 engine ID
+ type: dict
+ suboptions:
+ local:
+ description: Local engine ID.
+ type: str
+ use_default_ip_address:
+ description: Use default IP address for the engine ID.
+ type: bool
+ use_mac_address:
+ description: Uses management interface MAC Address for the engine ID.
+ type: bool
+ filter_duplicates:
+ description: Filter requests with duplicate source address/port and request ID.
+ type: bool
+ filter_interfaces:
+ description: List of interfaces that needs to be filtered.
+ type: dict
+ suboptions:
+ set:
+ description: Set filter-interfaces.
+ type: bool
+ all_internal_interfaces:
+ description: Filter all internal interfaces.
+ type: bool
+ interfaces:
+ description: Specify filter specified interfaces.
+ type: list
+ elements: str
+ health_monitor:
+ description: Specify health monitoring configuration.
+ type: dict
+ suboptions:
+ set:
+ description: Set health-monitor configuration.
+ type: bool
+ falling_threshold:
+ description: Falling threshold applied to all monitored objects.
+ type: int
+ rising_threshold:
+ description: Rising threshold applied to all monitored objects.
+ type: int
+ idp:
+ description: IDP health monitor configuration.
+ type: bool
+ interval:
+ description: Interval between samples.
+ type: int
+ if_count_with_filter_interfaces:
+ description: Filter interfaces config for ifNumber and ipv6Interfaces.
+ type: bool
+ interfaces:
+ description: Restrict SNMP requests to interfaces.
+ type: list
+ elements: str
+ location:
+ description: Specify physical location of system.
+ type: str
+ logical_system_trap_filter:
+ description: Allow only logical-system specific traps.
+ type: bool
+ name:
+ description: System name override.
+ type: str
+ nonvolatile:
+ description: Configure the handling of nonvolatile SNMP Set requests.
+ type: dict
+ suboptions:
+ commit_delay:
+ description: Delay between affirmative SNMP Set reply and start of commit (seconds).
+ type: int
+ proxies:
+ description: SNMP proxy configuration.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify proxy name.
+ type: str
+ device_name:
+ description: Satellite/Proxied Device name or IP address.
+ type: str
+ logical_system: *logical_system
+ routing_instances: *routing_instances
+ version_v1:
+ description: Specify For v1 proxy configuration define snmp-community.
+ type: dict
+ suboptions:
+ no_default_comm_to_v3_config:
+ description: Specify No default snmp-community and v3 configuration.
+ type: bool
+ snmp_community:
+ description: Specify community name.
+ type: str
+ version_v2c:
+ description: For v2c proxy configuration define snmp-community.
+ type: dict
+ suboptions:
+ no_default_comm_to_v3_config:
+ description: Specify No default snmp-community and v3 configuration.
+ type: bool
+ snmp_community:
+ description: Specify community name.
+ type: str
+ version_v3:
+ description: For v3 proxy configuration define security-name.
+ type: dict
+ suboptions:
+ context:
+ description: pecify context name associated to this security-name.
+ type: bool
+ security_name:
+ description: Specify v3 security-name.
+ type: str
+ rmon:
+ description: Specify Remote Monitoring configuration.
+ type: dict
+ suboptions:
+ set:
+ description: Set Remote monitoring configuration.
+ type: bool
+ alarms:
+ description: RMON alarm entries.
+ type: list
+ elements: dict
+ suboptions:
+ id:
+ description: Specify alarm ID.
+ type: str
+ description:
+ description: General description of alarm (stored in alarmOwner).
+ type: str
+ falling_event_index:
+ description: Event triggered after falling threshold is crossed.
+ type: int
+ falling_threshold:
+ description: Specify falling-threshold.
+ type: int
+ falling_threshold_interval:
+ description: Interval between samples during falling-threshold test.
+ type: int
+ interval:
+ description: Interval between samples.
+ type: int
+ request_type:
+ description: Type of SNMP request to issue for alarm.
+ type: str
+ choices: ["get-next-request", "get-request", "walk-request"]
+ rising_event_index:
+ description: Event triggered after rising threshold is crossed.
+ type: int
+ rising_threshold:
+ description: The rising threshold.
+ type: int
+ sample_type:
+ description: Method of sampling the selected variable.
+ type: str
+ choices: ["absolute-value", "delta-value"]
+ startup_alarm:
+ description: The alarm that may be sent upon entry startup.
+ type: str
+ choices: ["falling-alarm", "rising-alarm", "rising-or-falling-alarm"]
+ syslog_subtag:
+ description: Tag to be added to syslog messages.
+ type: str
+ variable:
+ description: OID of MIB variable to be monitored.
+ type: str
+ events:
+ description: RMON event entries.
+ type: list
+ elements: dict
+ suboptions:
+ id:
+ description: Specify event ID.
+ type: int
+ community:
+ description: The community (trap group) for outgoing traps.
+ type: str
+ description:
+ description: General description of event.
+ type: str
+ type:
+ description: The type of notification for this event.
+ type: str
+ choices: ["log", "log-and-trap", "none", "snmptrap"]
+ subagent:
+ description: SNMP subagent configuration.
+ type: dict
+ suboptions:
+ tcp:
+ description: Allow SNMP subagent tcp connection.
+ type: dict
+ suboptions:
+ set:
+ description: Set SNMP subagent TCP.
+ type: bool
+ routing_instances_default:
+ description: Specify routing-instance name for tcp connection.
+ type: bool
+ traceoptions:
+ description: Configure trace options for SNMP.
+ type: dict
+ suboptions:
+ file:
+ description: Specify trace file options.
+ type: dict
+ suboptions:
+ match:
+ description: Regular expression for lines to be logged.
+ type: str
+ files:
+ description: Specify maximum number of trace files.
+ type: int
+ no_world_readable:
+ description: Don't allow any user to read the log file.
+ type: bool
+ world_readable:
+ description: Allow any user to read the log file.
+ type: bool
+ size:
+ description: Specify maximum trace file size.
+ type: int
+ flag:
+ description: Specify flag traceoptions.
+ type: dict
+ suboptions:
+ all:
+ description: Trace everything.
+ type: bool
+ general:
+ description: Trace general events.
+ type: bool
+ interface_stats:
+ description: Trace interface statistics (logical and physical).
+ type: bool
+ nonvolatile_sets:
+ description: Nonvolatile SNMP set request handling.
+ type: bool
+ pdu:
+ description: Dump SNMP request/response packets.
+ type: bool
+ protocol_timeouts:
+ description: Trace SNMP request timeouts.
+ type: bool
+ routing_socket:
+ description: Trace routing socket calls.
+ type: bool
+ subagent:
+ description: Trace master-agent interations with sub-agents.
+ type: bool
+ timer:
+ description: Trace internal timer events.
+ type: bool
+ varbind_error:
+ description: Trace varbind errors.
+ type: bool
+ memory_trace:
+ description: Memory tracing information.
+ type: dict
+ suboptions:
+ set:
+ description: set memory traceoptions.
+ type: bool
+ size:
+ description: Specify Memory size reserved for tracing.
+ type: int
+ no_remote_trace:
+ description: Disable remote tracing.
+ type: bool
+ trap_groups:
+ description: Specify SNMP trap options.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify trap group name.
+ type: str
+ categories:
+ description: Specify Trap categories.
+ type: dict
+ suboptions:
+ authentication:
+ description: Specify Authentication failures.
+ type: bool
+ chassis:
+ description: Specify Chassis or environment notifications.
+ type: bool
+ chassis_cluster:
+ description: Specify Clustering notifications.
+ type: bool
+ configuration:
+ description: Configuration notifications.
+ type: bool
+ dot3oam_events:
+ description: Specify 802.3ah notifications.
+ type: bool
+ link:
+ description: Link up-down transitions.
+ type: bool
+ otn_alarms:
+ description: OTN alarm trap subcategories.
+ type: dict
+ suboptions:
+ set:
+ description: Set otn_alarms.
+ type: bool
+ oc_lof:
+ description: Loss of frame alarm notifications.
+ type: bool
+ oc_lom:
+ description: Loss of multiframe alarm notification.
+ type: bool
+ oc_los:
+ description: Loss of signal alarm notification.
+ type: bool
+ odu_ais:
+ description: ODU Alarm indication signal alarm notification.
+ type: bool
+ odu_bbe_threshold:
+ description: ODU Background block error threshold alarm notification.
+ type: bool
+ odu_bdi:
+ description: ODU Backward defect indication alarm notification.
+ type: bool
+ odu_bdodu_es_threshold:
+ description: ODU Errored Second threshold alarm notification.
+ type: bool
+ odu_lck:
+ description: ODU Locked alarm notification.
+ type: bool
+ odu_oci:
+ description: ODU Open connection indicator alarm notifications.
+ type: bool
+ odu_rx_aps_change:
+ description: ODU Receive APS change notifications.
+ type: bool
+ odu_sd:
+ description: ODU Signal degrade alarm notifications.
+ type: bool
+ odu_ses_threshold:
+ description: ODU Severely Errored Second threshold alarm notification.
+ type: bool
+ odu_sf:
+ description: ODU Signal fail alarm notification.
+ type: bool
+ odu_ttim:
+ description: ODU Trace identification mismatch alarm notification.
+ type: bool
+ odu_uas_threshold:
+ description: ODU Unavailable Second threshold alarm notification.
+ type: bool
+ opu_ptm:
+ description: ODU Payload Type Mismatch alarm notification.
+ type: bool
+ otu_ais:
+ description: OTU Alarm indication signal alarm notification.
+ type: bool
+ otu_bbe_threshold:
+ description: OTU Background block error threshold alarm notification.
+ type: bool
+ otu_bdi:
+ description: OTU Backward defect indication alarm notification.
+ type: bool
+ otu_es_threshold:
+ description: OTU Errored Second threshold alarm notification.
+ type: bool
+ otu_fec_deg:
+ description: OTU Fec degraded errors alarm notification.
+ type: bool
+ otu_fec_exe:
+ description: OTU Fec excessive errors alarm notification.
+ type: bool
+ otu_iae:
+ description: OTU Incoming alignment error alarm notification.
+ type: bool
+ otu_sd:
+ description: OTU Signal degrade alarm notification.
+ type: bool
+ otu_ses_threshold:
+ description: OTU Severely Errored Second threshold alarm notification.
+ type: bool
+ otu_sf:
+ description: OTU Signal fail alarm notification.
+ type: bool
+ otu_ttim:
+ description: OTU Trace identification mismatch alarm notification.
+ type: bool
+ otu_uas_threshold:
+ description: OTU Unavailable Second threshold alarm notification.
+ type: bool
+ wavelength_lock:
+ description: Wavelength lock alarm notification.
+ type: bool
+ remote_operations:
+ description: Remote operations.
+ type: bool
+ rmon_alarm:
+ description: RMON rising and falling alarms.
+ type: bool
+ routing:
+ description: Routing protocol notifications.
+ type: bool
+ services:
+ description: Services notifications.
+ type: bool
+ startup:
+ description: System warm and cold starts.
+ type: bool
+ vrrp_events:
+ description: VRRP notifications.
+ type: bool
+ destination_port:
+ description: SNMP trap receiver port number
+ type: int
+ logical_system: *logical_system
+ routing_instance:
+ description: Routing instance for trap destination.
+ type: str
+ targets:
+ description: Targets for trap messages
+ type: list
+ elements: str
+ version:
+ description: SNMP version.
+ type: str
+ choices: ["all", "v1", "v2"]
+ trap_options:
+ description: SNMP trap options.
+ type: dict
+ suboptions:
+ set:
+ description: Set trap options.
+ type: bool
+ agent_address:
+ description: Agent address for v1 trap PDUs.
+ type: dict
+ suboptions:
+ outgoing_interface:
+ description: Use address on outgoing interfaces.
+ type: bool
+ context_oid:
+ description: Add context oid in varbind of all traps at the end.
+ type: bool
+ enterprise_oid:
+ description: Add snmpTrapEnterprise oid in varbind of all traps.
+ type: bool
+ logical_system: *logical_system
+ routing_instance:
+ description: Specify routing-instance.
+ type: str
+ source_address:
+ description: IPv4/IPv6 source address for trap PDUs.
+ type: dict
+ suboptions:
+ address:
+ description: Use specified address.
+ type: str
+ lowest_loopback:
+ description: Use lowest address on loopback interfaces.
+ type: bool
+ snmp_v3:
+ description: SNMPv3 configuration information.
+ type: dict
+ suboptions:
+ notify:
+ description: Used to select management targets for notifications as well as the type of notifications.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify notify name.
+ type: str
+ tag:
+ description: Notifications will be sent to all targets configured with this tag.
+ type: str
+ type:
+ description: Notification type.
+ type: str
+ notify_filter:
+ description: Filters to apply to SNMP notifications.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specify notify filter name.
+ type: str
+ oids:
+ description: OID to include/exclude from notify filter.
+ type: list
+ elements: dict
+ suboptions:
+ oid:
+ description: Specify OID.
+ type: str
+ exclude:
+ description: Exclude this OID from the notify filtered.
+ type: bool
+ include:
+ description: Include this OID in the notify filter.
+ type: bool
+ snmp_community:
+ description: SNMP community and view-based access control model configuration.
+ type: list
+ elements: dict
+ suboptions:
+ community_index:
+ description: Unique index value in this community table entry.
+ type: str
+ security_name:
+ description: Security name used when performing access control.
+ type: str
+ community_name:
+ description: SNMPv1/v2c community name (default is same as community-index).
+ type: str
+ context:
+ description: Context used when performing access control.
+ type: str
+ tag:
+ description: Tag identifier for set of targets allowed to use this community string.
+ type: str
+ target_addresses:
+ description: Identifies notification targets as well as allowed management stations.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: SNMP target address name.
+ type: str
+ address:
+ description: SNMP target address.
+ type: str
+ address_mask:
+ description: Mask range of addresses for community string access control.
+ type: str
+ logical_system:
+ description: Logical-system name for trap destination.
+ type: str
+ port:
+ description: SNMP target port number.
+ type: int
+ retry_count:
+ description: Maximum retry count for confirmed SNMP notifications.
+ type: int
+ routing_instance:
+ description: Routing instance for trap destination.
+ type: str
+ tag_list:
+ description: SNMP tag list used to select target addresses.
+ type: str
+ target_parameters:
+ description: SNMPv3 target parameter name in the target parameters table.
+ type: str
+ timeout:
+ description: Acknowledgment timeout for confirmed SNMP notifications (seconds).
+ type: int
+ target_parameters:
+ description: SNMPv3 target parameter name in the target parameters table.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: SNMPv3 target parameters name.
+ type: str
+ notify_filter:
+ description: Notify filter with filter name to apply to notifications.
+ type: str
+ parameters:
+ description: Parameters used when sending notifications.
+ type: dict
+ suboptions:
+ message_processing_model:
+ description: The message processing model to be used when generating SNMP notifications.
+ type: str
+ choices: ["v1", "v2c", "v3"]
+ security_level:
+ description: Security-level used when generating SNMP notifications.
+ type: str
+ choices: ["authentication", "none", "privacy"]
+ security_model:
+ description: Security-model used when generating SNMP notifications.
+ type: str
+ choices: ["usm", "v1", "v2c"]
+ security_name:
+ description: Security name used when generating SNMP notifications.
+ type: str
+ usm:
+ description: User-based security model (USM) information.
+ type: dict
+ suboptions:
+ local_engine:
+ description: Local engine user configuration.
+ type: dict
+ suboptions:
+ users: &users
+ description: SNMPv3 USM user information.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: User name.
+ type: str
+ authentication_md5:
+ description: Configure MD5 authentication.
+ type: dict
+ suboptions:
+ key:
+ description: Encrypted key used for user authentication.
+ type: str
+ password:
+ description: User's authentication password
+ type: str
+ authentication_none:
+ description: Set no authentication for the user.
+ type: bool
+ authentication_sha:
+ description: Configure SHA authentication.
+ type: dict
+ suboptions:
+ key:
+ description: Encrypted key used for user authentication.
+ type: str
+ password:
+ description: User's authentication password
+ type: str
+ privacy_3des:
+ description: Configure Triple DES privacy.
+ type: dict
+ suboptions:
+ key:
+ description: Encrypted key used for user privacy.
+ type: str
+ password:
+ description: User's privacy password
+ type: str
+ privacy_aes128:
+ description: Configure AES128 privacy.
+ type: dict
+ suboptions:
+ key:
+ description: Encrypted key used for user privacy.
+ type: str
+ password:
+ description: User's privacy password
+ type: str
+ privacy_des:
+ description: Configure DES privacy.
+ type: dict
+ suboptions:
+ key:
+ description: Encrypted key used for user privacy.
+ type: str
+ password:
+ description: User's privacy password
+ type: str
+ privacy_none:
+ description: Set no privacy for the user.
+ type: bool
+ remote_engine:
+ description: Remote engine user configuration.
+ type: list
+ elements: dict
+ suboptions:
+ id:
+ description: Remote engine id.
+ type: str
+ users: *users
+ views:
+ description: Define MIB views.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: MIB view name.
+ type: str
+ oids:
+ description: OID include/exclude list
+ type: list
+ elements: dict
+ suboptions:
+ oid:
+ description: OID to include or exclude from view.
+ type: str
+ exclude:
+ description: Exclude this OID from the view.
+ type: bool
+ include:
+ description: Include this OID from the view.
+ type: bool
+ state:
+ description:
+ - The state the configuration should be left in.
+ - Refer to examples for more details.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - deleted
+ - overridden
+ - parsed
+ - gathered
+ - rendered
+ default: merged
+"""
+EXAMPLES = """
+# Using merged
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show routing-instances
+# clv1 {
+# description clv1;
+# }
+# clv2 {
+# description clv2;
+# }
+- name: Merge provided SNMP configuration into running configuration.
+ junipernetworks.junos.junos_snmp_server:
+ config:
+ arp:
+ set: true
+ host_name_resolution: true
+ client_lists: # ATTR-----2
+ - name: cl1
+ addresses:
+ - address: "192.16.1.0/24"
+ - address: "192.16.2.0/24"
+ - address: "11.11.11.11"
+ restrict: true
+ - name: cl2
+ addresses:
+ - address: "192.16.4.0/24"
+ routing_instance_access: # ATTR-----3
+ set: true
+ access_lists:
+ - "clv1"
+ - "clv2"
+ state: merged
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "arp": {
+# "host_name_resolution": true
+# },
+# "client_lists": [
+# {
+# "addresses": [
+# {
+# "address": "192.16.1.0/24"
+# },
+# {
+# "address": "192.16.2.0/24"
+# },
+# {
+# "address": "11.11.11.11/32",
+# "restrict": true
+# }
+# ],
+# "name": "cl1"
+# },
+# {
+# "addresses": [
+# {
+# "address": "192.16.4.0/24"
+# }
+# ],
+# "name": "cl2"
+# }
+# ],
+# "routing_instance_access": {
+# "access_lists": [
+# "clv1",
+# "clv2"
+# ]
+# }
+# },
+# "before": {},
+# "changed": true,
+# "commands": [
+# "<nc:snmp xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:arp><nc:host-name-resolution/></nc:arp><nc:client-list><nc:name>cl1</nc:name>"
+# "<nc:client-address-list><nc:name>192.16.1.0/24</nc:name></nc:client-address-list>"
+# "<nc:client-address-list><nc:name>192.16.2.0/24</nc:name></nc:client-address-list><nc:client-address-list>"
+# "<nc:name>11.11.11.11</nc:name><nc:restrict/></nc:client-address-list></nc:client-list><nc:client-list>"
+# "<nc:name>cl2</nc:name><nc:client-address-list><nc:name>192.16.4.0/24</nc:name></nc:client-address-list>"
+# "</nc:client-list><nc:routing-instance-access><nc:access-list><nc:name>clv1</nc:name></nc:access-list>"
+# "<nc:access-list><nc:name>clv2</nc:name></nc:access-list></nc:routing-instance-access></nc:snmp>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show snmp
+# client-list cl1 {
+# 192.16.1.0/24;
+# 192.16.2.0/24;
+# 11.11.11.11/32 {
+# restrict;
+# }
+# }
+# client-list cl2 {
+# 192.16.4.0/24;
+# }
+# routing-instance-access {
+# access-list {
+# clv1;
+# clv2;
+# }
+# }
+# arp {
+# host-name-resolution;
+# }
+# vagrant@vsrx# show routing-instances
+# clv1 {
+# description clv1;
+# }
+# clv2 {
+# description clv2;
+# }
+#
+# Using Replaced
+# Before state
+# ------------
+#
+# vagrant@vsrx# show snmp
+# client-list cl1 {
+# 192.16.1.0/24;
+# 192.16.2.0/24;
+# 11.11.11.11/32 {
+# restrict;
+# }
+# }
+# client-list cl2 {
+# 192.16.4.0/24;
+# }
+# routing-instance-access {
+# access-list {
+# clv1;
+# clv2;
+# }
+# }
+# arp {
+# host-name-resolution;
+# }
+# vagrant@vsrx# show routing-instances
+# clv1 {
+# description clv1;
+# }
+# clv2 {
+# description clv2;
+# }
+
+- name: Replaced running SNMP server configuration with provided configuration
+ junipernetworks.junos.junos_snmp_server:
+ config:
+ contact: "ansiblesupport11@redhat.com"
+ customization:
+ ether_stats_ifd_only: True
+ description: "Local SNMP Server"
+ engine_id:
+ local: "local1"
+ use_default_ip_address: True
+ use_mac_address: True
+ filter_duplicates: True
+ filter_interfaces:
+ set: True
+ all_internal_interfaces: True
+ interfaces:
+ - "eth1"
+ - "eth2"
+ state: replaced
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "contact": "ansiblesupport11@redhat.com",
+# "customization": {
+# "ether_stats_ifd_only": true
+# },
+# "description": "Local SNMP Server",
+# "engine_id": {
+# "use_mac_address": true
+# },
+# "filter_duplicates": true,
+# "filter_interfaces": {
+# "all_internal_interfaces": true,
+# "interfaces": [
+# "eth1",
+# "eth2"
+# ]
+# }
+# },
+# "before":
+# {
+# "arp": {
+# "host_name_resolution": true
+# },
+# "client_lists": [
+# {
+# "addresses": [
+# {
+# "address": "192.16.1.0/24"
+# },
+# {
+# "address": "192.16.2.0/24"
+# },
+# {
+# "address": "11.11.11.11/32",
+# "restrict": true
+# }
+# ],
+# "name": "cl1"
+# },
+# {
+# "addresses": [
+# {
+# "address": "192.16.4.0/24"
+# }
+# ],
+# "name": "cl2"
+# }
+# ],
+# "routing_instance_access": {
+# "access_lists": [
+# "clv1",
+# "clv2"
+# ]
+# }
+# },
+# "changed": true,
+# "commands": [
+# "<nc:snmp xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>",
+# "<nc:snmp xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" delete=\"delete\"/>",
+# "<nc:snmp xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:contact>ansiblesupport11@redhat.com</nc:contact><nc:customization>"
+# "<nc:ether-stats-ifd-only/></nc:customization><nc:description>Local SNMP Server</nc:description>"
+# "<nc:engine-id><nc:local>local1</nc:local><nc:use-default-ip-address/><nc:use-mac-address/>"
+# "</nc:engine-id><nc:filter-duplicates/><nc:filter-interfaces><nc:all-internal-interfaces/><nc:interfaces>"
+# "<nc:name>eth1</nc:name></nc:interfaces><nc:interfaces><nc:name>eth2</nc:name></nc:interfaces>"
+# "</nc:filter-interfaces></nc:snmp>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show routing-instances
+# clv1 {
+# description clv1;
+# }
+# clv2 {
+# description clv2;
+# }
+# vagrant@vsrx# show snmp
+# description "Local SNMP Server";
+# contact "ansiblesupport11@redhat.com";
+# filter-interfaces {
+# interfaces {
+# eth1;
+# eth2;
+# }
+# all-internal-interfaces;
+# }
+# filter-duplicates;
+# engine-id {
+# use-mac-address;
+# }
+# customization {
+# ether-stats-ifd-only;
+# }
+
+# Using overridden
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show snmp
+# client-list cl1 {
+# 192.16.1.0/24;
+# 192.16.2.0/24;
+# 11.11.11.11/32 {
+# restrict;
+# }
+# }
+# client-list cl2 {
+# 192.16.4.0/24;
+# }
+# routing-instance-access {
+# access-list {
+# clv1;
+# clv2;
+# }
+# }
+# arp {
+# host-name-resolution;
+# }
+# vagrant@vsrx# show routing-instances
+# clv1 {
+# description clv1;
+# }
+# clv2 {
+# description clv2;
+# }
+- name: Override running SNMP server configuration with provided configuration
+ junipernetworks.junos.junos_snmp_server:
+ config:
+ contact: "ansiblesupport11@redhat.com"
+ customization:
+ ether_stats_ifd_only: True
+ description: "Local SNMP Server"
+ engine_id:
+ local: "local1"
+ use_default_ip_address: True
+ use_mac_address: True
+ filter_duplicates: True
+ filter_interfaces:
+ set: True
+ all_internal_interfaces: True
+ interfaces:
+ - "eth1"
+ - "eth2"
+ state: overridden
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {
+# "contact": "ansiblesupport11@redhat.com",
+# "customization": {
+# "ether_stats_ifd_only": true
+# },
+# "description": "Local SNMP Server",
+# "engine_id": {
+# "use_mac_address": true
+# },
+# "filter_duplicates": true,
+# "filter_interfaces": {
+# "all_internal_interfaces": true,
+# "interfaces": [
+# "eth1",
+# "eth2"
+# ]
+# }
+# },
+# "before":
+# {
+# "arp": {
+# "host_name_resolution": true
+# },
+# "client_lists": [
+# {
+# "addresses": [
+# {
+# "address": "192.16.1.0/24"
+# },
+# {
+# "address": "192.16.2.0/24"
+# },
+# {
+# "address": "11.11.11.11/32",
+# "restrict": true
+# }
+# ],
+# "name": "cl1"
+# },
+# {
+# "addresses": [
+# {
+# "address": "192.16.4.0/24"
+# }
+# ],
+# "name": "cl2"
+# }
+# ],
+# "routing_instance_access": {
+# "access_lists": [
+# "clv1",
+# "clv2"
+# ]
+# }
+# },
+# "changed": true,
+# "commands": [
+# "<nc:snmp xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>",
+# "<nc:snmp xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" delete=\"delete\"/>",
+# "<nc:snmp xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:contact>ansiblesupport11@redhat.com</nc:contact><nc:customization>"
+# "<nc:ether-stats-ifd-only/></nc:customization><nc:description>Local SNMP Server</nc:description>"
+# "<nc:engine-id><nc:local>local1</nc:local><nc:use-default-ip-address/><nc:use-mac-address/>"
+# "</nc:engine-id><nc:filter-duplicates/><nc:filter-interfaces><nc:all-internal-interfaces/><nc:interfaces>"
+# "<nc:name>eth1</nc:name></nc:interfaces><nc:interfaces><nc:name>eth2</nc:name></nc:interfaces>"
+# "</nc:filter-interfaces></nc:snmp>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show routing-instances
+# clv1 {
+# description clv1;
+# }
+# clv2 {
+# description clv2;
+# }
+# vagrant@vsrx# show snmp
+# description "Local SNMP Server";
+# contact "ansiblesupport11@redhat.com";
+# filter-interfaces {
+# interfaces {
+# eth1;
+# eth2;
+# }
+# all-internal-interfaces;
+# }
+# filter-duplicates;
+# engine-id {
+# use-mac-address;
+# }
+# customization {
+# ether-stats-ifd-only;
+# }
+#
+# Using deleted
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show routing-instances
+# clv1 {
+# description clv1;
+# }
+# clv2 {
+# description clv2;
+# }
+# vagrant@vsrx# show snmp
+# description "Local SNMP Server";
+# contact "ansiblesupport11@redhat.com";
+# filter-interfaces {
+# interfaces {
+# eth1;
+# eth2;
+# }
+# all-internal-interfaces;
+# }
+# filter-duplicates;
+# engine-id {
+# use-mac-address;
+# }
+# customization {
+# ether-stats-ifd-only;
+# }
+#
+- name: Delete running SNMP server configuration
+ junipernetworks.junos.junos_snmp_server:
+ config:
+ state: deleted
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": {},
+# "before": {
+# "contact": "ansiblesupport11@redhat.com",
+# "customization": {
+# "ether_stats_ifd_only": true
+# },
+# "description": "Local SNMP Server",
+# "engine_id": {
+# "use_mac_address": true
+# },
+# "filter_duplicates": true,
+# "filter_interfaces": {
+# "all_internal_interfaces": true,
+# "interfaces": [
+# "eth1",
+# "eth2"
+# ]
+# }
+# },
+# "changed": true,
+# "commands": [
+# "<nc:snmp xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>",
+# "<nc:snmp xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" delete=\"delete\"/>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show routing-instances
+# clv1 {
+# description clv1;
+# }
+# clv2 {
+# description clv2;
+# }
+# vagrant@vsrx# show snmp
+# description "Local SNMP Server";
+# contact "ansiblesupport11@redhat.com";
+# filter-interfaces {
+# interfaces {
+# eth1;
+# eth2;
+# }
+# all-internal-interfaces;
+# }
+# filter-duplicates;
+# engine-id {
+# use-mac-address;
+# }
+# customization {
+# ether-stats-ifd-only;
+# }
+#
+- name: Gather running SNMP server configuration
+ junipernetworks.junos.junos_snmp_server:
+ state: gathered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "gathered": {
+# "contact": "ansiblesupport11@redhat.com",
+# "customization": {
+# "ether_stats_ifd_only": true
+# },
+# "description": "Local SNMP Server",
+# "engine_id": {
+# "use_mac_address": true
+# },
+# "filter_duplicates": true,
+# "filter_interfaces": {
+# "all_internal_interfaces": true,
+# "interfaces": [
+# "eth1",
+# "eth2"
+# ]
+# }
+# },
+# "changed": false,
+# Using rendered
+#
+# Before state
+# ------------
+#
+- name: Render xml for provided facts.
+ junipernetworks.junos.junos_snmp_server:
+ config:
+ arp:
+ set: true
+ host_name_resolution: true
+ routing_instance_access: # ATTR-----3
+ set: true
+ access_lists:
+ - "clv1"
+ - "clv2"
+ state: rendered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "rendered": [
+# "<nc:snmp xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+# "<nc:arp><nc:host-name-resolution/></nc:arp><nc:routing-instance-access>"
+# "<nc:access-list><nc:name>clv1</nc:name></nc:access-list><nc:access-list><nc:name>clv2</nc:name>"
+# "</nc:access-list></nc:routing-instance-access></nc:snmp>"
+# ]
+#
+# Using parsed
+# parsed.cfg
+# ------------
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <version>18.4R1-S2.4</version>
+# <system xmlns="http://yang.juniper.net/junos-es/conf/system">
+# <snmp>
+# <client-list>
+# <name>cl1</name>
+# <client-address-list>
+# <name>192.16.1.0/24</name>
+# </client-address-list>
+# <client-address-list>
+# <name>192.16.2.0/24</name>
+# </client-address-list>
+# <client-address-list>
+# <name>11.11.11.11/32</name>
+# <restrict/>
+# </client-address-list>
+# </client-list>
+# <client-list>
+# <name>cl2</name>
+# <client-address-list>
+# <name>192.16.4.0/24</name>
+# </client-address-list>
+# </client-list>
+# <routing-instance-access>
+# <access-list>
+# <name>clv1</name>
+# </access-list>
+# <access-list>
+# <name>clv2</name>
+# </access-list>
+# </routing-instance-access>
+# <arp>
+# <host-name-resolution/>
+# </arp>
+# </snmp>
+# </system>
+# </configuration>
+# </rpc-reply>
+#
+- name: Parse SNMP server running config
+ junipernetworks.junos.junos_snmp_server:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "parsed": {
+# "arp": {
+# "host_name_resolution": true
+# },
+# "client_lists": [
+# {
+# "addresses": [
+# {
+# "address": "192.16.1.0/24"
+# },
+# {
+# "address": "192.16.2.0/24"
+# },
+# {
+# "address": "11.11.11.11/32",
+# "restrict": true
+# }
+# ],
+# "name": "cl1"
+# },
+# {
+# "addresses": [
+# {
+# "address": "192.16.4.0/24"
+# }
+# ],
+# "name": "cl2"
+# }
+# ],
+# "routing_instance_access": {
+# "access_lists": [
+# "clv1",
+# "clv2"
+# ]
+# }
+# }
+#
+#
+"""
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+after:
+ description: The resulting configuration model invocation.
+ returned: when changed
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ['<nc:arp><nc:host-name-resolution/></nc:arp><nc:routing-instance-access>"',
+ '<nc:snmp xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.snmp_server.snmp_server import (
+ Snmp_serverArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.config.snmp_server.snmp_server import (
+ Snmp_server,
+)
+
+
+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",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ module = AnsibleModule(
+ argument_spec=Snmp_serverArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+
+ result = Snmp_server(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_static_routes.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_static_routes.py
new file mode 100644
index 000000000..7efe112a7
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_static_routes.py
@@ -0,0 +1,308 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_static_routes
+short_description: Static routes resource module
+description: This module provides declarative management of static routes on Juniper
+ JUNOS devices
+version_added: 1.0.0
+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
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show routing-options).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ 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)
+ junipernetworks.junos.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)
+ junipernetworks.junos.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)
+ junipernetworks.junos.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)
+ junipernetworks.junos.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_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.static_routes.static_routes import (
+ Static_routesArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.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
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ module = AnsibleModule(
+ argument_spec=Static_routesArgs.argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+ result = Static_routes(module).execute_module()
+
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_system.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_system.py
new file mode 100644
index 000000000..c70ded66f
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_system.py
@@ -0,0 +1,207 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_system
+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.
+version_added: 1.0.0
+extends_documentation_fragment:
+- junipernetworks.junos.junos
+options:
+ hostname:
+ description:
+ - Configure the device hostname parameter. This option takes an ASCII string value.
+ type: str
+ 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.
+ type: str
+ 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.
+ type: list
+ elements: str
+ 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.
+ type: list
+ elements: str
+ 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
+ type: str
+ 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.
+"""
+
+EXAMPLES = """
+- name: configure hostname and domain name
+ junipernetworks.junos.junos_system:
+ hostname: junos01
+ domain_name: test.example.com
+ domain-search:
+ - ansible.com
+ - redhat.com
+ - juniper.net
+
+- name: remove configuration
+ junipernetworks.junos.junos_system:
+ state: absent
+
+- name: configure name servers
+ junipernetworks.junos.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_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ map_obj_to_ele,
+ map_params_to_obj,
+ tostring,
+)
+
+
+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", elements="str"),
+ name_servers=dict(type="list", elements="str"),
+ state=dict(choices=["present", "absent"], default="present"),
+ active=dict(default=True, type="bool"),
+ )
+
+ 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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_user.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_user.py
new file mode 100644
index 000000000..0e9ee8ad9
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_user.py
@@ -0,0 +1,458 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_user
+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
+version_added: 1.0.0
+extends_documentation_fragment:
+- junipernetworks.junos.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.
+ aliases:
+ - users
+ - collection
+ type: list
+ elements: dict
+ suboptions:
+ 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.
+ required: true
+ type: str
+ 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.
+ type: str
+ 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.
+ type: str
+ 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
+ type: str
+ encrypted_password:
+ description:
+ - The C(encrypted_password) argument set already hashed password for the user
+ account on the remote system.
+ type: str
+ 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: false
+ 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
+ type: str
+ choices:
+ - present
+ - absent
+ active:
+ description:
+ - Specifies whether or not the configuration is active or deactivated
+ type: bool
+ 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.
+ type: str
+ 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.
+ type: str
+ 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.
+ type: str
+ 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
+ type: str
+ encrypted_password:
+ description:
+ - The C(encrypted_password) argument set already hashed password for the user
+ account on the remote system.
+ type: str
+ 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
+ type: str
+ 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.
+"""
+
+EXAMPLES = """
+- name: create new user account
+ junipernetworks.junos.junos_user:
+ name: ansible
+ role: super-user
+ sshkey: "{{ lookup('file', '~/.ssh/ansible.pub') }}"
+ state: present
+
+- name: remove a user account
+ junipernetworks.junos.junos_user:
+ name: ansible
+ state: absent
+
+- name: remove all user accounts except ansible
+ junipernetworks.junos.junos_user:
+ aggregate:
+ - name: ansible
+ purge: yes
+
+- name: set user password
+ junipernetworks.junos.junos_user:
+ name: ansible
+ role: super-user
+ encrypted_password: "{{ 'my-password' | password_hash('sha512') }}"
+ state: present
+
+- name: Create list of users
+ junipernetworks.junos.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
+ junipernetworks.junos.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 copy import deepcopy
+from functools import partial
+
+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.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_default_spec,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ get_connection,
+ load_config,
+ locked_config,
+ tostring,
+)
+
+
+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(no_log=False),
+ state=dict(choices=["present", "absent"], default="present"),
+ purge=dict(type="bool", default=False),
+ 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"),
+ )
+ aggregate_spec["purge"] = dict(type="bool", default=False)
+
+ argument_spec.update(element_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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_vlans.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_vlans.py
new file mode 100644
index 000000000..32f974df6
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_vlans.py
@@ -0,0 +1,467 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_vlans
+short_description: VLANs resource module
+description:
+- This module creates and manages VLAN configurations on Junos OS.
+version_added: 1.0.0
+author: Daniel Mellado (@dmellado)
+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,https://docs.ansible.com/ansible/latest/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
+ name:
+ description:
+ - Name of VLAN.
+ type: str
+ required: true
+ description:
+ description:
+ - Text description of VLANs
+ type: str
+ l3_interface:
+ description:
+ - Name of logical layer 3 interface.
+ type: str
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the Junos device
+ by executing the command B(show vlans).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result
+ type: str
+ state:
+ description:
+ - The state of the configuration after module completion.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - parsed
+ - rendered
+ default: merged
+"""
+
+EXAMPLES = """
+# Using merged
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show vlans
+#
+# [edit]
+
+- name: Merge provided Junos vlans config with running-config
+ junipernetworks.junos.junos_vlans:
+ config:
+ - name: vlan1
+ vlan_id: 1
+ - name: vlan2
+ vlan_id: 2
+ l3_interface: irb.12
+ state: merged
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": [
+# {
+# "name": "vlan1",
+# "vlan_id": 1
+# },
+# {
+# "l3_interface": "irb.12",
+# "name": "vlan2",
+# "vlan_id": 2
+# }
+# ],
+# "before": [],
+# "changed": true,
+# "commands": [
+# "<nc:vlans xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">"
+# "<nc:vlan><nc:name>vlan1</nc:name><nc:vlan-id>1</nc:vlan-id></nc:vlan>"
+# "<nc:vlan><nc:name>vlan2</nc:name><nc:vlan-id>2</nc:vlan-id><nc:l3-interface>irb.12</nc:l3-interface>"
+# "</nc:vlan></nc:vlans>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show vlans
+# vlan1 {
+# vlan-id 1;
+# }
+# vlan2 {
+# vlan-id 2;
+# l3-interface irb.12;
+# }
+
+# Using replaced
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show vlans
+# vlan1 {
+# vlan-id 1;
+# }
+# vlan2 {
+# vlan-id 2;
+# l3-interface irb.12;
+# }
+
+- name: Replace Junos vlans running-config with the provided config
+ junipernetworks.junos.junos_vlans:
+ config:
+ - name: vlan1
+ vlan_id: 11
+ l3_interface: irb.10
+
+ - name: vlan2
+ vlan_id: 2
+ state: replaced
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": [
+# {
+# "l3_interface": "irb.10",
+# "name": "vlan1",
+# "vlan_id": 11
+# },
+# {
+# "name": "vlan2",
+# "vlan_id": 2
+# }
+# ],
+# "before": [
+# {
+# "name": "vlan1",
+# "vlan_id": 1
+# },
+# {
+# "l3_interface": "irb.12",
+# "name": "vlan2",
+# "vlan_id": 2
+# }
+# ],
+# "changed": true,
+# "commands": [
+# "<nc:vlans xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">"
+# "<nc:vlan delete="delete"><nc:name>vlan1</nc:name></nc:vlan>"
+# "<nc:vlan delete="delete"><nc:name>vlan2</nc:name></nc:vlan>"
+# "<nc:vlan><nc:name>vlan1</nc:name><nc:vlan-id>11</nc:vlan-id>"
+# "<nc:l3-interface>irb.10</nc:l3-interface></nc:vlan><nc:vlan>"
+# "<nc:name>vlan2</nc:name><nc:vlan-id>2</nc:vlan-id></nc:vlan></nc:vlans>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show vlans
+# vlan1 {
+# vlan-id 11;
+# l3-interface irb.10;
+# }
+# vlan2 {
+# vlan-id 2;
+# }
+#
+# Using overridden
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show vlans
+# vlan1 {
+# vlan-id 11;
+# l3-interface irb.10;
+# }
+# vlan2 {
+# vlan-id 2;
+# }
+- name: Override Junos running-config with provided config
+ junipernetworks.junos.junos_vlans:
+ config:
+ - name: vlan3
+ vlan_id: 3
+ l3_interface: irb.13
+ state: overridden
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": [
+# {
+# "l3_interface": "irb.13",
+# "name": "vlan3",
+# "vlan_id": 3
+# }
+# ],
+# "before": [
+# {
+# "l3_interface": "irb.10",
+# "name": "vlan1",
+# "vlan_id": 11
+# },
+# {
+# "name": "vlan2",
+# "vlan_id": 2
+# }
+# ],
+# "changed": true,
+# "commands": [
+# "<nc:vlans xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">"
+# "<nc:vlan delete="delete"><nc:name>vlan1</nc:name></nc:vlan><nc:vlan delete="delete">"
+# "<nc:name>vlan2</nc:name></nc:vlan><nc:vlan><nc:name>vlan3</nc:name><nc:vlan-id>3</nc:vlan-id>"
+# "<nc:l3-interface>irb.13</nc:l3-interface></nc:vlan></nc:vlans>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show vlans
+# vlan3 {
+# vlan-id 3;
+# l3-interface irb.13;
+# }
+#
+# Using deleted
+#
+# Before state
+# ------------
+#
+# vagrant@vsrx# show vlans
+# vlan3 {
+# vlan-id 3;
+# l3-interface irb.13;
+# }
+- name: Delete specific vlan
+ junipernetworks.junos.junos_vlans:
+ config:
+ - name: vlan3
+ state: deleted
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "after": [],
+# "changed": true,
+# "commands": [
+# "<nc:vlans xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+# "<nc:vlan delete="delete"><nc:name>vlan3</nc:name></nc:vlan></nc:vlans>"
+# ]
+# After state
+# -----------
+#
+# vagrant@vsrx# show vlans
+# vlan1 {
+# vlan-id 11;
+# l3-interface irb.10;
+# }
+# vlan2 {
+# vlan-id 2;
+# }
+
+
+- name: Gather running vlans configuration
+ junipernetworks.junos.junos_vlans:
+ state: gathered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "gathered": [
+# {
+# "l3_interface": "irb.10",
+# "name": "vlan1",
+# "vlan_id": 11
+# },
+# {
+# "name": "vlan2",
+# "vlan_id": 2
+# }
+# ],
+# "changed": false,
+#
+# Using rendered
+#
+# Before state
+# ------------
+#
+- name: Render xml for provided facts.
+ junipernetworks.junos.junos_vlans:
+ config:
+ - name: vlan1
+ vlan_id: 1
+
+ - name: vlan2
+ vlan_id: 2
+ l3_interface: irb.12
+ state: rendered
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+# "rendered": [
+# "<nc:vlans xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">"
+# "<nc:vlan><nc:name>vlan1</nc:name><nc:vlan-id>1</nc:vlan-id></nc:vlan>"
+# "<nc:vlan><nc:name>vlan2</nc:name><nc:vlan-id>2</nc:vlan-id><nc:l3-interface>irb.12</nc:l3-interface>"
+# "</nc:vlan></nc:vlans>"
+# ]
+# Using parsed
+# parsed.cfg
+# ------------
+# <?xml version="1.0" encoding="UTF-8"?>
+# <rpc-reply message-id="urn:uuid:0cadb4e8-5bba-47f4-986e-72906227007f">
+# <configuration changed-seconds="1590139550" changed-localtime="2020-05-22 09:25:50 UTC">
+# <version>18.4R1-S2.4</version>
+# <vlans>
+# <vlan>
+# <name>vlan1</name>
+# <vlan-id>1</vlan-id>
+# </vlan>
+# <vlan>
+# <name>vlan2</name>
+# <vlan-id>2</vlan-id>
+# <l3-interface>irb.12</l3-interface>
+# </vlan>
+# </vlans>
+# </configuration>
+# </rpc-reply>
+
+- name: Parse routing instance running config
+ junipernetworks.junos.junos_vlans:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "parsed": [
+# {
+# "name": "vlan1",
+# "vlan_id": 1
+# },
+# {
+# "l3_interface": "irb.12",
+# "name": "vlan2",
+# "vlan_id": 2
+# }
+# ]
+#
+"""
+
+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: ['<nc:vlans xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
+ <nc:vlan><nc:name>vlan1</nc:name><nc:vlan-id>1</nc:vlan-id>
+ </nc:vlan><nc:vlan><nc:name>vlan2</nc:name><nc:vlan-id>2</nc:vlan-id>
+ <nc:l3-interface>irb.12</nc:l3-interface></nc:vlan></nc:vlans>', 'xml 2', 'xml 3']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.argspec.vlans.vlans import (
+ VlansArgs,
+)
+from ansible_collections.junipernetworks.junos.plugins.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", "rendered", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "parsed", ("running_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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/modules/junos_vrf.py b/ansible_collections/junipernetworks/junos/plugins/modules/junos_vrf.py
new file mode 100644
index 000000000..e2332d1c5
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/modules/junos_vrf.py
@@ -0,0 +1,342 @@
+#!/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
+
+
+DOCUMENTATION = """
+module: junos_vrf
+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.
+version_added: 1.0.0
+extends_documentation_fragment:
+- junipernetworks.junos.junos
+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
+ type: str
+ 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.
+ type: str
+ 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.
+ type: list
+ elements: str
+ 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.
+ type: list
+ elements: str
+ 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.
+ type: list
+ elements: str
+ 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.
+ default: true
+ 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.
+ type: list
+ elements: dict
+ suboptions:
+ 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
+ required: true
+ type: str
+ 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.
+ type: str
+ 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.
+ type: list
+ elements: str
+ 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.
+ type: list
+ elements: str
+ 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.
+ type: list
+ elements: str
+ 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
+ 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
+ type: str
+ choices:
+ - present
+ - absent
+ active:
+ description:
+ - Specifies whether or not the configuration is active or deactivated
+ type: bool
+ 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
+ type: str
+ 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.
+"""
+
+EXAMPLES = """
+- name: Configure vrf configuration
+ junipernetworks.junos.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
+ junipernetworks.junos.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
+ junipernetworks.junos.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
+ junipernetworks.junos.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
+ junipernetworks.junos.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_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_default_spec,
+)
+
+from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
+ commit_configuration,
+ discard_changes,
+ load_config,
+ locked_config,
+ map_obj_to_ele,
+ map_params_to_obj,
+ to_param_list,
+ tostring,
+)
+
+
+USE_PERSISTENT_CONNECTION = True
+
+
+def main():
+ """main entry point for module execution"""
+ element_spec = dict(
+ name=dict(),
+ description=dict(),
+ rd=dict(type="list", elements="str"),
+ interfaces=dict(type="list", elements="str"),
+ target=dict(type="list", elements="str"),
+ 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)
+
+ 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()
diff --git a/ansible_collections/junipernetworks/junos/plugins/netconf/__init__.py b/ansible_collections/junipernetworks/junos/plugins/netconf/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/netconf/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/netconf/junos.py b/ansible_collections/junipernetworks/junos/plugins/netconf/junos.py
new file mode 100644
index 000000000..9c7986a87
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/netconf/junos.py
@@ -0,0 +1,283 @@
+#
+# (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 (@ansible-network)
+name: 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: 1.0.0
+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.errors import AnsibleConnectionFailure
+from ansible.module_utils._text import to_native, to_text
+from ansible.module_utils.six import string_types
+from ansible_collections.ansible.netcommon.plugins.plugin_utils.netconf_base import (
+ NetconfBase,
+ ensure_ncclient,
+)
+
+
+try:
+ from ncclient import manager
+ from ncclient.operations import RPCError
+ from ncclient.transport.errors import SSHUnknownHostError
+ from ncclient.xml_ import new_ele, sub_ele, to_ele, to_xml
+
+ 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"] = list(self.m.server_capabilities)
+ result["client_capabilities"] = list(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,
+ timeout=None,
+ persist=None,
+ check=False,
+ 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)
diff --git a/ansible_collections/junipernetworks/junos/plugins/terminal/__init__.py b/ansible_collections/junipernetworks/junos/plugins/terminal/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/terminal/__init__.py
diff --git a/ansible_collections/junipernetworks/junos/plugins/terminal/junos.py b/ansible_collections/junipernetworks/junos/plugins/terminal/junos.py
new file mode 100644
index 000000000..574e80cc2
--- /dev/null
+++ b/ansible_collections/junipernetworks/junos/plugins/terminal/junos.py
@@ -0,0 +1,68 @@
+#
+# (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.errors import AnsibleConnectionFailure
+from ansible.module_utils.common.text.converters import to_bytes
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.plugin_utils.terminal_base import TerminalBase
+
+
+display = Display()
+
+
+class TerminalModule(TerminalBase):
+
+ terminal_stdout_re = [
+ re.compile(
+ to_bytes(r"({primary:node\d+})?[\r\n]?[\w@+\-\.:\/\[\]]+[>#%] ?$"),
+ ),
+ ]
+
+ terminal_stderr_re = [
+ re.compile(to_bytes(r"unknown command")),
+ re.compile(to_bytes(r"syntax error")),
+ re.compile(to_bytes(r"[\r\n]error:")),
+ ]
+
+ terminal_config_prompt = re.compile(r"^.+#$")
+
+ 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")