diff --git a/tests/junipernetworks.junos/README.md b/tests/junipernetworks.junos/README.md new file mode 100644 index 00000000..bdc6e87a --- /dev/null +++ b/tests/junipernetworks.junos/README.md @@ -0,0 +1,97 @@ +Functional Tests for Juniper Ansible Collection (junipernetworks.junos) + +This directory contains a complete suite of functional tests for the modules in the junipernetworks.junos Ansible collection. + +These playbooks verify behavior for each supported module using real Junos devices or virtual environments, following official module documentation examples. This ensures compatibility, schema adherence, and correctness across configuration states like merged, replaced, overridden, deleted, rendered, gathered, and parsed. + +๐Ÿ”ง Directory Structure + +All functional test playbooks are located under: + +tests/junipernetworks.junos/ + +Each playbook corresponds to one Ansible module, for example: + +pb.juniper_junos_system.yml + +pb.juniper_junos_lag_interfaces.yml + +pb.juniper_junos_bgp_global.yml + +etc. + +Any required configuration files (e.g., parsed_configs/*.cfg) are also included. + +๐Ÿงช Steps to Execute Functional Test Playbooks + +1. Clone the Repository + +git clone https://github.com/Juniper/ansible-junos-stdlib.git +cd ansible-junos-stdlib/tests/junipernetworks.junos + +2. Ensure ansible.cfg is configured correctly + +[defaults] +hash_behaviour = merge +inventory = inventory +host_key_checking = False +log_path = ./ansible.log + +[persistent_connection] +command_timeout = 300 + +3. Inventory Setup (inventory) + +The inventory file defines three connection types: + +a. NETCONF (default) + +[netconf_connection_testcases] +junos_device ansible_host=xx.xx.xx.xx + +b. Local connection + +[local_connection_testcases] +localhost ansible_connection=local ansible_network_os=none + +c. Network CLI + +[network_cli_testcases] +junos_netconf_device ansible_host=xx.xx.xx.xx ansible_connection=network_cli ansible_network_os=junipernetworks.junos.junos ansible_user=xx ansible_password=xx + +Global variables: + +[all:vars] +ansible_python_interpreter=/path/to/venv/bin/python +ansible_connection=netconf +ansible_network_os=junipernetworks.junos.junos +ansible_user=xx +ansible_password=xx + + +4. Run a Functional Test + +ansible-playbook pb.juniper_junos_l3_interfaces.yml + +You can use -v or -vvv for verbose output and troubleshooting. + +5. Run All Tests Automatically + +To run all 38 functional tests in sequence, use the provided script: + +./run_all_tests.sh + + +This script will: + +Execute every test playbook under junipernetworks.junos/ + +Log results to ansible.log + +Ensure a complete functional regression pass + +Make sure the script is executable: + +chmod +x run_all_tests.sh + + diff --git a/tests/junipernetworks.junos/ansible.cfg b/tests/junipernetworks.junos/ansible.cfg new file mode 100644 index 00000000..27b4e8e3 --- /dev/null +++ b/tests/junipernetworks.junos/ansible.cfg @@ -0,0 +1,9 @@ +[defaults] +hash_behaviour=merge +inventory = inventory +host_key_checking = False +log_path = ./ansible.log + + +[persistent_connection] +command_timeout = 300 diff --git a/tests/junipernetworks.junos/inventory b/tests/junipernetworks.junos/inventory new file mode 100644 index 00000000..a5fccefd --- /dev/null +++ b/tests/junipernetworks.junos/inventory @@ -0,0 +1,15 @@ +[netconf_connection_testcases] +junos_device ansible_host=xx.xx.xx.xx + +[local_connection_testcases] +localhost ansible_connection=local ansible_network_os=none + +[network_cli_testcases] +junos_netconf_device ansible_host=xx.xx.xx.xx ansible_connection=network_cli ansible_network_os=junipernetworks.junos.junos ansible_user=xx ansible_password=xx + +[all:vars] +ansible_python_interpreter=/path/to/venv/bin/python +ansible_connection=netconf +ansible_network_os=junipernetworks.junos.junos +ansible_user=xx +ansible_password=xx diff --git a/tests/junipernetworks.junos/parsed_configs/parsed_bgp_address_family.cfg b/tests/junipernetworks.junos/parsed_configs/parsed_bgp_address_family.cfg new file mode 100644 index 00000000..027160f5 --- /dev/null +++ b/tests/junipernetworks.junos/parsed_configs/parsed_bgp_address_family.cfg @@ -0,0 +1,104 @@ + + + + + + + + + + 20 + + 98 + + 2001 + + + + + + 2 + + + + + + + + + + + 4 + + + + + + + + + 9.9.9.9 + + + + + + + + + + + + + + 20 + + 99 + + + + + + + + + + + + 3 + + + + + 20 + + 99 + + 2000 + + + + + + + 23000 + 32000 + + + 20 + 32000 + + + + 2 + + + from-fib + + + + + + + + diff --git a/tests/junipernetworks.junos/parsed_configs/parsed_bgp_global.cfg b/tests/junipernetworks.junos/parsed_configs/parsed_bgp_global.cfg new file mode 100644 index 00000000..7a8f93f4 --- /dev/null +++ b/tests/junipernetworks.junos/parsed_configs/parsed_bgp_global.cfg @@ -0,0 +1,16 @@ + + + + + external-peers + external + 192.0.2.1 + + bgp-keychain + + 65100 + + 65000 + + + diff --git a/tests/junipernetworks.junos/parsed_configs/parsed_junos_vlans.cfg b/tests/junipernetworks.junos/parsed_configs/parsed_junos_vlans.cfg new file mode 100644 index 00000000..d4d690cb --- /dev/null +++ b/tests/junipernetworks.junos/parsed_configs/parsed_junos_vlans.cfg @@ -0,0 +1,16 @@ + + + + + + vlan1 + 1 + + + vlan2 + 2 + irb.12 + + + + diff --git a/tests/junipernetworks.junos/parsed_configs/parsed_logging_global.cfg b/tests/junipernetworks.junos/parsed_configs/parsed_logging_global.cfg new file mode 100644 index 00000000..04a189d4 --- /dev/null +++ b/tests/junipernetworks.junos/parsed_configs/parsed_logging_global.cfg @@ -0,0 +1,34 @@ + + + + + + + messages + + any + + + + authorization + + + + + interactive-commands + + interactive-commands + + + + + * + + any + + + + + + + diff --git a/tests/junipernetworks.junos/parsed_configs/parsed_ntp_global.cfg b/tests/junipernetworks.junos/parsed_configs/parsed_ntp_global.cfg new file mode 100644 index 00000000..4bca659d --- /dev/null +++ b/tests/junipernetworks.junos/parsed_configs/parsed_ntp_global.cfg @@ -0,0 +1,60 @@ + + + + 78.46.194.186 + +
172.16.255.255
+ 50 + 200 + 3 + rt1 +
+ +
192.16.255.255
+ 50 + 200 + 3 + rt2 +
+ + 2 + 224.0.0.1 + + 78.44.194.186 + + + 172.44.194.186 + 10000 + + 3 + + + 48.46.194.186 + 34 + + 2 + rt1 + + + 48.45.194.186 + 34 + + 2 + + + 172.45.194.186 + rt1 + + + 171.45.194.186 + rt2 + + + 300 + accept + + 3000 + 2000 +
+
+
diff --git a/tests/junipernetworks.junos/parsed_configs/parsed_ospf_interfaces.cfg b/tests/junipernetworks.junos/parsed_configs/parsed_ospf_interfaces.cfg new file mode 100644 index 00000000..847c78dc --- /dev/null +++ b/tests/junipernetworks.junos/parsed_configs/parsed_ospf_interfaces.cfg @@ -0,0 +1,18 @@ + + + + + 0.0.0.0 + + ge-0/0/0.0 + 5 + 10 + + + ge-0/0/1.0 + + + + + + diff --git a/tests/junipernetworks.junos/parsed_configs/parsed_ospfv2.cfg b/tests/junipernetworks.junos/parsed_configs/parsed_ospfv2.cfg new file mode 100644 index 00000000..5dff43df --- /dev/null +++ b/tests/junipernetworks.junos/parsed_configs/parsed_ospfv2.cfg @@ -0,0 +1,53 @@ + + + + + + 10g + + + 0.0.0.100 + + 100 + + + 10.200.16.0/24 + + 10000 + + + 10.200.11.0/24 + + + + + so-0/0/0.0 + + + + 1g + 5 + + + 10g + 40 + + + 5 + 3 + 2 + 2 + 4 + 2 + + + + + + 10.200.16.75 + + 65432 + + + + diff --git a/tests/junipernetworks.junos/parsed_configs/parsed_ospfv3.cfg b/tests/junipernetworks.junos/parsed_configs/parsed_ospfv3.cfg new file mode 100644 index 00000000..55292b7d --- /dev/null +++ b/tests/junipernetworks.junos/parsed_configs/parsed_ospfv3.cfg @@ -0,0 +1,34 @@ + + + + + + + 0.0.0.100 + + 200 + + + so-0/0/0.0 + + 5 + 3 + + + + + 0.0.0.200 + + ge-1/1/0.0 + + + ge-2/2/0.0 + + + + + + 10.200.16.75 + + + diff --git a/tests/junipernetworks.junos/parsed_configs/parsed_routing_instances.cfg b/tests/junipernetworks.junos/parsed_configs/parsed_routing_instances.cfg new file mode 100644 index 00000000..0acea602 --- /dev/null +++ b/tests/junipernetworks.junos/parsed_configs/parsed_routing_instances.cfg @@ -0,0 +1,25 @@ + + + + test + vrf + 10.58.255.1:37 + test-policy + test-policy + test-policy-1 + sp-0/0/0.0 + gr-0/0/0.0 + + + + forwardinst + forwarding + Configured by Ansible Content Team + + + vtest1 + virtual-router + ge-0/0/0.0 + + + diff --git a/tests/junipernetworks.junos/parsed_configs/parsed_routing_options.cfg b/tests/junipernetworks.junos/parsed_configs/parsed_routing_options.cfg new file mode 100644 index 00000000..e3e4d4ad --- /dev/null +++ b/tests/junipernetworks.junos/parsed_configs/parsed_routing_options.cfg @@ -0,0 +1,9 @@ + + + + + 2 + + 2.2.2.2 + + diff --git a/tests/junipernetworks.junos/parsed_configs/parsed_security_policies.cfg b/tests/junipernetworks.junos/parsed_configs/parsed_security_policies.cfg new file mode 100644 index 00000000..50fbe124 --- /dev/null +++ b/tests/junipernetworks.junos/parsed_configs/parsed_security_policies.cfg @@ -0,0 +1,32 @@ + + + + + + + test_glob_1 + + any-ipv6 + any-ipv6 + any + + + + + + + test_glob_2 + + any-ipv6 + any-ipv6 + any + + + + + + + + + + diff --git a/tests/junipernetworks.junos/parsed_configs/parsed_security_policies_global.cfg b/tests/junipernetworks.junos/parsed_configs/parsed_security_policies_global.cfg new file mode 100644 index 00000000..af26beca --- /dev/null +++ b/tests/junipernetworks.junos/parsed_configs/parsed_security_policies_global.cfg @@ -0,0 +1,41 @@ + + + + + + + + + 10k + 3 + + /[A-Z]*/gm + + + all + + + + + + + + + + enable + + + + + + + + 10 + 10 + + + + + + + diff --git a/tests/junipernetworks.junos/parsed_configs/parsed_security_zones.cfg b/tests/junipernetworks.junos/parsed_configs/parsed_security_zones.cfg new file mode 100644 index 00000000..640e69c2 --- /dev/null +++ b/tests/junipernetworks.junos/parsed_configs/parsed_security_zones.cfg @@ -0,0 +1,24 @@ + + + + + + + trust + Trusted zone + + ge-0/0/1.0 + + + ssh + + + ping + + + + + + + + diff --git a/tests/junipernetworks.junos/parsed_configs/parsed_snmp.cfg b/tests/junipernetworks.junos/parsed_configs/parsed_snmp.cfg new file mode 100644 index 00000000..3ba55e02 --- /dev/null +++ b/tests/junipernetworks.junos/parsed_configs/parsed_snmp.cfg @@ -0,0 +1,24 @@ + + + + + + + cl1 + 192.16.1.0/24 + 192.16.2.0/24 + 11.11.11.11/32 + + + cl2 + 192.16.4.0/24 + + + clv1 + clv2 + + + + + + diff --git a/tests/junipernetworks.junos/parsed_configs/parsed_static_routes.cfg b/tests/junipernetworks.junos/parsed_configs/parsed_static_routes.cfg new file mode 100644 index 00000000..9b0f576e --- /dev/null +++ b/tests/junipernetworks.junos/parsed_configs/parsed_static_routes.cfg @@ -0,0 +1,18 @@ + + + + + + + 192.168.16.0/24 + 172.16.1.2 + 172.16.1.3 + + + 192.168.47.0/24 + 10.200.16.2 + + + + + diff --git a/tests/junipernetworks.junos/pb.juniper_junos_acl_interfaces.yml b/tests/junipernetworks.junos/pb.juniper_junos_acl_interfaces.yml new file mode 100644 index 00000000..f051f1aa --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_acl_interfaces.yml @@ -0,0 +1,126 @@ + +- name: Functional Test - junos_acl_interfaces module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + vars: + interface_name: "ge-1/0/0" + inbound_acl_name: "inbound_acl" + outbound_acl_name: "outbound_acl" + + tasks: + + - name: Setup - Ensure initial ACL config is absent (clean slate) + junos_acl_interfaces: + config: + - name: "{{ interface_name }}" + access_groups: + - afi: ipv4 + acls: + - name: "{{ inbound_acl_name }}" + direction: in + - name: "{{ outbound_acl_name }}" + direction: out + state: deleted + register: cleanup_result + + - name: Assert cleanup before test + assert: + that: + - cleanup_result.changed in [true, false] + + - name: Pre-config - Create inbound and outbound ACL filters + junipernetworks.junos.junos_config: + lines: + - set firewall family inet filter {{ inbound_acl_name }} term 1 from source-address 10.0.0.0/8 + - set firewall family inet filter {{ inbound_acl_name }} term 1 then accept + - set firewall family inet filter {{ outbound_acl_name }} term 1 from destination-address 192.168.0.0/16 + - set firewall family inet filter {{ outbound_acl_name }} term 1 then accept + comment: "Test ACL filters for junos_acl_interfaces FT" + + + - name: Test - Merge ACL config into interface + junos_acl_interfaces: + config: + - name: "{{ interface_name }}" + access_groups: + - afi: ipv4 + acls: + - name: "{{ inbound_acl_name }}" + direction: in + - name: "{{ outbound_acl_name }}" + direction: out + state: merged + register: merge_result + + - name: Assert merge operation + assert: + that: + - merge_result.changed == true + - merge_result.after is defined + - merge_result.commands | length > 0 + + + - name: Test - Replace ACL config with only input filter + junos_acl_interfaces: + config: + - name: "{{ interface_name }}" + access_groups: + - afi: ipv4 + acls: + - name: "{{ inbound_acl_name }}" + direction: in + state: overridden + register: replace_result + + - name: Assert override operation + assert: + that: + - replace_result.changed == true + - outbound_acl_name not in (replace_result.after | to_json) + + + - name: Test - Override ACL config with both directions + junos_acl_interfaces: + config: + - name: "{{ interface_name }}" + access_groups: + - afi: ipv4 + acls: + - name: "{{ inbound_acl_name }}" + direction: in + - name: "{{ outbound_acl_name }}" + direction: out + state: overridden + register: override_result + + - name: Assert override operation + assert: + that: + - override_result.changed == true + + + - name: Test - Delete ACL config + junos_acl_interfaces: + config: + - name: "{{ interface_name }}" + access_groups: + - afi: ipv4 + acls: + - name: "{{ inbound_acl_name }}" + direction: in + - name: "{{ outbound_acl_name }}" + direction: out + state: deleted + register: delete_result + + - name: Assert delete operation + assert: + that: + - delete_result.changed == true + - delete_result.after is defined + + diff --git a/tests/junipernetworks.junos/pb.juniper_junos_acls.yml b/tests/junipernetworks.junos/pb.juniper_junos_acls.yml new file mode 100644 index 00000000..0ee9e576 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_acls.yml @@ -0,0 +1,64 @@ +- name: Functional Test - junos_acls module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + vars: + acl_name: "allow_ssh_acl" + term_name: "ssh_rule" + + tasks: + + - name: Pre-clean - Delete test ACL if it exists + junos_acls: + config: + - afi: ipv4 + acls: + - name: "{{ acl_name }}" + state: deleted + register: pre_cleanup + + - name: Assert pre-clean success + assert: + that: + - pre_cleanup.changed in [true, false] + + + - name: Apply ACL with state merged + junos_acls: + config: + - afi: ipv4 + acls: + - name: "{{ acl_name }}" + aces: + - name: "{{ term_name }}" + source: + port_protocol: + eq: ssh + protocol: tcp + state: merged + register: merge_result + + - name: Assert merged config applied + assert: + that: + - merge_result.changed == true + - merge_result.after is defined + - merge_result.commands | length > 0 + + + - name: Post-clean - Remove ACL + junos_acls: + config: + - afi: ipv4 + acls: + - name: "{{ acl_name }}" + state: deleted + register: post_cleanup + + - name: Assert ACL was cleaned up + assert: + that: + - post_cleanup.changed == true diff --git a/tests/junipernetworks.junos/pb.juniper_junos_banner.yml b/tests/junipernetworks.junos/pb.juniper_junos_banner.yml new file mode 100644 index 00000000..7799536b --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_banner.yml @@ -0,0 +1,74 @@ +- name: Functional Test - junos_banner module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + vars: + login_banner_text: | + this is my login banner + used for testing purposes + + tasks: + - name: Pre-clean - Remove login banner if exists + junipernetworks.junos.junos_banner: + banner: login + state: absent + register: preclean_result + + - name: Assert pre-clean successful + assert: + that: + - preclean_result.changed in [true, false] + + - name: Apply login banner with state present + junipernetworks.junos.junos_banner: + banner: login + text: "{{ login_banner_text }}" + state: present + register: present_result + + - name: Assert login banner applied + assert: + that: + - present_result.changed == true + + - name: Deactivate the login banner + junipernetworks.junos.junos_banner: + banner: login + text: "{{ login_banner_text }}" + state: present + active: false + register: deactivate_result + + - name: Assert login banner deactivated + assert: + that: + - deactivate_result.changed == true + + - name: Reactivate the login banner + junipernetworks.junos.junos_banner: + banner: login + state: present + active: true + text: | + this is my login banner + used for testing purpose + register: reactivate_result + + - name: Assert login banner reactivated + assert: + that: + - reactivate_result.changed == true + + - name: Post-clean - Remove login banner + junipernetworks.junos.junos_banner: + banner: login + state: absent + register: postclean_result + + - name: Assert login banner removed + assert: + that: + - postclean_result.changed == true diff --git a/tests/junipernetworks.junos/pb.juniper_junos_bgp_address_family.yml b/tests/junipernetworks.junos/pb.juniper_junos_bgp_address_family.yml new file mode 100644 index 00000000..b7eb1b9c --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_bgp_address_family.yml @@ -0,0 +1,151 @@ +- name: Functional Test - junos_bgp_address_family + hosts: junos_device + gather_facts: no + connection: ansible.netcommon.netconf + collections: + - junipernetworks.junos + + tasks: + - name: MERGED - Full BGP address family config + 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 + + - name: REPLACED - Replace BGP config with simplified evpn + 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 + + - name: OVERRIDDEN - Override with same evpn 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 + + - name: DELETED - Delete AFI inet only + junipernetworks.junos.junos_bgp_address_family: + config: + address_family: + - afi: 'inet' + state: deleted + + - name: DELETED - Delete all address-family configuration + junipernetworks.junos.junos_bgp_address_family: + config: {} + state: deleted + + - name: GATHERED - Gather current BGP AF config + junipernetworks.junos.junos_bgp_address_family: + config: {} + state: gathered + register: gathered_output + + - name: Assert BGP config gathered + assert: + that: + - gathered_output.gathered is defined + + - name: RENDERED - Render BGP config + 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 + state: rendered + + - name: PARSED - Parse provided BGP config + junipernetworks.junos.junos_bgp_address_family: + running_config: "{{ lookup('file', './parsed_configs/parsed_bgp_address_family.cfg') }}" + state: parsed diff --git a/tests/junipernetworks.junos/pb.juniper_junos_bgp_global.yml b/tests/junipernetworks.junos/pb.juniper_junos_bgp_global.yml new file mode 100644 index 00000000..2aa9a467 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_bgp_global.yml @@ -0,0 +1,124 @@ +- name: Functional Test - junos_bgp_global + hosts: junos_device + connection: netconf + gather_facts: false + + tasks: + + - name: MERGED - Merge provided 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_from_main_vpn_tables: true + advertise_inactive: true + 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 + + - name: REPLACED - Replace bgp config + junipernetworks.junos.junos_bgp_global: + config: + advertise_inactive: true + 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: "Replace running bgp config" + egress_te_sid_stats: true + hold_time: 5 + out_delay: 10 + preference: "2" + state: replaced + + - name: OVERRIDDEN - Override running config + junipernetworks.junos.junos_bgp_global: + config: + advertise_inactive: true + 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: "Replace running bgp config" + egress_te_sid_stats: true + hold_time: 5 + out_delay: 10 + preference: "2" + state: overridden + + - name: GATHERED - Gather bgp global facts + junipernetworks.junos.junos_bgp_global: + config: + state: gathered + + - name: RENDERED - Render configuration into XML + 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_from_main_vpn_tables: true + advertise_inactive: true + 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: rendered + + - name: PARSED - Parse the device config into facts + junipernetworks.junos.junos_bgp_global: + running_config: "{{ lookup('file', './parsed_configs/parsed_bgp_global.cfg') }}" + state: parsed + + - name: DELETED - Delete the bgp config + junipernetworks.junos.junos_bgp_global: + config: + state: deleted + + - name: PURGED - Purge the bgp config + junipernetworks.junos.junos_bgp_global: + config: + state: purged diff --git a/tests/junipernetworks.junos/pb.juniper_junos_command.yml b/tests/junipernetworks.junos/pb.juniper_junos_command.yml new file mode 100644 index 00000000..14e7271c --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_command.yml @@ -0,0 +1,68 @@ + + +- name: Functional Test - junos_command module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + - name: Run show version + junipernetworks.junos.junos_command: + commands: show version + register: version_output + + - name: Assert show version output is returned + assert: + that: + - version_output.stdout is defined + - "'Junos' in version_output.stdout[0]" + + - name: Run show version with wait_for condition (positive match) + junipernetworks.junos.junos_command: + commands: show version + wait_for: + - result[0] contains Hostname + register: show_version_wait_positive + + - name: Assert wait_for with positive match passed + assert: + that: + - show_version_wait_positive.stdout is defined + - show_version_wait_positive.failed_conditions is not defined + + - name: Run multiple commands + junipernetworks.junos.junos_command: + commands: + - show version + - show interfaces terse + register: multi_output + + - name: Assert multiple commands worked + assert: + that: + - multi_output.stdout | length == 2 + - "'Interface' in multi_output.stdout[1]" + + - name: Run show version with json output + junipernetworks.junos.junos_command: + commands: show version + display: json + register: json_output + + - name: Assert json output is returned + assert: + that: + - json_output.stdout is defined + + - name: Run RPC get-software-information + junipernetworks.junos.junos_command: + rpcs: get-software-information + register: rpc_output + + - name: Assert RPC output + assert: + that: + - rpc_output.stdout is defined + - rpc_output.stdout[0] is string diff --git a/tests/junipernetworks.junos/pb.juniper_junos_config.yml b/tests/junipernetworks.junos/pb.juniper_junos_config.yml new file mode 100644 index 00000000..82ecfb9d --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_config.yml @@ -0,0 +1,73 @@ +- name: Functional Test - junos_config module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + + - name: Pre-clean - Remove existing test interface description + junipernetworks.junos.junos_config: + lines: + - delete interfaces ge-0/0/1 unit 0 description + comment: "Clean up test interface config" + register: preclean_result + + - name: Assert pre-clean successful + ansible.builtin.assert: + that: + - preclean_result.changed in [true, false] + + - name: Apply test config - set interface description + junipernetworks.junos.junos_config: + lines: + - set interfaces ge-0/0/1 unit 0 description "FT Test interface" + comment: "Apply test config" + register: apply_result + + - name: Assert interface config applied + ansible.builtin.assert: + that: + - apply_result.changed == true + + - name: Confirm commit test with timer + junipernetworks.junos.junos_config: + lines: + - set system host-name ft-test-host + confirm: 3 + comment: "Test commit confirmation" + # Intentionally allowing commit to rollback to test confirm + + - name: Rollback config to rollback 0 + junipernetworks.junos.junos_config: + rollback: 0 + + - name: Backup config to custom path + junipernetworks.junos.junos_config: + lines: + - set system services ssh + backup: true + backup_options: + filename: ssh_backup.cfg + dir_path: ./backup + register: backup_result + + - name: Debug backup_result + debug: + var: backup_result + + + - name: Assert backup created + ansible.builtin.assert: + that: + - backup_result.backup_path is defined or backup_result.__backup__ is defined + + - name: Post-clean - delete test configuration + junipernetworks.junos.junos_config: + lines: + - delete interfaces ge-0/0/1 unit 0 description + - delete system host-name + - delete system services ssh + comment: "Post-clean" + diff --git a/tests/junipernetworks.junos/pb.juniper_junos_facts.yml b/tests/junipernetworks.junos/pb.juniper_junos_facts.yml new file mode 100644 index 00000000..a40a534a --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_facts.yml @@ -0,0 +1,44 @@ +- name: Functional Test - junos_facts module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + - name: Collect default set of facts (min) + junipernetworks.junos.junos_facts: + register: default_facts + + - name: Assert default facts gathered + assert: + that: + - default_facts.ansible_facts is defined + - default_facts.ansible_facts.ansible_net_model is defined + - default_facts.ansible_facts.ansible_net_hostname is defined + + - name: Collect full facts including config and interfaces + junipernetworks.junos.junos_facts: + gather_subset: + - all + register: full_facts + + - name: Assert full facts gathered + assert: + that: + - full_facts.ansible_facts.ansible_net_interfaces is defined + - full_facts.ansible_facts.ansible_net_config is defined + + - name: Collect hardware and config with text format + junipernetworks.junos.junos_facts: + gather_subset: + - hardware + - config + config_format: text + register: hw_config_facts + + - name: Assert hardware and config facts gathered + assert: + that: + - hw_config_facts.ansible_facts.ansible_net_config is defined + - "'system' in hw_config_facts.ansible_facts.ansible_net_config" diff --git a/tests/junipernetworks.junos/pb.juniper_junos_hostname.yml b/tests/junipernetworks.junos/pb.juniper_junos_hostname.yml new file mode 100644 index 00000000..afe3c26f --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_hostname.yml @@ -0,0 +1,57 @@ +- name: Functional Test - junos_hostname module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + vars: + test_hostname: "ft-host-20250424084647" + + tasks: + + - name: Pre-clean - Delete existing hostname + junipernetworks.junos.junos_hostname: + config: {} + state: deleted + register: delete_result + + - name: Assert pre-clean success + assert: + that: + - delete_result.changed == true or delete_result.changed == false + + - name: Apply hostname config with state merged + junipernetworks.junos.junos_hostname: + config: + hostname: "{{ test_hostname }}" + state: merged + register: merged_result + + - name: Assert hostname was set + assert: + that: + - merged_result.changed == true + - merged_result.after.hostname == test_hostname + + - name: Gather hostname config + junipernetworks.junos.junos_hostname: + state: gathered + register: gather_result + + - name: Assert gathered hostname is correct + assert: + that: + - gather_result.changed == false + - gather_result.gathered.hostname == test_hostname + + - name: Delete test hostname (post-clean) + junipernetworks.junos.junos_hostname: + config: {} + state: deleted + register: cleanup_result + + - name: Assert hostname deleted + assert: + that: + - cleanup_result.changed == true diff --git a/tests/junipernetworks.junos/pb.juniper_junos_interfaces.yml b/tests/junipernetworks.junos/pb.juniper_junos_interfaces.yml new file mode 100644 index 00000000..8aa9b620 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_interfaces.yml @@ -0,0 +1,64 @@ +- name: Functional Test - junos_interfaces module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + - name: Pre-clean - Delete test configuration if present + junipernetworks.junos.junos_interfaces: + config: + - name: ge-0/0/1 + units: + - name: 0 + state: deleted + ignore_errors: true + + - name: Apply test config with state merged + junipernetworks.junos.junos_interfaces: + config: + - name: ge-0/0/1 + description: "FT updated interface" + enabled: true + mtu: 1800 + units: + - name: 0 + description: "FT logical unit" + state: merged + register: merge_result + + - name: Gather current interface config + junipernetworks.junos.junos_interfaces: + state: gathered + register: gathered_result + + - name: Assert merged interface config applied + assert: + that: + - merge_result.changed is defined + - gathered_result.gathered is defined + - gathered_result.gathered | selectattr("name", "equalto", "ge-0/0/1") | list | length > 0 + + - name: Render config offline (no connection to device) + junipernetworks.junos.junos_interfaces: + config: + - name: ge-0/0/1 + description: Render test + state: rendered + register: render_result + + - name: Assert rendered config returned + assert: + that: + - render_result.rendered is defined + - render_result.rendered | length > 0 + + - name: Post-clean - Delete test configuration + junipernetworks.junos.junos_interfaces: + config: + - name: ge-0/0/1 + units: + - name: 0 + state: deleted + ignore_errors: true diff --git a/tests/junipernetworks.junos/pb.juniper_junos_l2_interfaces.yml b/tests/junipernetworks.junos/pb.juniper_junos_l2_interfaces.yml new file mode 100644 index 00000000..78d9c90c --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_l2_interfaces.yml @@ -0,0 +1,86 @@ +# Note: This functional test requires switching to be enabled on interfaces. + +- name: Functional Test - junos_l2_interfaces module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + - name: Pre-define required VLANs + junipernetworks.junos.junos_vlans: + config: + - name: v101 + vlan_id: 101 + - name: vlan30 + vlan_id: 30 + - name: vlan50 + vlan_id: 50 + state: merged + + - name: Pre-clean - Delete existing L2 config + junipernetworks.junos.junos_l2_interfaces: + config: + - name: ge-0/0/3 + - name: ge-0/0/4 + state: deleted + ignore_errors: true + + - name: Apply L2 config - merge access and trunk modes + 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 + register: merge_result + + - name: Assert L2 config merged + assert: + that: + - merge_result is defined + - merge_result.changed is defined + - merge_result.changed | bool == true + + - name: Gather current L2 interface config + junipernetworks.junos.junos_l2_interfaces: + state: gathered + register: gathered_result + + - name: Assert L2 config gathered + assert: + that: + - gathered_result.gathered | selectattr("name", "equalto", "ge-0/0/3") | list | length > 0 + - gathered_result.gathered | selectattr("name", "equalto", "ge-0/0/4") | list | length > 0 + + - name: Render L2 config offline + 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: rendered + register: render_result + + - name: Assert rendered L2 config + assert: + that: + - render_result.rendered is defined + - render_result.rendered | length > 0 + + - name: Post-clean - Delete L2 config + junipernetworks.junos.junos_l2_interfaces: + config: + - name: ge-0/0/3 + - name: ge-0/0/4 + state: deleted + ignore_errors: true diff --git a/tests/junipernetworks.junos/pb.juniper_junos_l3_interfaces.yml b/tests/junipernetworks.junos/pb.juniper_junos_l3_interfaces.yml new file mode 100644 index 00000000..f83b6d2e --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_l3_interfaces.yml @@ -0,0 +1,73 @@ +- name: Functional Test - junos_l3_interfaces module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + + - name: Pre-clean - Delete L3 logical interfaces if present + junos_l3_interfaces: + config: + - name: ge-0/0/1 + - name: ge-0/0/2 + state: deleted + ignore_errors: true + + - name: Apply L3 configuration (merge) + junos_l3_interfaces: + config: + - name: ge-0/0/1 + ipv4: + - address: 192.168.1.10/24 + ipv6: + - address: 2001:db8::1/64 + - name: ge-0/0/2 + ipv4: + - address: dhcp + state: merged + register: merge_result + + - name: Assert L3 config applied + assert: + that: + - merge_result.changed is defined + - merge_result.after | selectattr("name", "equalto", "ge-0/0/1") | list | length > 0 + - merge_result.after | selectattr("name", "equalto", "ge-0/0/2") | list | length > 0 + + - name: Gather L3 interfaces + junos_l3_interfaces: + state: gathered + register: gathered_result + + - name: Assert L3 interfaces gathered + assert: + that: + - gathered_result.gathered | selectattr("name", "equalto", "ge-0/0/1") | list | length > 0 + - gathered_result.gathered | selectattr("name", "equalto", "ge-0/0/2") | list | length > 0 + + - name: Render L3 config (offline) + junos_l3_interfaces: + config: + - name: ge-0/0/1 + ipv4: + - address: 192.168.1.10/24 + ipv6: + - address: 2001:db8::1/64 + state: rendered + register: render_result + + - name: Assert rendered config is present + assert: + that: + - render_result.rendered is defined + - render_result.rendered | length > 0 + + - name: Post-clean - Delete test L3 configuration + junos_l3_interfaces: + config: + - name: ge-0/0/1 + - name: ge-0/0/2 + state: deleted + ignore_errors: true diff --git a/tests/junipernetworks.junos/pb.juniper_junos_lacp.yml b/tests/junipernetworks.junos/pb.juniper_junos_lacp.yml new file mode 100644 index 00000000..51717b28 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_lacp.yml @@ -0,0 +1,55 @@ +- name: Functional Test - junos_lacp module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + + - name: Pre-clean - Delete existing global LACP config + junos_lacp: + state: deleted + ignore_errors: true + + - name: Merge global LACP attributes + junos_lacp: + config: + system_priority: 63 + # link_protection: revertive + state: merged + register: merge_result + + - name: Assert LACP config merged + assert: + that: + - merge_result.changed is defined + + - name: Gather global LACP config + junos_lacp: + state: gathered + register: gather_result + + - name: Assert gathered global LACP config + assert: + that: + - gather_result.gathered.system_priority == 63 + + - name: Render LACP config (offline) + junos_lacp: + config: + system_priority: 63 + link_protection: revertive + state: rendered + register: render_result + + - name: Assert rendered config is returned + assert: + that: + - render_result.rendered is defined + - render_result.rendered | length > 0 + + - name: Post-clean - Delete global LACP config + junos_lacp: + state: deleted + ignore_errors: true diff --git a/tests/junipernetworks.junos/pb.juniper_junos_lacp_interfaces.yml b/tests/junipernetworks.junos/pb.juniper_junos_lacp_interfaces.yml new file mode 100644 index 00000000..126abf23 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_lacp_interfaces.yml @@ -0,0 +1,71 @@ +--- +- name: Functional Test - junos_lacp_interfaces module + hosts: netconf_connection_testcases + gather_facts: false + connection: netconf + + tasks: + + - name: Pre-clean - Delete LACP attributes on ae0 + junipernetworks.junos.junos_lacp_interfaces: + config: + - name: ae0 + state: deleted + ignore_errors: true + + - name: Merge LACP configuration onto ae0 + junipernetworks.junos.junos_lacp_interfaces: + config: + - name: ae0 + period: fast + sync_reset: enable + system: + priority: 100 + mac: + address: 00:00:00:00:00:02 + state: merged + + - name: Replace LACP configuration on ae0 + junipernetworks.junos.junos_lacp_interfaces: + config: + - name: ae0 + period: slow + state: replaced + + - name: Override all LACP configuration on ae0 + junipernetworks.junos.junos_lacp_interfaces: + config: + - name: ae0 + system: + priority: 300 + mac: + address: 00:00:00:00:00:03 + state: overridden + + - name: Gather LACP interfaces + junipernetworks.junos.junos_lacp_interfaces: + state: gathered + register: gather_result + + - name: Extract gathered interface names + set_fact: + gathered_names: "{{ gather_result.gathered | map(attribute='name') | list }}" + + - name: Assert ae0 is present in gathered result + ansible.builtin.assert: + that: + - "'ae0' in gathered_names" + fail_msg: "Expected interface ae0 not found in gathered result" + success_msg: "Successfully found ae0 in gathered result" + + - name: Render platform-specific XML from input config + junipernetworks.junos.junos_lacp_interfaces: + config: + - name: ae0 + period: fast + sync_reset: enable + system: + priority: 100 + mac: + address: 00:00:00:00:00:02 + state: rendered diff --git a/tests/junipernetworks.junos/pb.juniper_junos_lag_interfaces.yml b/tests/junipernetworks.junos/pb.juniper_junos_lag_interfaces.yml new file mode 100644 index 00000000..05ef71cf --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_lag_interfaces.yml @@ -0,0 +1,45 @@ +- name: Functional Test - junos_lag_interfaces + hosts: junos_device + connection: ansible.netcommon.netconf + gather_facts: false + collections: + - junipernetworks.junos + + tasks: + + - name: GATHERED - Retrieve existing LAG configuration + junipernetworks.junos.junos_lag_interfaces: + state: gathered + register: result_gathered + + - name: Assert gathered LAG config is returned + assert: + that: + - result_gathered.gathered is defined + - result_gathered.gathered | type_debug == 'list' + + - name: RENDERED - Generate platform-specific XML config + junipernetworks.junos.junos_lag_interfaces: + state: rendered + 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 + register: result_rendered + + - name: Assert rendered LAG config is valid + assert: + that: + - result_rendered.rendered is defined + - result_rendered.rendered | length > 0 diff --git a/tests/junipernetworks.junos/pb.juniper_junos_lldp_global.yml b/tests/junipernetworks.junos/pb.juniper_junos_lldp_global.yml new file mode 100644 index 00000000..9d72de12 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_lldp_global.yml @@ -0,0 +1,75 @@ +- name: Functional Test - junos_lldp_global module + hosts: netconf_connection_testcases + connection: ansible.netcommon.netconf + gather_facts: false + collections: + - junipernetworks.junos + + tasks: + + - name: Merge LLDP global configuration + junipernetworks.junos.junos_lldp_global: + config: + interval: 10000 + address: 10.1.1.1 + transmit_delay: 400 + hold_multiplier: 10 + state: merged + register: merge_result + + - name: Assert LLDP global merge applied + assert: + that: + - merge_result.changed == true + + - name: Replace LLDP global configuration + junipernetworks.junos.junos_lldp_global: + config: + address: 20.2.2.2 + hold_multiplier: 5 + enabled: false + state: replaced + register: replace_result + + - name: Assert LLDP global replace applied + assert: + that: + - replace_result.changed == true + + - name: Gather LLDP global configuration + junipernetworks.junos.junos_lldp_global: + state: gathered + register: gather_result + + - name: Assert LLDP address is correctly configured + assert: + that: + - gather_result.gathered.address == "20.2.2.2" + - gather_result.gathered.hold_multiplier == 5 + - gather_result.gathered.enabled == false + + - name: Render LLDP global configuration to XML + junipernetworks.junos.junos_lldp_global: + config: + interval: 10000 + address: 10.1.1.1 + transmit_delay: 400 + hold_multiplier: 10 + state: rendered + register: render_result + + - name: Assert rendered LLDP config is valid + assert: + that: + - render_result.rendered is defined + - render_result.rendered | length > 0 + + - name: Delete LLDP global configuration + junipernetworks.junos.junos_lldp_global: + state: deleted + register: delete_result + + - name: Assert LLDP global config deleted + assert: + that: + - delete_result.changed == true diff --git a/tests/junipernetworks.junos/pb.juniper_junos_lldp_interfaces.yml b/tests/junipernetworks.junos/pb.juniper_junos_lldp_interfaces.yml new file mode 100644 index 00000000..8b36ea22 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_lldp_interfaces.yml @@ -0,0 +1,61 @@ +- name: Functional Test - junos_lldp_interfaces module + hosts: netconf_connection_testcases + connection: ansible.netcommon.netconf + gather_facts: false + tasks: + + - name: Pre-clean LLDP interface config + junipernetworks.junos.junos_lldp_interfaces: + config: + - name: ge-0/0/1 + - name: ge-0/0/2 + - name: ge-0/0/3 + state: deleted + ignore_errors: true + + - name: Merge LLDP interface configuration + junipernetworks.junos.junos_lldp_interfaces: + config: + - name: ge-0/0/1 + - name: ge-0/0/2 + enabled: false + state: merged + + - name: Replace LLDP interface configuration + junipernetworks.junos.junos_lldp_interfaces: + config: + - name: ge-0/0/2 + enabled: true + - name: ge-0/0/3 + enabled: false + state: replaced + + - name: Override LLDP interface configuration + junipernetworks.junos.junos_lldp_interfaces: + config: + - name: ge-0/0/3 + enabled: false + state: overridden + + - name: Gather current LLDP interface configuration + junipernetworks.junos.junos_lldp_interfaces: + state: gathered + register: lldp_interface_gather + + - name: Assert ge-0/0/3 is in gathered LLDP interfaces and disabled + ansible.builtin.assert: + that: + - lldp_interface_gather.gathered | selectattr("name", "equalto", "ge-0/0/3") | selectattr("enabled", "equalto", false) | list | length > 0 + fail_msg: "ge-0/0/3 with enabled: false not found in gathered result" + success_msg: "ge-0/0/3 is correctly disabled in LLDP interfaces" + + - name: Render LLDP interface configuration for offline validation + junipernetworks.junos.junos_lldp_interfaces: + config: + - name: ge-0/0/1 + - name: ge-0/0/2 + enabled: false + state: rendered + register: rendered_lldp + + diff --git a/tests/junipernetworks.junos/pb.juniper_junos_logging_global.yml b/tests/junipernetworks.junos/pb.juniper_junos_logging_global.yml new file mode 100644 index 00000000..76b47f18 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_logging_global.yml @@ -0,0 +1,195 @@ +- name: Functional Test - junos_logging_global + hosts: junos_device + gather_facts: no + connection: ansible.netcommon.netconf + + vars: + routing_instance_name: inst11 + logging_source_address: "{{ source_address }}" + logging_host_address: "{{ host_address }}" + + tasks: + + - name: Ensure routing instance exists + junipernetworks.junos.junos_config: + lines: + - "set routing-instances {{ routing_instance_name }} instance-type virtual-router" + comment: "Pre-create routing instance required for syslog" + update: merge + + - name: MERGED - Full logging 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: "{{ routing_instance_name }}" + source_address: "{{ logging_host_address }}" + routing_instance: "{{ routing_instance_name }}" + log_rotate_frequency: 45 + source_address: "{{ logging_source_address }}" + 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 + + - name: REPLACED - Replace logging 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: "{{ routing_instance_name }}" + source_address: "{{ logging_host_address }}" + users: + - name: "user1" + allow_duplicates: true + - name: "user2" + allow_duplicates: true + any: + level: "any" + user: + level: info + state: replaced + + - name: OVERRIDDEN - Override entire logging config + 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: "{{ routing_instance_name }}" + source_address: "{{ logging_host_address }}" + users: + - name: "user1" + allow_duplicates: true + - name: "user2" + allow_duplicates: true + any: + level: "any" + user: + level: info + state: overridden + + - name: GATHERED - Gather current logging config + junipernetworks.junos.junos_logging_global: + state: gathered + register: gathered_output + + - name: RENDERED - Render config into XML + junipernetworks.junos.junos_logging_global: + config: "{{ gathered_output.gathered }}" + state: rendered + + - name: PARSED - Load from parsed.cfg + junipernetworks.junos.junos_logging_global: + running_config: "{{ lookup('file', './parsed_configs/parsed_logging_global.cfg') }}" + state: parsed + + - name: DELETED - Delete all logging config + junipernetworks.junos.junos_logging_global: + config: {} + state: deleted diff --git a/tests/junipernetworks.junos/pb.juniper_junos_netconf.yml b/tests/junipernetworks.junos/pb.juniper_junos_netconf.yml new file mode 100644 index 00000000..862dab57 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_netconf.yml @@ -0,0 +1,30 @@ +- name: Functional Test - junos_netconf module + hosts: network_cli_testcases + gather_facts: false + connection: network_cli + collections: + - junipernetworks.junos + + tasks: + - name: Enable NETCONF service on port 830 + junipernetworks.junos.junos_netconf: + netconf_port: 830 + state: present + register: enable_result + + - name: Assert NETCONF service was enabled + assert: + that: + - enable_result.changed is defined + - enable_result.commands | length > 0 + + - name: Disable NETCONF service + junipernetworks.junos.junos_netconf: + state: absent + register: disable_result + + - name: Assert NETCONF service was disabled + assert: + that: + - disable_result.changed is defined + - disable_result.commands | length > 0 diff --git a/tests/junipernetworks.junos/pb.juniper_junos_ntp_global.yml b/tests/junipernetworks.junos/pb.juniper_junos_ntp_global.yml new file mode 100644 index 00000000..6593c1c0 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_ntp_global.yml @@ -0,0 +1,217 @@ +- name: Functional Test - junos_ntp_global module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + + - name: Pre-clean - Delete existing NTP global config + junipernetworks.junos.junos_ntp_global: + config: {} + state: deleted + register: preclean_result + - name: Pre-create required routing instances + junipernetworks.junos.junos_routing_instances: + config: + - name: "rt1" + type: "virtual-router" + - name: "rt2" + type: "virtual-router" + state: merged + + - name: Apply NTP global config using merged + 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 + register: merged_result + + - name: Assert merged result + assert: + that: + - merged_result.changed == true + + - name: Gather NTP global config + junipernetworks.junos.junos_ntp_global: + state: gathered + register: gathered_result + + - name: Assert gathered result + assert: + that: + - gathered_result.gathered is defined + + - name: Replace running NTP global config + 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 + register: replaced_result + + - name: Assert replaced result + assert: + that: + - replaced_result.changed == true + + - name: Override running NTP global config + 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 + register: overridden_result + + - name: Assert overridden result + assert: + that: + - overridden_result.changed == true + + - name: Delete NTP global configuration + junipernetworks.junos.junos_ntp_global: + config: {} + state: deleted + register: deleted_result + + - name: Assert deleted result + assert: + that: + - deleted_result.changed == true + + - name: Render NTP global 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: rendered + register: rendered_result + + - name: Assert rendered result + assert: + that: + - rendered_result.rendered is defined + + - name: Parse NTP global config + junipernetworks.junos.junos_ntp_global: + running_config: "{{ lookup('file', 'parsed_configs/parsed_ntp_global.cfg') }}" + state: parsed + register: parsed_result + + - name: Assert parsed result + assert: + that: + - parsed_result is defined + - parsed_result.parsed is defined \ No newline at end of file diff --git a/tests/junipernetworks.junos/pb.juniper_junos_ospf_interfaces.yml b/tests/junipernetworks.junos/pb.juniper_junos_ospf_interfaces.yml new file mode 100644 index 00000000..82d667a9 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_ospf_interfaces.yml @@ -0,0 +1,141 @@ +- name: Functional Test - junos_ospf_interfaces module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + - name: Pre-clean - Delete existing OSPF interface config + junipernetworks.junos.junos_ospf_interfaces: + config: + - name: "ge-0/0/2.0" + state: deleted + register: deleted_result + + - name: Assert deleted result + assert: + that: + - deleted_result is succeeded + + - name: Apply OSPF interface config using merged + junipernetworks.junos.junos_ospf_interfaces: + config: + - name: "ge-0/0/2.0" + address_family: + - afi: "ipv4" + processes: + area: + area_id: "0.0.0.2" + metric: 5 + priority: 3 + state: merged + register: merged_result + + - name: Assert merged result + assert: + that: + - merged_result.changed == true + + - name: Replace OSPF interface 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" + metric: 6 + priority: 6 + state: replaced + register: replaced_result + + - name: Assert replaced result + assert: + that: + - replaced_result.changed == true + + - name: Override OSPF interface config + junipernetworks.junos.junos_ospf_interfaces: + config: + - name: so-0/0/0.0 + router_id: 10.200.16.75 + address_family: + - afi: ipv4 + processes: + area: + area_id: 0.0.0.110 + bandwidth_based_metrics: + - bandwidth: 1g + metric: 5 + - bandwidth: 10g + metric: 40 + metric: 5 + priority: 3 + passive: true + - name: ge-0/0/2.0 + router_id: 10.200.16.75 + address_family: + - afi: ipv4 + processes: + area: + area_id: 0.0.0.3 + metric: 7 + priority: 4 + state: overridden + register: overridden_result + + + - name: Assert overridden result + assert: + that: + - overridden_result.changed == true + + - name: Delete specific OSPF interface config + junipernetworks.junos.junos_ospf_interfaces: + config: + - name: "ge-0/0/1.0" + state: deleted + register: deleted_specific_result + + - name: Gather OSPF interfaces config + junipernetworks.junos.junos_ospf_interfaces: + state: gathered + register: gathered_result + + - name: Assert gathered result + assert: + that: + - gathered_result.gathered is defined + + - name: Render 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" + metric: 5 + priority: 3 + state: rendered + register: rendered_result + + - name: Assert rendered output + assert: + that: + - rendered_result.rendered is defined + + + - name: Parse OSPF interfaces running config + junipernetworks.junos.junos_ospf_interfaces: + running_config: "{{ lookup('file', 'parsed_configs/parsed_ospf_interfaces.cfg') }}" + state: parsed + register: parsed_result + + - name: Assert parsed output + assert: + that: + - parsed_result.parsed is defined diff --git a/tests/junipernetworks.junos/pb.juniper_junos_ospfv2.yml b/tests/junipernetworks.junos/pb.juniper_junos_ospfv2.yml new file mode 100644 index 00000000..d3b8c810 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_ospfv2.yml @@ -0,0 +1,181 @@ +- name: Functional Test - junos_ospfv2 module + hosts: junos_device + gather_facts: false + connection: ansible.netcommon.netconf + + tasks: + + - name: DELETE - Reset before MERGED + junipernetworks.junos.junos_ospfv2: + config: [] + state: deleted + + - name: MERGED - Configure OSPFv2 instance + junipernetworks.junos.junos_ospfv2: + config: + - reference_bandwidth: 10g + areas: + - area_id: 0.0.0.100 + area_ranges: + - address: 10.200.17.0/24 + exact: true + restrict: true + override_metric: 2000 + - address: 10.200.15.0/24 + exact: true + restrict: true + override_metric: 2000 + 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 + + - name: DELETE - Reset before REPLACED + junipernetworks.junos.junos_ospfv2: + config: [] + state: deleted + + - name: REPLACED - Replace OSPFv2 instance + junipernetworks.junos.junos_ospfv2: + config: + - reference_bandwidth: 10g + areas: + - area_id: 0.0.0.100 + area_ranges: + - address: 10.200.17.0/24 + exact: true + restrict: true + - address: 10.200.16.0/24 + exact: true + restrict: true + override_metric: 1000 + 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: replaced + + - name: DELETE - Reset before OVERRIDDEN + junipernetworks.junos.junos_ospfv2: + config: [] + state: deleted + + - name: OVERRIDDEN - Override OSPFv2 instance + junipernetworks.junos.junos_ospfv2: + config: + - reference_bandwidth: 10g + areas: + - area_id: 0.0.0.110 + area_ranges: + - address: 20.200.17.0/24 + exact: true + restrict: true + override_metric: 2000 + - address: 20.200.15.0/24 + exact: true + restrict: true + override_metric: 2000 + stub: + default_metric: 200 + 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 + state: overridden + + - name: RENDERED - Render OSPFv2 config + junipernetworks.junos.junos_ospfv2: + config: + - reference_bandwidth: 10g + areas: + - area_id: 0.0.0.100 + area_ranges: + - address: 10.200.17.0/24 + exact: true + restrict: true + override_metric: 2000 + - address: 10.200.15.0/24 + exact: true + restrict: true + override_metric: 2000 + 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 + state: rendered + + - name: GATHERED - Get current OSPFv2 config + junipernetworks.junos.junos_ospfv2: + config: [] + state: gathered + register: ospf_gather + + - name: Show GATHERED + ansible.builtin.debug: + var: ospf_gather.gathered + + - name: PARSED - Parsed ospfv2 config from XML + junipernetworks.junos.junos_ospfv2: + running_config: "{{ lookup('file', './parsed_configs/parsed_ospfv2.cfg') }}" + state: parsed + register: ospf_parsed + + - name: Show PARSED + ansible.builtin.debug: + var: ospf_parsed.parsed diff --git a/tests/junipernetworks.junos/pb.juniper_junos_ospfv3.yml b/tests/junipernetworks.junos/pb.juniper_junos_ospfv3.yml new file mode 100644 index 00000000..20ed913f --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_ospfv3.yml @@ -0,0 +1,88 @@ +- name: Functional Test - junos_ospfv3 module + hosts: junos_device + gather_facts: false + connection: ansible.netcommon.netconf + + tasks: + - name: DELETE - Reset before test + junipernetworks.junos.junos_ospfv3: + config: [] + state: deleted + + - name: MERGED - Merge Junos OSPFv3 config + junipernetworks.junos.junos_ospfv3: + config: + - router_id: 10.200.16.75 + areas: + - area_id: 0.0.0.100 + interfaces: + - metric: 5 + name: so-0/0/0.0 + priority: 3 + - metric: 6 + name: so-0/0/1.0 + priority: 2 + stub: + default_metric: 200 + set: true + state: merged + + - name: REPLACED - Replace Junos OSPFv3 config + junipernetworks.junos.junos_ospfv3: + config: + - router_id: 10.200.16.75 + areas: + - area_id: 0.0.0.100 + interfaces: + - name: so-0/0/0.0 + state: replaced + + - name: OVERRIDDEN - Override Junos OSPFv3 config + junipernetworks.junos.junos_ospfv3: + config: + - router_id: 10.200.16.75 + 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 + + - name: GATHERED - Get current OSPFv3 configuration + junipernetworks.junos.junos_ospfv3: + config: [] + state: gathered + register: gathered_ospfv3 + + - name: PARSED - Parse structured config from XML file + junipernetworks.junos.junos_ospfv3: + running_config: "{{ lookup('file', './parsed_configs/parsed_ospfv3.cfg') }}" + state: parsed + + - name: RENDERED - Render OSPFv3 config into XML + junipernetworks.junos.junos_ospfv3: + config: + - router_id: 10.200.16.75 + areas: + - area_id: 0.0.0.100 + interfaces: + - metric: 5 + name: so-0/0/0.0 + priority: 3 + - metric: 6 + name: so-0/0/1.0 + priority: 2 + stub: + default_metric: 200 + set: true + state: rendered diff --git a/tests/junipernetworks.junos/pb.juniper_junos_package.yml b/tests/junipernetworks.junos/pb.juniper_junos_package.yml new file mode 100644 index 00000000..9c508742 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_package.yml @@ -0,0 +1,63 @@ +- name: Functional Test - junos_package module + hosts: localhost + gather_facts: false + collections: + - junipernetworks.junos + + tasks: + + - name: Install local package on remote device + junipernetworks.junos.junos_package: + src: "{{ package_src }}" + reboot: true + provider: + host: xx.xx.xx.xx + username: xx + password: xx + port: 830 + transport: netconf + register: result_install + + - name: Wait for device to come back online after reboot (TCP check) + wait_for: + host: xx.xx.xx.xx + port: 830 + delay: 30 + timeout: 300 + + - name: Wait until NETCONF service is ready (SSH banner check) + wait_for: + host: xx.xx.xx.xx + port: 830 + search_regex: "SSH" + timeout: 300 + delay: 10 + sleep: 5 + register: wait_result + until: wait_result is succeeded + retries: 10 + delay: 10 + + - name: Assert install task ran + assert: + that: + - result_install is defined + + - name: Install local package without reboot + junipernetworks.junos.junos_package: + src: /tmp/junos-vsrx-12.1X46-D10.2-domestic.tgz + reboot: false + provider: + host: xx.xx.xx.xx + username: xxx + password: xxx + port: 830 + transport: netconf + register: result_noreboot + + - name: Assert no-reboot task ran + assert: + that: + - result_noreboot is defined + + diff --git a/tests/junipernetworks.junos/pb.juniper_junos_ping.yml b/tests/junipernetworks.junos/pb.juniper_junos_ping.yml new file mode 100644 index 00000000..315571b8 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_ping.yml @@ -0,0 +1,67 @@ +- name: Functional Test - junos_ping module + hosts: network_cli_testcases + gather_facts: false + connection: network_cli + collections: + - junipernetworks.junos + + tasks: + + - name: Test reachability to target + junipernetworks.junos.junos_ping: + dest: xx.xx.xx.xx + register: ping_default + + - name: Assert default ping worked + assert: + that: + - ping_default.packet_loss is defined + + - name: Test reachability to target using source and size set + junipernetworks.junos.junos_ping: + dest: xx.xx.xx.xx + size: 1024 + ttl: 128 + register: ping_source_ttl + + - name: Assert source TTL ping worked + assert: + that: + - ping_source_ttl.packet_loss is defined + + - name: Test unreachability to target using interval + junipernetworks.junos.junos_ping: + dest: xx.xx.xx.xx + interval: 3 + state: present + register: ping_absent + + - name: "Assert unreachable ping worked (state: absent)" + assert: + that: + - ping_absent.packet_loss is defined + + - name: Test reachability to target setting count and interface + junipernetworks.junos.junos_ping: + dest: xx.xx.xx.xx + interface: fxp0 + count: 20 + size: 512 + register: ping_iface + + - name: Assert ping with count/interface worked + assert: + that: + - ping_iface.packet_loss is defined + + - name: Test reachability to target using do-not-fragment and rapid + junipernetworks.junos.junos_ping: + dest: xx.xx.xx.xx + df_bit: true + rapid: true + register: ping_df_rapid + + - name: Assert ping with DF bit and rapid worked + assert: + that: + - ping_df_rapid.packet_loss is defined diff --git a/tests/junipernetworks.junos/pb.juniper_junos_prefix_lists.yml b/tests/junipernetworks.junos/pb.juniper_junos_prefix_lists.yml new file mode 100644 index 00000000..95fca784 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_prefix_lists.yml @@ -0,0 +1,118 @@ +- name: Functional Test - junos_prefix_lists module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + - name: Pre-clean - Delete all prefix-lists if present + junos_prefix_lists: + state: deleted + ignore_errors: true + + - name: Apply prefix-lists using merged + 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 + register: merged_result + + - name: Assert merged result + assert: + that: + - merged_result.changed == true + + - name: Gather prefix-lists + junos_prefix_lists: + state: gathered + register: gathered_result + + - name: Assert gathered prefix-lists + assert: + that: + - gathered_result.gathered is defined + - gathered_result.gathered | length > 0 + + - name: Replace prefix-list Test2 with new prefixes + junos_prefix_lists: + config: + - name: Test2 + address_prefixes: + - 172.16.4.32 + - 172.16.8.32 + - 172.16.9.32 + state: replaced + register: replaced_result + + - name: Assert replaced result + assert: + that: + - replaced_result.changed == true + + - name: Override prefix-lists with only Test2 entries + 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 + register: overridden_result + + - name: Assert overridden result + assert: + that: + - overridden_result.changed == true + + - name: Render prefix-lists offline + 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 + register: rendered_result + + - name: Assert rendered output + assert: + that: + - rendered_result.rendered is defined + - rendered_result.rendered | length > 0 + + - name: Post-clean - Delete specific prefix-lists + junos_prefix_lists: + config: + - name: Test1 + - name: Test2 + state: deleted + register: deleted_result + + - name: Assert deleted specific prefix-lists + assert: + that: + - deleted_result.changed == true + + - name: Final clean - Delete all prefix-lists + junos_prefix_lists: + state: deleted + ignore_errors: true diff --git a/tests/junipernetworks.junos/pb.juniper_junos_routing_instances.yml b/tests/junipernetworks.junos/pb.juniper_junos_routing_instances.yml new file mode 100644 index 00000000..710e7f53 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_routing_instances.yml @@ -0,0 +1,146 @@ +- name: Functional Test - junos_routing_instances module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + + - name: Pre-clean - Create required policy statements + junipernetworks.junos.junos_config: + lines: + - set policy-options policy-statement test-policy term t1 then reject + - set policy-options policy-statement test-policy-1 term t1 then reject + comment: "Pre-create dummy policies needed for routing instances FT" + + - name: Pre-clean - Delete test routing instances + junipernetworks.junos.junos_routing_instances: + config: + - name: "test" + - name: "forwardinst" + - name: "vtest1" + state: deleted + + - name: Apply routing instances using merged + 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 + register: merged_result + + - name: Assert merged result + assert: + that: + - merged_result.changed == true + + - name: Gather routing instances + junipernetworks.junos.junos_routing_instances: + state: gathered + register: gathered_result + + - name: Assert gathered result + assert: + that: + - gathered_result.gathered is defined + + - name: Replace routing instance configuration + junipernetworks.junos.junos_routing_instances: + config: + - 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 + register: replaced_result + + - name: Assert replaced result + assert: + that: + - replaced_result.changed == true + + + + - name: Delete specific routing instance + junipernetworks.junos.junos_routing_instances: + config: + - name: "test" + state: deleted + register: delete_specific_result + + - name: Assert specific routing instance deleted + assert: + that: + - delete_specific_result.changed == true + + - name: Final clean - Delete test routing instances only + junipernetworks.junos.junos_routing_instances: + config: + - name: "forwardinst" + - name: "vtest1" + state: deleted + register: delete_all_result + + - name: Assert all routing instances deleted + assert: + that: + - delete_all_result.changed == true + + - name: Render 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" + state: rendered + register: rendered_result + + - name: Assert rendered configuration + assert: + that: + - rendered_result.rendered is defined + + - name: Parse routing instance running configuration + junipernetworks.junos.junos_routing_instances: + running_config: "{{ lookup('file', 'parsed_configs/parsed_routing_instances.cfg') }}" + state: parsed + register: parsed_result + + - name: Assert parsed result + assert: + that: + - parsed_result.parsed is defined diff --git a/tests/junipernetworks.junos/pb.juniper_junos_routing_options.yml b/tests/junipernetworks.junos/pb.juniper_junos_routing_options.yml new file mode 100644 index 00000000..71e4157b --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_routing_options.yml @@ -0,0 +1,105 @@ +- name: Functional Test - junos_routing_options module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + + - name: Pre-clean - Delete existing routing options + junipernetworks.junos.junos_routing_options: + config: {} + state: deleted + + - name: Apply routing options using merged + junipernetworks.junos.junos_routing_options: + config: + autonomous_system: + as_number: 2 + asdot_notation: true + state: merged + register: merged_result + + - name: Assert merged result + assert: + that: + - merged_result.changed == true + + - name: Gather routing options + junipernetworks.junos.junos_routing_options: + state: gathered + register: gathered_result + + - name: Assert gathered result + assert: + that: + - gathered_result.gathered is defined + + - name: Replace routing options configuration + junipernetworks.junos.junos_routing_options: + config: + autonomous_system: + as_number: 2 + asdot_notation: true + router_id: "1.1.1.1" + state: replaced + register: replaced_result + + - name: Assert replaced result + assert: + that: + - replaced_result.changed == true + + - name: Override routing options configuration + junipernetworks.junos.junos_routing_options: + config: + autonomous_system: + as_number: 2 + asdot_notation: true + router_id: "2.2.2.2" + state: overridden + register: overridden_result + + - name: Assert overridden result + assert: + that: + - overridden_result.changed == true + + - name: Render routing options configuration + junipernetworks.junos.junos_routing_options: + config: + autonomous_system: + as_number: 2 + asdot_notation: true + loops: 4 + router_id: "12.12.12.12" + state: rendered + register: rendered_result + + - name: Assert rendered configuration + assert: + that: + - rendered_result.rendered is defined + + - name: Parse routing options running configuration + junipernetworks.junos.junos_routing_options: + running_config: "{{ lookup('file', 'parsed_configs/parsed_routing_options.cfg') }}" + state: parsed + register: parsed_result + + - name: Assert parsed result + assert: + that: + - parsed_result.parsed is defined + + - name: Final clean - Delete all routing options + junipernetworks.junos.junos_routing_options: + config: {} + state: deleted + register: delete_result + + - name: Assert routing options deleted + assert: + that: + - delete_result.changed == true diff --git a/tests/junipernetworks.junos/pb.juniper_junos_rpc.yml b/tests/junipernetworks.junos/pb.juniper_junos_rpc.yml new file mode 100644 index 00000000..956f13e8 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_rpc.yml @@ -0,0 +1,48 @@ +- name: Functional Test - junos_rpc module + hosts: netconf_connection_testcases + gather_facts: false + connection: ansible.netcommon.netconf + collections: + - junipernetworks.junos + + tasks: + + - name: Collect interface information using RPC + junipernetworks.junos.junos_rpc: + rpc: get-interface-information + args: + interface-name: em0 + media: true + register: interface_info + + - name: Assert interface information RPC returned XML + assert: + that: + - interface_info.xml is defined + + - name: Get system information using RPC + junipernetworks.junos.junos_rpc: + rpc: get-system-information + register: system_info + + - name: Assert system information RPC returned XML + assert: + that: + - system_info.xml is defined + + - name: Load configuration using RPC (requires file on device) + junipernetworks.junos.junos_rpc: + rpc: load-configuration + attrs: + action: override + format: text + url: /tmp/config.conf + register: config_load + when: false + + - name: Assert load configuration RPC executed + assert: + that: + - config_load.xml is defined + when: false + diff --git a/tests/junipernetworks.junos/pb.juniper_junos_scp.yml b/tests/junipernetworks.junos/pb.juniper_junos_scp.yml new file mode 100644 index 00000000..f6441cf8 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_scp.yml @@ -0,0 +1,71 @@ +- name: Functional Test - junos_scp module + hosts: localhost + connection: local + gather_facts: false + collections: + - junipernetworks.junos + + vars: + scp_src_file: "./files/test.tgz" + scp_dest_dir: "/tmp/" + scp_custom_ssh_config: "/home/user/customsshconfig" + + tasks: + + - name: "Pre-check - Ensure src file exists locally" + ansible.builtin.stat: + path: "{{ scp_src_file }}" + register: file_check + + - name: "Abort if test source file is not found" + ansible.builtin.fail: + msg: "Source file for SCP test not found at {{ scp_src_file }}" + when: not file_check.stat.exists + + - name: "TEST 1 - Upload local file to home directory on remote device" + junipernetworks.junos.junos_scp: + src: "{{ scp_src_file }}" + register: result_upload_home + + - name: "ASSERT 1 - Upload to home succeeded" + ansible.builtin.assert: + that: + - result_upload_home is defined + - result_upload_home.changed is true + + - name: "TEST 2 - Upload local file to /tmp directory on remote device" + junipernetworks.junos.junos_scp: + src: "{{ scp_src_file }}" + dest: "{{ scp_dest_dir }}" + register: result_upload_tmp + + - name: "ASSERT 2 - Upload to /tmp succeeded" + ansible.builtin.assert: + that: + - result_upload_tmp is defined + - result_upload_tmp.changed is true + + - name: "TEST 3 - Download file from remote device" + junipernetworks.junos.junos_scp: + src: "{{ scp_dest_dir }}test.tgz" + remote_src: true + register: result_download + + - name: "ASSERT 3 - Download from device succeeded" + ansible.builtin.assert: + that: + - result_download is defined + - result_download.changed is true + + - name: "TEST 4 - Download using custom SSH config" + junipernetworks.junos.junos_scp: + src: "{{ scp_dest_dir }}test.tgz" + remote_src: true + ssh_config: "{{ scp_custom_ssh_config }}" + register: result_ssh_config + + - name: "ASSERT 4 - Download with custom SSH config succeeded" + ansible.builtin.assert: + that: + - result_ssh_config is defined + - result_ssh_config.changed is true diff --git a/tests/junipernetworks.junos/pb.juniper_junos_security_policies.yml b/tests/junipernetworks.junos/pb.juniper_junos_security_policies.yml new file mode 100644 index 00000000..bf1b3ca7 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_security_policies.yml @@ -0,0 +1,27 @@ +- name: Functional Test - junos_security_policies (parsed and rendered only) + hosts: junos_device + gather_facts: no + connection: ansible.netcommon.netconf + + tasks: + - name: Render security policy config + junipernetworks.junos.junos_security_policies: + config: + global: + policies: + - name: test_glob_1 + match: + application: + any: true + source_address: + any_ipv6: true + destination_address: + any_ipv6: true + then: + deny: true + state: rendered + + - name: Parse from saved running config + junipernetworks.junos.junos_security_policies: + running_config: "{{ lookup('file', './parsed_configs/parsed_security_policies.cfg') }}" + state: parsed diff --git a/tests/junipernetworks.junos/pb.juniper_junos_security_policies_global.yml b/tests/junipernetworks.junos/pb.juniper_junos_security_policies_global.yml new file mode 100644 index 00000000..ec835f3f --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_security_policies_global.yml @@ -0,0 +1,37 @@ +- name: Functional Test - junos_security_policies_global (parsed, rendered, gathered) + hosts: junos_device + gather_facts: no + connection: netconf + + tasks: + + - name: PARSED - Parse running config from local file + junipernetworks.junos.junos_security_policies_global: + running_config: "{{ lookup('file', './parsed_configs/parsed_security_policies_global.cfg') }}" + state: parsed + + - name: RENDERED - Render the provided config + 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: rendered + + diff --git a/tests/junipernetworks.junos/pb.juniper_junos_security_zones.yml b/tests/junipernetworks.junos/pb.juniper_junos_security_zones.yml new file mode 100644 index 00000000..919e8314 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_security_zones.yml @@ -0,0 +1,41 @@ +- name: Functional Test - junos_security_zones module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + + - name: Render Security Zone config to XML + junipernetworks.junos.junos_security_zones: + config: + zones: + - name: trust + description: "Trusted zone" + interfaces: + - ge-0/0/1.0 + host_inbound_traffic: + system_services: + - name: ssh + - name: ping + state: rendered + register: result_rendered + + - name: Assert rendered output + assert: + that: + - result_rendered.rendered is defined + - result_rendered.changed == false + + - name: Parse Security Zone config from file + junipernetworks.junos.junos_security_zones: + running_config: "{{ lookup('file', 'parsed_configs/parsed_security_zones.cfg') }}" + state: parsed + register: result_parsed + + - name: Assert parsed zone config + assert: + that: + - result_parsed.parsed is defined + - result_parsed.changed == false diff --git a/tests/junipernetworks.junos/pb.juniper_junos_snmp_server.yml b/tests/junipernetworks.junos/pb.juniper_junos_snmp_server.yml new file mode 100644 index 00000000..a8afd50c --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_snmp_server.yml @@ -0,0 +1,152 @@ +- name: Functional Test - junos_snmp_server (all states) + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + - name: Ensure routing instances clv1 and clv2 exist + junipernetworks.junos.junos_routing_instances: + config: + - name: clv1 + type: virtual-router + - name: clv2 + type: virtual-router + state: merged + + - name: Render SNMP server configuration (dry-run XML) + junipernetworks.junos.junos_snmp_server: + config: + arp: + set: true + host_name_resolution: true + routing_instance_access: + set: true + access_lists: + - clv1 + - clv2 + state: rendered + register: result_rendered + + - name: Assert rendered SNMP config + assert: + that: + - result_rendered.rendered is defined + - result_rendered.changed == false + + - name: Parse SNMP server config from XML + junipernetworks.junos.junos_snmp_server: + running_config: "{{ lookup('file', 'parsed_configs/parsed_snmp.cfg') }}" + state: parsed + register: result_parsed + + - name: Assert parsed SNMP config + assert: + that: + - result_parsed.parsed is defined + - result_parsed.changed == false + + - name: Merge SNMP server configuration + junipernetworks.junos.junos_snmp_server: + config: + arp: + set: true + host_name_resolution: true + client_lists: + - 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: + set: true + access_lists: + - clv1 + - clv2 + state: merged + register: result_merge + + - name: Assert merged SNMP config + assert: + that: + - result_merge.changed is defined + + - name: Replace SNMP server 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 + register: result_replaced + + - name: Assert replaced SNMP config + assert: + that: + - result_replaced.changed is defined + + - name: Override SNMP server 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 + register: result_overridden + + - name: Assert overridden SNMP config + assert: + that: + - result_overridden.changed is defined + + - name: Gather SNMP server configuration from device + junipernetworks.junos.junos_snmp_server: + state: gathered + register: result_gathered + + - name: Assert gathered SNMP config + assert: + that: + - result_gathered.gathered is defined + - result_gathered.changed == false + + - name: Delete SNMP server configuration + junipernetworks.junos.junos_snmp_server: + config: {} + state: deleted + register: result_deleted + + - name: Assert deleted SNMP config + assert: + that: + - result_deleted.changed is defined + diff --git a/tests/junipernetworks.junos/pb.juniper_junos_static_routes.yml b/tests/junipernetworks.junos/pb.juniper_junos_static_routes.yml new file mode 100644 index 00000000..373e6326 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_static_routes.yml @@ -0,0 +1,33 @@ +- name: Functional Test - junos_static_routes (safe states only) + hosts: netconf_connection_testcases + connection: netconf + gather_facts: no + + tasks: + + - name: 1. Render static route config for 192.168.16.0/24 โ†’ 172.16.1.2 + junipernetworks.junos.junos_static_routes: + config: + - vrf: default + address_families: + - afi: ipv4 + routes: + - dest: 192.168.16.0/24 + next_hop: + - forward_router_address: 172.16.1.2 + state: rendered + register: rendered_output + + - name: Debug rendered config + debug: + var: rendered_output.rendered + + - name: 2. Parse running config from parsed_static_routes.cfg + junipernetworks.junos.junos_static_routes: + running_config: "{{ lookup('file', 'parsed_configs/parsed_static_routes.cfg') }}" + state: parsed + register: parsed_output + + - name: Debug parsed output + debug: + var: parsed_output.parsed diff --git a/tests/junipernetworks.junos/pb.juniper_junos_system.yml b/tests/junipernetworks.junos/pb.juniper_junos_system.yml new file mode 100644 index 00000000..ad001c8f --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_system.yml @@ -0,0 +1,73 @@ +- name: Functional Test - junos_system module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + + - name: Pre-clean - Remove system configuration + junipernetworks.junos.junos_system: + hostname: junos01 + domain_name: test.example.com + domain_search: + - ansible.com + - redhat.com + - juniper.net + name_servers: + - 8.8.8.8 + - 8.8.4.4 + state: absent + register: preclean_result + + - name: Assert pre-clean result + assert: + that: + - preclean_result is not failed + + - name: Configure hostname, domain name, and domain search + junipernetworks.junos.junos_system: + hostname: junos01 + domain_name: test.example.com + domain_search: + - ansible.com + - redhat.com + - juniper.net + register: configure_hostname_domain + + - name: Assert hostname and domain name configured + assert: + that: + - configure_hostname_domain.changed == true + + - name: Configure name servers + junipernetworks.junos.junos_system: + name_servers: + - 8.8.8.8 + - 8.8.4.4 + register: configure_nameservers + + - name: Assert name servers configured + assert: + that: + - configure_nameservers.changed == true + + - name: Cleanup - Remove system configuration + junipernetworks.junos.junos_system: + hostname: junos01 + domain_name: test.example.com + domain_search: + - ansible.com + - redhat.com + - juniper.net + name_servers: + - 8.8.8.8 + - 8.8.4.4 + state: absent + register: cleanup_result + + - name: Assert final clean-up + assert: + that: + - cleanup_result.changed == true diff --git a/tests/junipernetworks.junos/pb.juniper_junos_user.yml b/tests/junipernetworks.junos/pb.juniper_junos_user.yml new file mode 100644 index 00000000..24622709 --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_user.yml @@ -0,0 +1,48 @@ +# Please ensure the 'passlib' library is installed before running this test (pip install passlib). + +--- +- name: Functional Test - junos_user module + hosts: netconf_connection_testcases + gather_facts: false + connection: ansible.netcommon.netconf + + tasks: + - name: Ensure test user is absent before test + junipernetworks.junos.junos_user: + name: ansible_test_user + state: absent + ignore_errors: true + + - name: Create a new user account with optional SSH key + junipernetworks.junos.junos_user: + name: ansible_test_user + role: super-user + sshkey: "{{ user_ssh_key | default(omit) }}" + full_name: "Ansible Test User" + state: present + # Note: Provide SSH key using: + # ansible-playbook pb.juniper_junos_user.yml -e "user_ssh_key={{ lookup('file', '~/.ssh/id_rsa.pub') }}" + + - name: Set user password (SHA-512 hashed) + junipernetworks.junos.junos_user: + name: ansible_test_user + role: super-user + encrypted_password: "{{ 'testpass123' | password_hash('sha512') }}" + state: present + + - name: Create a list of additional users + junipernetworks.junos.junos_user: + aggregate: + - { name: test_user1, full_name: "Operator User", role: operator, state: present } + - { name: test_user2, full_name: "ReadOnly User", role: read-only, state: present } + + - name: Delete additional users + junipernetworks.junos.junos_user: + aggregate: + - { name: test_user1, full_name: "Operator User", role: operator, state: absent } + - { name: test_user2, full_name: "ReadOnly User", role: read-only, state: absent } + + - name: Remove the test user account + junipernetworks.junos.junos_user: + name: ansible_test_user + state: absent diff --git a/tests/junipernetworks.junos/pb.juniper_junos_vlans.yml b/tests/junipernetworks.junos/pb.juniper_junos_vlans.yml new file mode 100644 index 00000000..6e331a3f --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_vlans.yml @@ -0,0 +1,49 @@ + +- name: Functional Test - junos_vlans (read-only states) + hosts: netconf_connection_testcases + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + + - name: Render VLAN configuration (dry-run XML) + junipernetworks.junos.junos_vlans: + config: + - name: vlan1 + vlan_id: 1 + - name: vlan2 + vlan_id: 2 + l3_interface: irb.12 + state: rendered + register: result_rendered + + - name: Assert rendered VLAN config + assert: + that: + - result_rendered.rendered is defined + - result_rendered.changed == false + + - name: Gather VLAN configuration from device + junipernetworks.junos.junos_vlans: + state: gathered + register: result_gathered + + - name: Assert gathered VLAN config + assert: + that: + - result_gathered.gathered is defined + - result_gathered.changed == false + + - name: Parse VLAN config from XML file + junipernetworks.junos.junos_vlans: + running_config: "{{ lookup('file', 'parsed_configs/parsed_junos_vlans.cfg') }}" + state: parsed + register: result_parsed + + - name: Assert parsed VLAN config + assert: + that: + - result_parsed.parsed is defined + - result_parsed.changed == false diff --git a/tests/junipernetworks.junos/pb.juniper_junos_vrf.yml b/tests/junipernetworks.junos/pb.juniper_junos_vrf.yml new file mode 100644 index 00000000..1af69e1a --- /dev/null +++ b/tests/junipernetworks.junos/pb.juniper_junos_vrf.yml @@ -0,0 +1,69 @@ +- name: Functional Test - junos_vrf module + hosts: junos_device + gather_facts: false + connection: netconf + collections: + - junipernetworks.junos + + tasks: + - name: Pre-clean conflicting routing-instances + junipernetworks.junos.junos_config: + lines: + - delete routing-instances test-1 + - delete routing-instances test-2 + comment: "Cleanup existing VRFs" + + - name: Preconfigure required interfaces + junipernetworks.junos.junos_config: + lines: + - set interfaces ge-0/0/2.0 family inet address 192.0.2.2/24 + - set interfaces ge-0/0/3.0 family inet address 192.0.2.3/24 + - set interfaces ge-0/0/4.0 family inet address 192.0.2.4/24 + - set interfaces ge-0/0/5.0 family inet address 192.0.2.5/24 + comment: "Ensure full logical units configured" + + - name: Deactivate VRF test-1 + junipernetworks.junos.junos_vrf: + name: test-1 + active: false + rd: 192.0.2.1:10 + target: target:65514:113 + interfaces: + - ge-0/0/3.0 + - ge-0/0/2.0 + description: test-vrf-1 + register: deactivate_result + + - name: Assert VRF test-1 deactivated + assert: + that: deactivate_result.changed == true + + - name: Remove VRF test-1 + junipernetworks.junos.junos_vrf: + name: test-1 + description: test-vrf-1 + interfaces: + - ge-0/0/3.0 + - ge-0/0/2.0 + rd: 192.0.2.1:10 + target: target:65514:113 + state: absent + register: remove_test1 + + - name: Assert VRF test-1 removed + assert: + that: remove_test1.changed == true + + - name: Remove VRF test-2 + junipernetworks.junos.junos_vrf: + name: test-2 + description: test-vrf-2 + interfaces: + - ge-0/0/4.0 + - ge-0/0/5.0 + rd: 192.0.2.2:10 + target: target:65515:114 + state: absent + register: remove_test2 + + diff --git a/tests/junipernetworks.junos/run_all_tests.sh b/tests/junipernetworks.junos/run_all_tests.sh new file mode 100755 index 00000000..70a09558 --- /dev/null +++ b/tests/junipernetworks.junos/run_all_tests.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +echo "Starting execution of all Ansible Junos playbooks..." +echo "-----------------------------------------------------" + +# File to store passed test logs +PASS_LOG="junos_passed_tests.log" +> "$PASS_LOG" # Clear previous contents + +# Loop through all *.yml playbooks +for file in pb.juniper_junos_*.yml; do + echo "Running $file" + ansible-playbook -i inventory "$file" + status=$? + + if [ $status -ne 0 ]; then + echo "โŒ $file failed with status $status" + else + echo "โœ… $file completed successfully" + echo "$file PASSED at $(date)" >> "$PASS_LOG" + fi + + echo "-----------------------------------------------------" +done + +echo "All playbooks processed." +echo "Passed test results saved to $PASS_LOG" diff --git a/tests/pb.juniper_junos_command.yml b/tests/pb.juniper_junos_command.yml index d51c1725..6c307835 100644 --- a/tests/pb.juniper_junos_command.yml +++ b/tests/pb.juniper_junos_command.yml @@ -140,3 +140,47 @@ - test8.results[0].msg == "The command executed successfully." - test8.results[1].command == "show version" - test8.results[1].msg == "The command executed successfully." + + + - name: TEST 9 - Multi-command text output + juniper.device.command: + commands: + - "show system uptime" + - "show version" + formats: + - "text" + - "text" + register: test9 + + - name: Check TEST 9 - Ensure output for both commands exists + ansible.builtin.assert: + that: + - test9.results[0].stdout is defined + - test9.results[1].stdout is defined + + - name: Ensure output directory exists + ansible.builtin.file: + path: "{{ playbook_dir }}/out" + state: directory + mode: '0755' + delegate_to: localhost + run_once: true + + - name: TEST 10 - Save text output of commands to dest_dir + juniper.device.command: + commands: + - "show version" + - "show interfaces terse" + format: text + dest_dir: "{{ playbook_dir }}/out" + register: test12 + + - name: Check TEST 10 - Command execution status + ansible.builtin.assert: + that: + - test12.results[0].msg == "The command executed successfully." + - test12.results[1].msg == "The command executed successfully." + + + + \ No newline at end of file diff --git a/tests/pb.juniper_junos_config.yml b/tests/pb.juniper_junos_config.yml index a7021f54..b1e550e7 100644 --- a/tests/pb.juniper_junos_config.yml +++ b/tests/pb.juniper_junos_config.yml @@ -4,8 +4,8 @@ gather_facts: false tasks: -################ - - name: Retrieve the committed configuration + + - name: TEST 1 - Retrieve the committed configuration juniper.device.config: retrieve: 'committed' diff: false @@ -19,8 +19,8 @@ ansible.builtin.assert: that: - test1.config -################ - - name: Append .foo to the hostname using private config mode. + + - name: TEST 2 - Append .foo to the hostname using private config mode. juniper.device.config: config_mode: 'private' load: 'merge' @@ -35,8 +35,8 @@ ansible.builtin.assert: that: - test2.diff_lines -################ - - name: Rollback to the previous config. + + - name: TEST 3 - Rollback to the previous config. juniper.device.config: config_mode: 'private' rollback: 1 @@ -48,12 +48,11 @@ ansible.builtin.assert: that: - test3.diff_lines -################# + - name: Save rescue configuration juniper.device.command: commands: "request system configuration rescue save" - formats: - - "xml" + formats: ["xml"] - name: Configure syslog configuration juniper.device.config: @@ -62,20 +61,22 @@ - "set system syslog file TEST any any" comment: "Configured system services" - - name: Rollback to the rescue config. + - name: Rollback to the rescue config juniper.device.config: rollback: 'rescue' register: test4 + - name: Check TEST 4 ansible.builtin.assert: that: - test4.diff_lines + - name: Clean up TEST 4 ansible.builtin.file: path: out state: absent -############### - - name: Configure system services. + + - name: Configure system services juniper.device.config: config_mode: 'private' load: 'merge' @@ -83,7 +84,7 @@ - "set system services netconf ssh" comment: "Configured system services" - - name: Retrieve [edit system services] of current committed config. + - name: TEST 5 - Retrieve [edit system services] of current committed config juniper.device.config: retrieve: 'committed' filter: 'system/services' @@ -97,11 +98,10 @@ - name: Check TEST 5 ansible.builtin.assert: that: - - test5.failed == False + - test5.failed == false - "'system {' in test5.config_lines" -################# - - name: Confirm the previous commit with a commit check (but no commit) + - name: TEST 6 - Confirm the previous commit with a commit check (no commit) juniper.device.config: check: true diff: false @@ -111,11 +111,9 @@ - name: Check TEST 6 ansible.builtin.assert: that: - test6.changed == False + - test6.changed == false -################# - - - name: Confirm the commit with a commit sync + - name: TEST 7 - Confirm the commit with a commit sync juniper.device.config: check: true diff: false @@ -126,11 +124,9 @@ - name: Check TEST 7 ansible.builtin.assert: that: - - test7.changed == False - -################# + - test7.changed == false - - name: Confirm the commit with a commit sync force + - name: TEST 8 - Confirm the commit with a commit sync force juniper.device.config: check: true diff: false @@ -141,20 +137,114 @@ - name: Check TEST 8 ansible.builtin.assert: that: - test8.changed == False -################ - - name: Test commit timeout . + - test8.changed == false + + - name: TEST 2 Repeat - Commit with timeout juniper.device.config: load: 'merge' lines: - "set system host-name {{ inventory_hostname }}.foo" comment: "Append .foo to the hostname" timeout: 300 - register: test2 + register: test2b ignore_errors: true tags: [test2] - - name: Check TEST 2 + - name: Check TEST 2b ansible.builtin.assert: that: - - test2.diff_lines + - test2b.diff_lines + + - name: TEST 9 - Diff between rollback 11 and current + juniper.device.config: + rollback: 11 + diff: true + check: false + commit: false + register: test_rollback_diff + + - name: Check TEST 9 - Rollback diff task executed successfully + ansible.builtin.assert: + that: + - test_rollback_diff.failed is not defined or test_rollback_diff.failed == false + + - name: Ensure output directory exists for TEST 10 + ansible.builtin.file: + path: "{{ playbook_dir }}/output" + state: directory + mode: '0755' + run_once: true + delegate_to: localhost + + - name: TEST 10 - Retrieve using XML filter and save to dest_dir + juniper.device.config: + retrieve: 'committed' + format: 'xml' + commit: false + check: false + diff: false + dest_dir: "{{ playbook_dir }}/output" + filter: "re0" + return_output: true + register: test_xml_filter + + - name: CHECK TEST 10 - Retrieve with XML filter executed successfully + ansible.builtin.assert: + that: + - test_xml_filter.failed is not defined or test_xml_filter.failed == false + + - name: Ensure configs directory exists for TEST 11 + ansible.builtin.file: + path: "{{ playbook_dir }}/configs" + state: directory + mode: '0755' + delegate_to: localhost + run_once: true + + - name: Ensure override config file exists for TEST 11 + ansible.builtin.copy: + content: | + set system host-name test-host + dest: "{{ playbook_dir }}/configs/{{ inventory_hostname }}.conf" + delegate_to: localhost + run_once: true + + - name: Dry-run override config using private mode + juniper.device.config: + config_mode: private + load: set + src: "{{ playbook_dir }}/configs/{{ inventory_hostname }}.conf" + check: true + commit: false + register: test_override + ignore_errors: true + + - name: Skip TEST 11 if exclusive lock prevents config + ansible.builtin.debug: + msg: "Skipping TEST 11 - configure exclusive lock is active" + when: test_override.msg is defined and + ('configure exclusive' in test_override.msg or + 'exclusive' in test_override.msg or + test_override.failed) + + - name: CHECK TEST 11 - Dry-run override was successful + ansible.builtin.assert: + that: + - test_override.failed == false + when: test_override.failed == false + + + + + + + + + + + + + + + + diff --git a/tests/pb.juniper_junos_facts.yml b/tests/pb.juniper_junos_facts.yml index 7d2fb042..127ffbb8 100644 --- a/tests/pb.juniper_junos_facts.yml +++ b/tests/pb.juniper_junos_facts.yml @@ -26,3 +26,48 @@ ansible.builtin.assert: that: - "'= 0 + tags: [test9] + +########################################################################### +## TEST 10 +########################################################################### + - name: Ensure logs directory exists for TEST 10 + ansible.builtin.file: + path: "{{ playbook_dir }}/logs" + state: directory + mode: '0755' + delegate_to: localhost + run_once: true + tags: [test10] + + - name: TEST 10 - Use test_files with logdir and level + juniper.device.jsnapy: + action: snapcheck + dir: "{{ playbook_dir }}/config" + test_files: + - junos_jsnapy/test_loopback.yml + logdir: "{{ playbook_dir }}/logs" + level: INFO + register: test10 + ignore_errors: true + tags: [test10] + + - name: Check TEST 10 + ansible.builtin.assert: + that: + - test10.passPercentage is defined + - test10.total_failed == 0 + tags: [test10] + +############################################################## +## TEST 11 +############################################################## + - name: TEST 11 - Use logdir for check action + juniper.device.jsnapy: + action: check + dir: junos_jsnapy + test_files: "test_loopback.yml" + logdir: "{{ playbook_dir }}/logs" + register: test11 + ignore_errors: true + tags: [test11] + + - name: Check TEST 11 + ansible.builtin.assert: + that: + - test11.passPercentage is defined + - test11.passPercentage >= 0 + - test11.final_result is defined + tags: [test11] + + + + + + + + diff --git a/tests/pb.juniper_junos_ping.yml b/tests/pb.juniper_junos_ping.yml index 84421770..fb5be3ce 100644 --- a/tests/pb.juniper_junos_ping.yml +++ b/tests/pb.juniper_junos_ping.yml @@ -3,6 +3,7 @@ hosts: all gather_facts: false tasks: + - name: "TEST 1 - Ping Host DNS" juniper.device.ping: dest_ip: "{{ ansible_ssh_host }}" @@ -14,7 +15,7 @@ that: - test1.packet_loss == '0' -############ + ################################################ - name: "TEST 2 - Ping Wrong IP" juniper.device.ping: @@ -26,7 +27,8 @@ ansible.builtin.assert: that: - test2.packet_loss == '100' -################# + + ################################################ - name: "TEST 3 - Change nbr packets" juniper.device.ping: @@ -40,7 +42,7 @@ that: - test3.packets_sent == '3' -################# + ################################################ - name: "TEST 4 - Ping with DF-bit set" juniper.device.ping: @@ -56,4 +58,66 @@ that: - test4.packets_received == '3' -################# + ################################################ + + - name: "TEST 5 - Acceptable packet loss" + juniper.device.ping: + dest_ip: 8.8.1.1 + acceptable_percent_loss: 50 + register: test5 + ignore_errors: true + + - name: Check TEST 5 + ansible.builtin.assert: + that: + - test5.packet_loss == '100' + - test5.acceptable_percent_loss == '50' + + ################################################ + + - name: "TEST 6 - TTL and rapid=false" + juniper.device.ping: + dest_ip: "{{ ansible_ssh_host }}" + ttl: 15 + count: 10 + rapid: false + register: test6 + ignore_errors: true + + - name: Check TEST 6 + ansible.builtin.assert: + that: + - test6.ttl == '15' + - test6.rapid == false + + ################################################ + + - name: "TEST 7 - Ping with source IP" + juniper.device.ping: + dest_ip: "{{ ansible_ssh_host }}" + source: "{{ ansible_ssh_host }}" + register: test7 + ignore_errors: true + + - name: Check TEST 7 + ansible.builtin.assert: + that: + - test7.source == test7.source_ip + + ################################################ + + - name: "TEST 8 - Ping from routing-instance" + juniper.device.ping: + dest_ip: "{{ ansible_ssh_host }}" + routing_instance: "default" + register: test8 + ignore_errors: true + + - name: Check TEST 8 + ansible.builtin.assert: + that: + - test8.routing_instance == 'default' + + ################################################ + + diff --git a/tests/pb.juniper_junos_pmtud.yml b/tests/pb.juniper_junos_pmtud.yml index b5684214..ed91eba1 100644 --- a/tests/pb.juniper_junos_pmtud.yml +++ b/tests/pb.juniper_junos_pmtud.yml @@ -25,3 +25,56 @@ ansible.builtin.assert: that: - test1.inet_mtu <= 700 + + + - name: TEST 3 - PMTUD with max_range and max_size + juniper.device.pmtud: + dest_ip: "{{ ansible_ssh_host }}" + max_size: 65496 + max_range: 65536 + register: test3 + ignore_errors: true + + - name: Check TEST 3 + ansible.builtin.assert: + that: + - test3.inet_mtu | int <= 65496 + + - name: "TEST 4 - PMTUD from specific interface" + juniper.device.pmtud: + dest_ip: "{{ ansible_ssh_host }}" + interface: "ge-0/0/1.0" + register: test4 + + - name: Check TEST 4 + ansible.builtin.assert: + that: + - test4.inet_mtu is defined + - test4.inet_mtu | int >= 768 + + - name: "TEST 5 - PMTUD with source IP" + juniper.device.pmtud: + dest_ip: "{{ ansible_ssh_host }}" + source: "{{ ansible_ssh_host }}" + register: test5 + + - name: Check TEST 5 + ansible.builtin.assert: + that: + - test5.inet_mtu is defined + - test5.inet_mtu | int >= 768 + + - name: "TEST 6 - PMTUD with routing instance" + juniper.device.pmtud: + dest_ip: "{{ ansible_ssh_host }}" + routing_instance: "default" + register: test6 + + - name: Check TEST 6 + ansible.builtin.assert: + that: + - test6.inet_mtu is defined + - test6.inet_mtu | int >= 768 + + + diff --git a/tests/pb.juniper_junos_rpc.yml b/tests/pb.juniper_junos_rpc.yml index 12f7a302..7178b202 100644 --- a/tests/pb.juniper_junos_rpc.yml +++ b/tests/pb.juniper_junos_rpc.yml @@ -4,7 +4,7 @@ gather_facts: false tasks: -################# +################ - name: "Execute single RPC get-software-information without any kwargs" juniper.device.rpc: rpcs: @@ -274,3 +274,129 @@ that: - test1.msg == "The RPC executed successfully." tags: [test13] + + ################# + + - name: TEST 14 - RPC with ignore_warning + juniper.device.rpc: + rpcs: + - get-software-information + ignore_warning: true + register: test14 + tags: [test14] + + - name: Check TEST 14 + ansible.builtin.assert: + that: + - test14.msg == "The RPC executed successfully." + tags: [test14] + + ################# + + - name: Ensure logdir exists + ansible.builtin.file: + path: "{{ playbook_dir }}/rpc_logs" + state: directory + mode: "0755" + delegate_to: localhost + run_once: true + tags: [test15] + + - name: TEST 15 - RPC with logdir + juniper.device.rpc: + rpcs: + - get-software-information + logdir: "{{ playbook_dir }}/rpc_logs" + register: test15 + tags: [test15] + + - name: Check TEST 15 log file + ansible.builtin.stat: + path: "{{ playbook_dir }}/rpc_logs/{{ inventory_hostname }}.log" + register: stat_result_log15 + delegate_to: localhost + + - name: Clean up logdir + ansible.builtin.file: + path: "{{ playbook_dir }}/rpc_logs" + state: absent + delegate_to: localhost + run_once: true + tags: [test15] + + ################# + + - name: Ensure output directory exists for TEST 16 + ansible.builtin.file: + path: "{{ playbook_dir }}/rpc_output" + state: directory + mode: '0755' + delegate_to: localhost + run_once: true + tags: [test16] + + - name: TEST 16 - RPC with return_output false and dest_dir + juniper.device.rpc: + rpcs: + - get-software-information + return_output: false + dest_dir: "{{ playbook_dir }}/rpc_output" + register: test16 + tags: [test16] + + - name: Assert TEST 16 has no output returned + ansible.builtin.assert: + that: + - test16.stdout is not defined + tags: [test16] + + - name: Clean up TEST 16 output dir + ansible.builtin.file: + path: "{{ playbook_dir }}/rpc_output" + state: absent + delegate_to: localhost + run_once: true + tags: [test16] + + ################# + + - name: TEST 17 - RPC with attrs (attribute applied without kwargs) + juniper.device.rpc: + rpcs: + - get-config + attrs: + format: text + filter: "" + register: test17 + tags: [test17] + + - name: Check TEST 17 + ansible.builtin.assert: + that: + - test17.stdout is defined + - "'