diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-18 05:52:35 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-18 05:52:35 +0000 |
commit | 7fec0b69a082aaeec72fee0612766aa42f6b1b4d (patch) | |
tree | efb569b86ca4da888717f5433e757145fa322e08 /ansible_collections/cisco/aci/tests | |
parent | Releasing progress-linux version 7.7.0+dfsg-3~progress7.99u1. (diff) | |
download | ansible-7fec0b69a082aaeec72fee0612766aa42f6b1b4d.tar.xz ansible-7fec0b69a082aaeec72fee0612766aa42f6b1b4d.zip |
Merging upstream version 9.4.0+dfsg.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/cisco/aci/tests')
154 files changed, 14376 insertions, 1041 deletions
diff --git a/ansible_collections/cisco/aci/tests/integration/inventory.networking b/ansible_collections/cisco/aci/tests/integration/inventory.networking index 16e3d1ee1..357f58758 100644 --- a/ansible_collections/cisco/aci/tests/integration/inventory.networking +++ b/ansible_collections/cisco/aci/tests/integration/inventory.networking @@ -3,11 +3,12 @@ cn-dmz-apic-m1-02-v42 ansible_host=173.36.219.68 aci_hostname=173.36.219.68 cn-dmz-apic-m1-03-v52 ansible_host=173.36.219.69 aci_hostname=173.36.219.69 cn-dmz-apic-m1-04-v60 ansible_host=173.36.219.70 aci_hostname=173.36.219.70 cn-dmz-apic-m1-07-v32 ansible_host=173.36.219.73 aci_hostname=173.36.219.73 -aws_cloud ansible_host=52.52.20.121 aci_hostname=52.52.20.121 aci_password="sJ94G92#8dq2hx*K4qh" cloud_type=aws region=us-east-1 region_2=us-west-1 availability_zone=us-west-1a -azure_cloud ansible_host=20.245.236.136 aci_hostname=20.245.236.136 aci_password="sJ94G92#8dq2hx*K4qh" cloud_type=azure region=westus region_2=westus2 vnet_gateway=true +aws_cloud ansible_host=52.52.20.121 aci_hostname=52.52.20.121 cloud_type=aws region=us-east-1 region_2=us-west-1 availability_zone=us-west-1a +azure_cloud ansible_host=20.245.236.136 aci_hostname=20.245.236.136 cloud_type=azure region=westus region_2=westus2 vnet_gateway=true [aci:vars] aci_username=ansible_github_ci aci_password="sJ94G92#8dq2hx*K4qh" +ansible_network_os=cisco.aci.aci ansible_connection=local ansible_python_interpreter=/usr/bin/python3.9 diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user/tasks/main.yml index 56de63830..52f3ed0fb 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user/tasks/main.yml @@ -8,23 +8,14 @@ msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined - -# CLEAN ENVIRONMENT -- name: Remove any pre-existing user - cisco.aci.aci_aaa_user: &user_absent - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' - aaa_user: ansible +- name: Uninstall dateutil for error checking + ansible.builtin.pip: &dateutil + name: python-dateutil state: absent - + ignore_errors: true # ignore errors to because of multiple executions for hosts at the same time # ADD USER -- name: Add user (check_mode) +- name: Add user without dateutil installed (error) cisco.aci.aci_aaa_user: &user_present host: '{{ aci_hostname }}' username: '{{ aci_username }}' @@ -42,6 +33,36 @@ first_name: Test last_name: User phone: 1-234-555-678 + ignore_errors: true + register: err_no_python_dateutil + +- name: Verify add user + ansible.builtin.assert: + that: + - err_no_python_dateutil.msg == "dateutil required for this module" + +- name: Install dateutil + ansible.builtin.pip: + <<: *dateutil + state: present + ignore_errors: true # ignore errors to because of multiple executions for hosts at the same time + +# CLEAN ENVIRONMENT +- name: Remove any pre-existing user + cisco.aci.aci_aaa_user: &user_absent + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + aaa_user: ansible + state: absent + +# ADD USER +- name: Add user (check_mode) + cisco.aci.aci_aaa_user: *user_present check_mode: true register: cm_add_user @@ -49,7 +70,8 @@ - name: Add user (normal mode) cisco.aci.aci_aaa_user: <<: *user_present - aaa_password: 12!Ab:cD!34 + # changed password because password strength check is triggered on the 6.0(2h) version, thus failing testcase + aaa_password: khsaubf@3ijsdn!!2#%nbsh register: nm_add_user - name: Add user again (check mode) @@ -72,7 +94,6 @@ - nm_add_user_again is not changed - nm_add_user_again.current.0.aaaUser.attributes.descr == 'Ansible test user' - # MODIFY USER - name: Modify user (check_mode) cisco.aci.aci_aaa_user: &user_changed @@ -92,6 +113,13 @@ check_mode: true register: cm_modify_user +- name: Error wrong expiration (error) + cisco.aci.aci_aaa_user: + <<: *user_changed + expiration: wrong_expiration + ignore_errors: true + register: err_modify_user_expiration + - name: Modify user (normal mode) cisco.aci.aci_aaa_user: *user_changed register: nm_modify_user @@ -109,6 +137,7 @@ assert: that: - cm_modify_user is changed + - err_modify_user_expiration.msg == "Failed to parse date format 'wrong_expiration', Unknown string format{{":"}} wrong_expiration" - nm_modify_user is changed - nm_modify_user.current.0.aaaUser.attributes.descr == 'Ansible test user for integration tests' - cm_modify_user_again is not changed diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/tasks/main.yml index 9d300e4d7..3140816e0 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/tasks/main.yml @@ -300,13 +300,13 @@ state: present - name: Remove user ansible_test - aci_aaa_user: - <<: *aci_info - aaa_user: ansible_test - state: absent + cisco.aci.aci_aaa_user: + <<: *aci_info + aaa_user: ansible_test + state: absent - name: Add user ansible_test - aci_aaa_user: + cisco.aci.aci_aaa_user: <<: *aci_info aaa_user: ansible_test aaa_password: ansible_5351 @@ -315,7 +315,7 @@ state: present - name: Add user certificate - aci_aaa_user_certificate: + cisco.aci.aci_aaa_user_certificate: <<: *aci_info aaa_user: ansible_test name: test @@ -323,10 +323,8 @@ state: present - name: Query test certificate - aci_aaa_user_certificate: - host: "{{ aci_hostname }}" - username: "{{ aci_username }}" - validate_certs: '{{ aci_validate_certs | default(false) }}' + cisco.aci.aci_aaa_user_certificate: + <<: *aci_info certificate_name: admin private_key: '{{ role_path }}/pki/admin.key' aaa_user: ansible_test @@ -334,13 +332,75 @@ state: query register: query_test +- name: Query test certificate with a private key file and no certificate name + cisco.aci.aci_aaa_user_certificate: + <<: *aci_info + private_key: '{{ role_path }}/pki/admin.key' + aaa_user: ansible_test + name: test + state: query + register: query_test_pk_file + +- name: Query test certificate with a non existent key + cisco.aci.aci_aaa_user_certificate: + <<: *aci_info + private_key: '{{ role_path }}/pki/non_existent.key' + aaa_user: ansible_test + name: test + state: query + register: query_test_non_existent_key + ignore_errors: true + +- name: Query test certificate with private key content and no certificate name present + cisco.aci.aci_aaa_user_certificate: + <<: *aci_info + private_key: | + -----BEGIN PRIVATE KEY----- + MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKIRv+2sbbewm0mj + D+6/tpoUymzYIdFsN+gu02teIr/lZi8ipEB514pyhoaerstzboPteWvniLuwq4KQ + VTEHgoln7J8EaHCnECViGA61pVx8RkJ99cmCkepspROw3I96zBcm58oXs6+Q/BnD + /OWET5sBvR9oTv9GNRVJ1rvSMAEJAgMBAAECgYByu3QO0qF9h7X3JEu0Ld4cKBnB + giQ2uJC/et7KxIJ/LOvw9GopBthyt27KwG1ntBkJpkTuAaQHkyNns7vLkNB0S0IR + +owVFEcKYq9VCHTaiQU8TDp24gN+yPTrpRuH8YhDVq5SfVdVuTMgHVQdj4ya4VlF + Gj+a7+ipxtGiLsVGrQJBAM7p0Fm0xmzi+tBOASUAcVrPLcteFIaTBFwfq16dm/ON + 00Khla8Et5kMBttTbqbukl8mxFjBEEBlhQqb6EdQQ0sCQQDIhHx1a9diG7y/4DQA + 4KvR3FCYwP8PBORlSamegzCo+P1OzxiEo0amX7yQMA5UyiP/kUsZrme2JBZgna8S + p4R7AkEAr7rMhSOPUnMD6V4WgsJ5g1Jp5kqkzBaYoVUUSms5RASz4+cwJVCwTX91 + Y1jcpVIBZmaaY3a0wrx13ajEAa0dOQJBAIpjnb4wqpsEh7VpmJqOdSdGxb1XXfFQ + sA0T1OQYqQnFppWwqrxIL+d9pZdiA1ITnNqyvUFBNETqDSOrUHwwb2cCQGArE+vu + ffPUWQ0j+fiK+covFG8NL7H+26NSGB5+Xsn9uwOGLj7K/YT6CbBtr9hJiuWjM1Al + 0V4ltlTuu2mTMaw= + -----END PRIVATE KEY----- + aaa_user: ansible_test + name: test + state: query + register: query_test_pk_content + - name: Verify query_test assert: that: - query_test is not changed + - query_test_pk_file is not changed + - '"Provided private key ******** does not appear to be a private key or provided file does not exist." in query_test_non_existent_key.msg' + - query_test_pk_content is not changed + +# Cleanup environment +- name: Remove test certificate + cisco.aci.aci_aaa_user_certificate: + <<: *aci_info + aaa_user: ansible_test + name: test + state: absent - name: Remove user to clean environment for next test on ci - aci_aaa_user: + cisco.aci.aci_aaa_user: <<: *aci_info aaa_user: ansible_test state: absent + +- name: Remove test certificate + cisco.aci.aci_aaa_user_certificate: + <<: *aci_info + aaa_user: '{{ aci_username }}' + name: admin + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group/tasks/main.yml new file mode 100644 index 000000000..e2d00e525 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group/tasks/main.yml @@ -0,0 +1,334 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Akini Ross (@akinross) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +# CLEAN TEST ENVIRONMENT BEFORE TESTS + +- name: Query all span source groups ( clean before ) + cisco.aci.aci_access_span_src_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean access span source groups ( clean before ) + cisco.aci.aci_access_span_src_group: + <<: *aci_info + source_group: "{{ item.spanSrcGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Query all span destination groups ( clean before ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean access span destination groups ( clean before ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Execute tasks only for non-cloud sites ( clean before ) + when: + - query_cloud.current == [] + block: + - name: Query all access span filter groups ( clean before ) + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + state: query + register: query_for_clean + + - name: Clean access span filter groups ( clean before ) + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + filter_group: "{{ item.spanFilterGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + + - name: Add a access span filter groups ( clean before ) + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + filter_group: "{{ item }}" + state: present + loop: + - span_filter_group_1 + - span_filter_group_2 + +- name: Add access span destination group type epg ( clean before ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + destination_group: span_dest_1 + description: test span epg + destination_epg: + destination_ip: 10.0.0.1 + source_ip: 10.0.2.1 + tenant: ansible_test + ap: ansible_test + epg: ansible_test + state: present + +- name: Add access span destination group type access interface port ( clean before ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + destination_group: span_dest_2 + description: test span access interface port + access_interface: + pod: 1 + node: 101 + path: eth1/1 + mtu: 1500 + state: present + +- name: Add access span destination group type access interface direct port channel ( clean before ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + destination_group: span_dest_3 + description: test span access interface port channel + access_interface: + pod: 1 + node: 101 + path: test-PolGrp + state: present + +# TEST CREATE SOURCE GROUPS + +- name: Add access span source group 1 ( checkmode ) + cisco.aci.aci_access_span_src_group: &span_src_1 + <<: *aci_info + source_group: span_src_1 + destination_group: span_dest_1 + filter_group: span_filter_group_1 + state: present + check_mode: true + register: cm_span_src_1 + +- name: Add access span source group 1 + cisco.aci.aci_access_span_src_group: + <<: *span_src_1 + register: nm_span_src_1 + +- name: Add access span source group 1 again + cisco.aci.aci_access_span_src_group: + <<: *span_src_1 + register: nm_span_src_1_again + +- name: Verify add access span source group 1 + ansible.builtin.assert: + that: + - cm_span_src_1 is changed + - cm_span_src_1.previous == [] + - cm_span_src_1.current == [] + - cm_span_src_1.proposed.spanSrcGrp.attributes.name == "span_src_1" + - cm_span_src_1.proposed.spanSrcGrp.children.0.spanSpanLbl.attributes.name == "span_dest_1" + - cm_span_src_1.proposed.spanSrcGrp.children.1.spanRsSrcGrpToFilterGrp.attributes.tDn == "uni/infra/filtergrp-span_filter_group_1" + - nm_span_src_1 is changed + - nm_span_src_1.previous == [] + - nm_span_src_1.current.0.spanSrcGrp.attributes.name == "span_src_1" + - nm_span_src_1.current.0.spanSrcGrp.attributes.descr == "" + - nm_span_src_1.current.0.spanSrcGrp.attributes.adminSt == "enabled" + - nm_span_src_1.current.0.spanSrcGrp.children.1.spanSpanLbl.attributes.name == "span_dest_1" + - nm_span_src_1.current.0.spanSrcGrp.children.0.spanRsSrcGrpToFilterGrp.attributes.tDn == "uni/infra/filtergrp-span_filter_group_1" + - nm_span_src_1_again is not changed + - nm_span_src_1_again.previous.0.spanSrcGrp.attributes.name == "span_src_1" + - nm_span_src_1_again.previous.0.spanSrcGrp.attributes.descr == "" + - nm_span_src_1_again.previous.0.spanSrcGrp.attributes.adminSt == "enabled" + - nm_span_src_1_again.previous.0.spanSrcGrp.children.1.spanSpanLbl.attributes.name == "span_dest_1" + - nm_span_src_1_again.previous.0.spanSrcGrp.children.0.spanRsSrcGrpToFilterGrp.attributes.tDn == "uni/infra/filtergrp-span_filter_group_1" + - nm_span_src_1_again.current.0.spanSrcGrp.attributes.name == "span_src_1" + - nm_span_src_1_again.current.0.spanSrcGrp.attributes.descr == "" + - nm_span_src_1_again.current.0.spanSrcGrp.attributes.adminSt == "enabled" + - nm_span_src_1_again.current.0.spanSrcGrp.children.1.spanSpanLbl.attributes.name == "span_dest_1" + - nm_span_src_1_again.current.0.spanSrcGrp.children.0.spanRsSrcGrpToFilterGrp.attributes.tDn == "uni/infra/filtergrp-span_filter_group_1" + +- name: Change access span source group 1 + cisco.aci.aci_access_span_src_group: &change_span_src_1 + <<: *span_src_1 + destination_group: span_dest_2 + filter_group: span_filter_group_2 + description: "changed description" + admin_state: false + register: nm_changed_span_src_1 + +- name: Change access span source group 1 again + cisco.aci.aci_access_span_src_group: + <<: *change_span_src_1 + register: nm_changed_span_src_1_again + +- name: Change access span source group 1 remove filter group + cisco.aci.aci_access_span_src_group: + <<: *aci_info + source_group: span_src_1 + destination_group: span_dest_2 + register: nm_changed_span_src_1_remove_filter_group + +- name: Verify changed access span source group 1 + ansible.builtin.assert: + that: + - nm_changed_span_src_1 is changed + - nm_changed_span_src_1.previous.0.spanSrcGrp.attributes.descr == "" + - nm_changed_span_src_1.previous.0.spanSrcGrp.attributes.adminSt == "enabled" + - nm_changed_span_src_1.previous.0.spanSrcGrp.children.1.spanSpanLbl.attributes.name == "span_dest_1" + - nm_changed_span_src_1.previous.0.spanSrcGrp.children.0.spanRsSrcGrpToFilterGrp.attributes.tDn == "uni/infra/filtergrp-span_filter_group_1" + - nm_changed_span_src_1.current.0.spanSrcGrp.attributes.descr == "changed description" + - nm_changed_span_src_1.current.0.spanSrcGrp.attributes.adminSt == "disabled" + - nm_changed_span_src_1.current.0.spanSrcGrp.children.1.spanSpanLbl.attributes.name == "span_dest_2" + - nm_changed_span_src_1.current.0.spanSrcGrp.children.0.spanRsSrcGrpToFilterGrp.attributes.tDn == "uni/infra/filtergrp-span_filter_group_2" + - nm_changed_span_src_1_again is not changed + - nm_changed_span_src_1_again.previous.0.spanSrcGrp.attributes.descr == "changed description" + - nm_changed_span_src_1_again.previous.0.spanSrcGrp.attributes.adminSt == "disabled" + - nm_changed_span_src_1_again.previous.0.spanSrcGrp.children.1.spanSpanLbl.attributes.name == "span_dest_2" + - nm_changed_span_src_1_again.previous.0.spanSrcGrp.children.0.spanRsSrcGrpToFilterGrp.attributes.tDn == "uni/infra/filtergrp-span_filter_group_2" + - nm_changed_span_src_1_again.current.0.spanSrcGrp.attributes.descr == "changed description" + - nm_changed_span_src_1_again.current.0.spanSrcGrp.attributes.adminSt == "disabled" + - nm_changed_span_src_1_again.current.0.spanSrcGrp.children.1.spanSpanLbl.attributes.name == "span_dest_2" + - nm_changed_span_src_1_again.current.0.spanSrcGrp.children.0.spanRsSrcGrpToFilterGrp.attributes.tDn == "uni/infra/filtergrp-span_filter_group_2" + - nm_changed_span_src_1_remove_filter_group is changed + - nm_changed_span_src_1_remove_filter_group.current.0.spanSrcGrp.children | length == 1 + - nm_changed_span_src_1_remove_filter_group.current.0.spanSrcGrp.children.0.spanSpanLbl.attributes.name == "span_dest_2" + +- name: Add access span source group 2 with admin_state to false + cisco.aci.aci_access_span_src_group: + <<: *change_span_src_1 + source_group: span_src_2 + destination_group: span_dest_2 + admin_state: false + register: nm_changed_span_src_2_admin_state_false + +- name: Add another access span source group 3 with admin_state to true + cisco.aci.aci_access_span_src_group: + <<: *change_span_src_1 + source_group: span_src_3 + destination_group: span_dest_3 + admin_state: true + register: nm_changed_span_src_3_admin_state_true + +- name: Verify admin_state sets for access span source group 2 and 3 + ansible.builtin.assert: + that: + - nm_changed_span_src_2_admin_state_false is changed + - nm_changed_span_src_2_admin_state_false.current.0.spanSrcGrp.attributes.adminSt == "disabled" + - nm_changed_span_src_3_admin_state_true is changed + - nm_changed_span_src_3_admin_state_true.current.0.spanSrcGrp.attributes.adminSt == "enabled" + +# TEST QUERY SOURCE GROUPS + +- name: Query span source group span_src_1 + cisco.aci.aci_access_span_src_group: + <<: *change_span_src_1 + state: query + register: query_one + +- name: Query all span source groups + cisco.aci.aci_access_span_src_group: + <<: *aci_info + state: query + register: query_all + +- name: Verify querying access span destination groups + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current | length == 1 + - query_one.current.0.spanSrcGrp.attributes.name == "span_src_1" + - query_all is not changed + - query_all.current | length >= 3 + +# TEST REMOVAL SOURCE GROUPS + +- name: Remove span source group ( checkmode ) + cisco.aci.aci_access_span_src_group: &remove_span_src_1 + <<: *change_span_src_1 + state: absent + check_mode: true + register: cm_remove_span_src_1 + +- name: Remove span source group + cisco.aci.aci_access_span_src_group: + <<: *remove_span_src_1 + register: nm_remove_span_src_1 + +- name: Remove span source group again + cisco.aci.aci_access_span_src_group: + <<: *remove_span_src_1 + register: nm_remove_span_src_1_again + +- name: Verify remove access span destination groups + ansible.builtin.assert: + that: + - cm_remove_span_src_1 is changed + - cm_remove_span_src_1.current | length == 1 + - cm_remove_span_src_1.previous | length == 1 + - cm_remove_span_src_1.proposed == {} + - nm_remove_span_src_1 is changed + - nm_remove_span_src_1.current == [] + - nm_remove_span_src_1.previous | length == 1 + - nm_remove_span_src_1_again is not changed + - nm_remove_span_src_1_again.current == [] + - nm_remove_span_src_1_again.previous == [] + +# CLEAN TEST ENVIRONMENT AFTER TESTS + +- name: Query all span source groups ( clean after ) + cisco.aci.aci_access_span_src_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean access span source groups ( clean after ) + cisco.aci.aci_access_span_src_group: + <<: *aci_info + source_group: "{{ item.spanSrcGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Query all span destination groups ( clean after ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean access span destination groups ( clean after ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Execute tasks only for non-cloud sites ( clean after ) + when: + - query_cloud.current == [] + block: + - name: Query all access span filter groups ( clean after ) + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + state: query + register: query_for_clean + + - name: Clean access span filter groups ( clean after ) + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + filter_group: "{{ item.spanFilterGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group_src/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group_src/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group_src/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group_src/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group_src/tasks/main.yml new file mode 100644 index 000000000..a0fe48f08 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group_src/tasks/main.yml @@ -0,0 +1,532 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Akini Ross (@akinross) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +# CLEAN TEST ENVIRONMENT BEFORE TESTS + +- name: Query all span source groups ( clean before ) + cisco.aci.aci_access_span_src_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean access span source groups ( clean before ) + cisco.aci.aci_access_span_src_group: + <<: *aci_info + source_group: "{{ item.spanSrcGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Query all span destination groups ( clean before ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean access span destination groups ( clean before ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Execute tasks only for non-cloud sites ( clean before ) + when: + - query_cloud.current == [] + block: + - name: Query all access span filter groups ( clean before ) + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + state: query + register: query_for_clean + + - name: Clean access span filter groups ( clean before ) + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + filter_group: "{{ item.spanFilterGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + + - name: Add a access span filter groups ( clean before ) + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + filter_group: "{{ item }}" + state: present + loop: + - span_filter_group_1 + - span_filter_group_2 + +- name: Add access span destination group type epg ( clean before ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + destination_group: span_dest_1 + description: test span epg + destination_epg: + destination_ip: 10.0.0.1 + source_ip: 10.0.2.1 + tenant: ansible_test + ap: ansible_test + epg: ansible_test + state: present + +- name: Add access span source group 1 ( clean before ) + cisco.aci.aci_access_span_src_group: + <<: *aci_info + source_group: "{{ item }}" + destination_group: span_dest_1 + state: present + loop: + - span_src_group_1 + - span_src_group_2 + - span_src_group_3 + +# TEST CREATE SOURCE + +- name: Add access span source 1 ( checkmode ) + cisco.aci.aci_access_span_src_group_src: &span_src_1 + <<: *aci_info + source_group: span_src_group_1 + filter_group: span_filter_group_1 + source: span_src_1 + state: present + check_mode: true + register: cm_span_src_1 + +- name: Add access span source 1 + cisco.aci.aci_access_span_src_group_src: + <<: *span_src_1 + register: nm_span_src_1 + +- name: Add access span source 1 again + cisco.aci.aci_access_span_src_group_src: + <<: *span_src_1 + register: nm_span_src_1_again + +- name: Verify add access span source group 1 + ansible.builtin.assert: + that: + - cm_span_src_1 is changed + - cm_span_src_1.previous == [] + - cm_span_src_1.current == [] + - cm_span_src_1.proposed.spanSrc.attributes.name == "span_src_1" + - cm_span_src_1.proposed.spanSrc.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1" + - cm_span_src_1.proposed.spanSrc.children.0.spanRsSrcToFilterGrp.attributes.tDn == "uni/infra/filtergrp-span_filter_group_1" + - nm_span_src_1 is changed + - nm_span_src_1.previous == [] + - nm_span_src_1.current.0.spanSrc.attributes.name == "span_src_1" + - nm_span_src_1.current.0.spanSrc.attributes.descr == "" + - nm_span_src_1.current.0.spanSrc.attributes.dir == "both" + - nm_span_src_1.current.0.spanSrc.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1" + - nm_span_src_1.current.0.spanSrc.children.0.spanRsSrcToFilterGrp.attributes.tDn == "uni/infra/filtergrp-span_filter_group_1" + - nm_span_src_1_again is not changed + - nm_span_src_1_again.previous.0.spanSrc.attributes.name == "span_src_1" + - nm_span_src_1_again.previous.0.spanSrc.attributes.descr == "" + - nm_span_src_1_again.previous.0.spanSrc.attributes.dir == "both" + - nm_span_src_1_again.previous.0.spanSrc.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1" + - nm_span_src_1_again.previous.0.spanSrc.children.0.spanRsSrcToFilterGrp.attributes.tDn == "uni/infra/filtergrp-span_filter_group_1" + - nm_span_src_1_again.current.0.spanSrc.attributes.name == "span_src_1" + - nm_span_src_1_again.current.0.spanSrc.attributes.descr == "" + - nm_span_src_1_again.current.0.spanSrc.attributes.dir == "both" + - nm_span_src_1_again.current.0.spanSrc.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1" + - nm_span_src_1_again.current.0.spanSrc.children.0.spanRsSrcToFilterGrp.attributes.tDn == "uni/infra/filtergrp-span_filter_group_1" + +- name: Change access span source group 1 + cisco.aci.aci_access_span_src_group_src: &change_span_src_1 + <<: *span_src_1 + source: span_src_1 + filter_group: span_filter_group_2 + description: "changed description" + direction: both + register: nm_changed_span_src_1 + +- name: Change access span source group 1 direction incoming + cisco.aci.aci_access_span_src_group_src: + <<: *change_span_src_1 + direction: incoming + register: nm_changed_span_src_1_incoming + +- name: Change access span source group 1 direction outgoing + cisco.aci.aci_access_span_src_group_src: &change_span_src_1_again + <<: *change_span_src_1 + direction: outgoing + register: nm_changed_span_src_1_outgoing + +- name: Change access span source group 1 again + cisco.aci.aci_access_span_src_group_src: + <<: *change_span_src_1_again + register: nm_changed_span_src_1_again + +- name: Verify changed access span source group 1 + ansible.builtin.assert: + that: + - nm_changed_span_src_1 is changed + - nm_changed_span_src_1.previous.0.spanSrc.attributes.name == "span_src_1" + - nm_changed_span_src_1.previous.0.spanSrc.attributes.descr == "" + - nm_changed_span_src_1.previous.0.spanSrc.attributes.dir == "both" + - nm_changed_span_src_1.previous.0.spanSrc.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1" + - nm_changed_span_src_1.previous.0.spanSrc.children.0.spanRsSrcToFilterGrp.attributes.tDn == "uni/infra/filtergrp-span_filter_group_1" + - nm_changed_span_src_1.current.0.spanSrc.attributes.name == "span_src_1" + - nm_changed_span_src_1.current.0.spanSrc.attributes.descr == "changed description" + - nm_changed_span_src_1.current.0.spanSrc.attributes.dir == "both" + - nm_changed_span_src_1.current.0.spanSrc.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1" + - nm_changed_span_src_1.current.0.spanSrc.children.0.spanRsSrcToFilterGrp.attributes.tDn == "uni/infra/filtergrp-span_filter_group_2" + - nm_changed_span_src_1_incoming.current.0.spanSrc.attributes.dir == "in" + - nm_changed_span_src_1_outgoing.current.0.spanSrc.attributes.dir == "out" + - nm_changed_span_src_1_again is not changed + +- name: Add access span source 2 of epg type + cisco.aci.aci_access_span_src_group_src: &span_src_epg + <<: *aci_info + source_group: span_src_group_2 + epg: + tenant: tenant1 + ap: ap1 + epg: epg1 + source: span_src_2 + state: present + register: nm_span_src_2 + +- name: Change access span source 2 of epg type + cisco.aci.aci_access_span_src_group_src: + <<: *span_src_epg + epg: + tenant: tenant1 + ap: ap1 + epg: epg2 + register: nm_changed_span_src_2 + +- name: Change access span source 2 of epg type to none type + cisco.aci.aci_access_span_src_group_src: + <<: *aci_info + source_group: span_src_group_2 + source: span_src_2 + state: present + register: nm_changed_span_src_2_type_none + +- name: Add access span source 3 of routed_outside type + cisco.aci.aci_access_span_src_group_src: &span_src_routed_outside + <<: *aci_info + source_group: span_src_group_3 + routed_outside: + tenant: tenant1 + l3out: l3out1 + encap: 1089 + source: span_src_3 + state: present + register: nm_span_src_3 + +- name: Add access span source 3 of routed_outside type without l3out + cisco.aci.aci_access_span_src_group_src: + <<: *span_src_routed_outside + routed_outside: + tenant: tenant1 + encap: 1089 + state: present + register: nm_changed_span_src_3_no_l3out + +- name: Add access span source 3 of routed_outside type without encap + cisco.aci.aci_access_span_src_group_src: + <<: *span_src_routed_outside + routed_outside: + tenant: tenant1 + l3out: l3out1 + state: present + register: nm_changed_span_src_3_no_encap + +- name: Add access span source 3 of routed_outside type without tenant + cisco.aci.aci_access_span_src_group_src: + <<: *span_src_routed_outside + routed_outside: + l3out: l3out1 + encap: 1089 + state: present + register: nm_changed_span_src_3_no_tenant + +- name: Change access span source 3 of routed_outside type + cisco.aci.aci_access_span_src_group_src: + <<: *span_src_routed_outside + routed_outside: + tenant: tenant1 + l3out: l3out2 + encap: 1090 + register: nm_changed_span_src_3 + +- name: Change access span source 3 of routed_outside type to epg type + cisco.aci.aci_access_span_src_group_src: + <<: *aci_info + source_group: span_src_group_3 + source: span_src_3 + epg: + tenant: tenant1 + ap: ap1 + epg: epg3 + state: present + register: nm_changed_span_src_3_type_epg + +- name: Verify changed access span source types group 2 and 3 + ansible.builtin.assert: + that: + - nm_span_src_2 is changed + - nm_span_src_2.current.0.spanSrc.attributes.name == "span_src_2" + - nm_span_src_2.current.0.spanSrc.children.0.spanRsSrcToEpg.attributes.tDn == "uni/tn-tenant1/ap-ap1/epg-epg1" + - nm_changed_span_src_2 is changed + - nm_changed_span_src_2.current.0.spanSrc.attributes.name == "span_src_2" + - nm_changed_span_src_2.current.0.spanSrc.children.0.spanRsSrcToEpg.attributes.tDn == "uni/tn-tenant1/ap-ap1/epg-epg2" + - nm_changed_span_src_2_type_none is changed + - nm_changed_span_src_2_type_none.previous.0.spanSrc.children.0.spanRsSrcToEpg.attributes.tDn == "uni/tn-tenant1/ap-ap1/epg-epg2" + - '"children" not in nm_changed_span_src_2_type_none.current.0.spanSrc' + - nm_span_src_3 is changed + - nm_span_src_3.current.0.spanSrc.attributes.name == "span_src_3" + - nm_span_src_3.current.0.spanSrc.children.0.spanRsSrcToL3extOut.attributes.tDn == "uni/tn-tenant1/out-l3out1" + - nm_span_src_3.current.0.spanSrc.children.0.spanRsSrcToL3extOut.attributes.encap == "vlan-1089" + - nm_changed_span_src_3 is changed + - nm_changed_span_src_3.current.0.spanSrc.attributes.name == "span_src_3" + - nm_changed_span_src_3.current.0.spanSrc.children.0.spanRsSrcToL3extOut.attributes.tDn == "uni/tn-tenant1/out-l3out2" + - nm_changed_span_src_3.current.0.spanSrc.children.0.spanRsSrcToL3extOut.attributes.encap == "vlan-1090" + - nm_changed_span_src_3_type_epg is changed + - nm_changed_span_src_3_type_epg.current.0.spanSrc.attributes.name == "span_src_3" + - nm_changed_span_src_3_type_epg.current.0.spanSrc.children.0.spanRsSrcToEpg.attributes.tDn == "uni/tn-tenant1/ap-ap1/epg-epg3" + - nm_changed_span_src_3_no_l3out is changed + - nm_changed_span_src_3_no_l3out.current.0.spanSrc.attributes.name == "span_src_3" + - nm_changed_span_src_3_no_l3out.current.0.spanSrc.children.0.spanRsSrcToL3extOut.attributes.encap == "vlan-1089" + - nm_changed_span_src_3_no_l3out.current.0.spanSrc.children.0.spanRsSrcToL3extOut.attributes.tDn == "" + - nm_changed_span_src_3_no_tenant is changed + - nm_changed_span_src_3_no_tenant.current.0.spanSrc.attributes.name == "span_src_3" + - nm_changed_span_src_3_no_tenant.current.0.spanSrc.children.0.spanRsSrcToL3extOut.attributes.encap == "vlan-1089" + - nm_changed_span_src_3_no_tenant.current.0.spanSrc.children.0.spanRsSrcToL3extOut.attributes.tDn == "" + - nm_changed_span_src_3_no_encap is changed + - nm_changed_span_src_3_no_encap.current.0.spanSrc.attributes.name == "span_src_3" + - nm_changed_span_src_3_no_encap.current.0.spanSrc.children.0.spanRsSrcToL3extOut.attributes.encap == "unknown" + - nm_changed_span_src_3_no_encap.current.0.spanSrc.children.0.spanRsSrcToL3extOut.attributes.tDn == "uni/tn-tenant1/out-l3out1" + +- name: Change access span source 2 drop_packets true + cisco.aci.aci_access_span_src_group_src: + <<: *aci_info + source_group: span_src_group_2 + source: span_src_2 + drop_packets: true + state: present + register: nm_changed_span_src_2_type_drop_packets_true + +- name: Change access span source 2 drop_packets false + cisco.aci.aci_access_span_src_group_src: + <<: *aci_info + source_group: span_src_group_2 + source: span_src_2 + drop_packets: false + state: present + register: nm_changed_span_src_2_type_drop_packets_false + +- name: Verify changed access span source group 1 drop packets + ansible.builtin.assert: + that: + - nm_changed_span_src_2_type_drop_packets_true is changed + - nm_changed_span_src_2_type_drop_packets_true.current.0.spanSrc.attributes.name == "span_src_2" + - nm_changed_span_src_2_type_drop_packets_true.current.0.spanSrc.attributes.spanOnDrop == "yes" + - nm_changed_span_src_2_type_drop_packets_false is changed + - nm_changed_span_src_2_type_drop_packets_false.current.0.spanSrc.attributes.name == "span_src_2" + - nm_changed_span_src_2_type_drop_packets_false.current.0.spanSrc.attributes.spanOnDrop == "no" + +# TEST QUERY SOURCE + +- name: Query span source group span_src_1 + cisco.aci.aci_access_span_src_group_src: + <<: *aci_info + source: span_src_1 + state: query + register: query_one + +- name: Query all span source groups + cisco.aci.aci_access_span_src_group_src: + <<: *aci_info + state: query + register: query_all + +- name: Verify querying access span sources + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current | length == 1 + - query_one.current.0.spanSrc.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1" + - query_all is not changed + - query_all.current | length >= 3 + +# TEST ERRORS SOURCE + +- name: Add access span source group 4 + cisco.aci.aci_access_span_src_group: + <<: *aci_info + source_group: span_src_group_4 + destination_group: span_dest_1 + filter_group: span_filter_group_1 + state: present + +- name: Add access span source 4 with epg and routed_outside ( mutually exclusive error ) + cisco.aci.aci_access_span_src_group_src: + <<: *aci_info + source_group: span_src_group_4 + epg: + tenant: tenant1 + ap: ap1 + epg: epg3 + routed_outside: + tenant: tenant1 + l3out: l3out2 + encap: 1090 + source: span_src_4 + state: present + ignore_errors: true + register: err_mutually_exclusive_epg_routed_outside + +- name: Add access span source 4 with filter_group and drop_packets( drop_packets true error ) + cisco.aci.aci_access_span_src_group_src: + <<: *aci_info + source_group: span_src_group_4 + filter_group: span_filter_group_1 + source: span_src_4 + drop_packets: true + ignore_errors: true + register: err_filter_group_drop_packets + +- name: Add access span source 4 with epg and drop_packets ( drop_packets true error ) + cisco.aci.aci_access_span_src_group_src: + <<: *aci_info + source_group: span_src_group_4 + source: span_src_4 + epg: + tenant: tenant1 + ap: ap1 + epg: epg3 + drop_packets: true + ignore_errors: true + register: err_epg_drop_packets + +- name: Add access span source 4 with routed_outside and drop_packets ( drop_packets true error ) + cisco.aci.aci_access_span_src_group_src: + <<: *aci_info + source_group: span_src_group_4 + source: span_src_4 + routed_outside: + tenant: tenant1 + l3out: l3out2 + encap: 1090 + drop_packets: true + ignore_errors: true + register: err_routed_outside_drop_packets + +- name: Add access span source 4 with drop_packets true ( parent filter group config error ) + cisco.aci.aci_access_span_src_group_src: + <<: *aci_info + source_group: span_src_group_4 + source: span_src_4 + drop_packets: true + state: present + ignore_errors: true + register: err_parent_filter_and_drop_packets + +- name: Verify errors on incorrect input + ansible.builtin.assert: + that: + - err_mutually_exclusive_epg_routed_outside.msg == "parameters are mutually exclusive{{':'}} epg|routed_outside" + - err_filter_group_drop_packets.msg == "Setting 'drop_packets' to 'true' is not allowed when 'filter_group' is configured on the source." + - err_epg_drop_packets.msg == "Setting 'drop_packets' to 'true' is not allowed when 'epg' is configured on the source." + - err_routed_outside_drop_packets.msg == "Setting 'drop_packets' to 'true' is not allowed when 'routed_outside' is configured on the source." + - err_parent_filter_and_drop_packets.msg == "APIC Error 105{{':'}} Span on drop not supported for the configuration" + +# TEST REMOVAL SOURCE + +- name: Remove span source group ( checkmode ) + cisco.aci.aci_access_span_src_group_src: &remove_span_src_1 + <<: *change_span_src_1 + state: absent + check_mode: true + register: cm_remove_span_src_1 + +- name: Remove span source group + cisco.aci.aci_access_span_src_group_src: + <<: *remove_span_src_1 + register: nm_remove_span_src_1 + +- name: Remove span source group again + cisco.aci.aci_access_span_src_group_src: + <<: *remove_span_src_1 + register: nm_remove_span_src_1_again + +- name: Verify remove access span destination groups + ansible.builtin.assert: + that: + - cm_remove_span_src_1 is changed + - cm_remove_span_src_1.current | length == 1 + - cm_remove_span_src_1.previous | length == 1 + - cm_remove_span_src_1.proposed == {} + - nm_remove_span_src_1 is changed + - nm_remove_span_src_1.current == [] + - nm_remove_span_src_1.previous | length == 1 + - nm_remove_span_src_1_again is not changed + - nm_remove_span_src_1_again.current == [] + - nm_remove_span_src_1_again.previous == [] + +# CLEAN TEST ENVIRONMENT AFTER TESTS + +- name: Query all span source groups ( clean after ) + cisco.aci.aci_access_span_src_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean access span source groups ( clean after ) + cisco.aci.aci_access_span_src_group: + <<: *aci_info + source_group: "{{ item.spanSrcGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Query all span destination groups ( clean after ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean access span destination groups ( clean after ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Execute tasks only for non-cloud sites ( clean after ) + when: + - query_cloud.current == [] + block: + - name: Query all access span filter groups ( clean after ) + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + state: query + register: query_for_clean + + - name: Clean access span filter groups ( clean after ) + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + filter_group: "{{ item.spanFilterGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group_src_path/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group_src_path/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group_src_path/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group_src_path/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group_src_path/tasks/main.yml new file mode 100644 index 000000000..f370b1323 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_src_group_src_path/tasks/main.yml @@ -0,0 +1,280 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Akini Ross (@akinross) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +# CLEAN TEST ENVIRONMENT BEFORE TESTS + +- name: Query all span source groups ( clean before ) + cisco.aci.aci_access_span_src_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean access span source groups ( clean before ) + cisco.aci.aci_access_span_src_group: + <<: *aci_info + source_group: "{{ item.spanSrcGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Query all span destination groups ( clean before ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean access span destination groups ( clean before ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Add access span destination group type epg ( clean before ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + destination_group: span_dest_1 + description: test span epg + destination_epg: + destination_ip: 10.0.0.1 + source_ip: 10.0.2.1 + tenant: ansible_test + ap: ansible_test + epg: ansible_test + state: present + +- name: Add access span source group 1 ( clean before ) + cisco.aci.aci_access_span_src_group: + <<: *aci_info + source_group: span_src_group_1 + destination_group: span_dest_1 + state: present + +- name: Add access span source group source 1 ( clean before ) + cisco.aci.aci_access_span_src_group_src: + <<: *aci_info + source_group: span_src_group_1 + source: span_src_1 + state: present + +# TEST CREATE SOURCE PATHS + +- name: Add access span source path 1 of type port ( checkmode ) + cisco.aci.aci_access_span_src_group_src_path: &span_src_path_1 + <<: *aci_info + source_group: span_src_group_1 + source: span_src_1 + pod: 1 + nodes: + - 101 + path_ep: eth1/1 + state: present + check_mode: true + register: cm_span_src_path_1 + +- name: Add access span source 1 of type port + cisco.aci.aci_access_span_src_group_src_path: + <<: *span_src_path_1 + register: nm_span_src_path_1 + +- name: Add access span source 1 of type port again + cisco.aci.aci_access_span_src_group_src_path: + <<: *span_src_path_1 + register: nm_span_src_path_1_again + +- name: Add access span source path 2 of type Direct Port Channel + cisco.aci.aci_access_span_src_group_src_path: + <<: *aci_info + source_group: span_src_group_1 + source: span_src_1 + pod: 1 + nodes: + - 101 + path_ep: test_pc_pol_group + state: present + register: nm_span_src_path_2 + +- name: Add access span source path 3 of type VPC component PC + cisco.aci.aci_access_span_src_group_src_path: + <<: *aci_info + source_group: span_src_group_1 + source: span_src_1 + pod: 1 + nodes: + - 101 + path_ep: test_vpc_pol_group + state: present + register: nm_span_src_path_3 + +- name: Add access span source path 4 of type Virtual Port Channel + cisco.aci.aci_access_span_src_group_src_path: + <<: *aci_info + source_group: span_src_group_1 + source: span_src_1 + pod: 1 + nodes: + - 101 + - 104 + path_ep: test_vpc_pol_group + state: present + register: nm_span_src_path_4 + +- name: Verify add access span source group 1 of type port + ansible.builtin.assert: + that: + - cm_span_src_path_1 is changed + - cm_span_src_path_1.previous == [] + - cm_span_src_path_1.current == [] + - cm_span_src_path_1.proposed.spanRsSrcToPathEp.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - cm_span_src_path_1.proposed.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - nm_span_src_path_1 is changed + - nm_span_src_path_1.current.0.spanRsSrcToPathEp.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - nm_span_src_path_1.current.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - nm_span_src_path_1.previous == [] + - nm_span_src_path_1_again is not changed + - nm_span_src_path_1_again.previous.0.spanRsSrcToPathEp.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - nm_span_src_path_1_again.previous.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - nm_span_src_path_1_again.current.0.spanRsSrcToPathEp.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - nm_span_src_path_1_again.current.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - nm_span_src_path_2 is changed + - nm_span_src_path_2.previous == [] + - nm_span_src_path_2.current.0.spanRsSrcToPathEp.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[test_pc_pol_group]]" + - nm_span_src_path_2.current.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[test_pc_pol_group]" + - nm_span_src_path_3 is changed + - nm_span_src_path_3.previous == [] + - nm_span_src_path_3.current.0.spanRsSrcToPathEp.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[test_vpc_pol_group]]" + - nm_span_src_path_3.current.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[test_vpc_pol_group]" + - nm_span_src_path_4 is changed + - nm_span_src_path_4.previous == [] + - nm_span_src_path_4.current.0.spanRsSrcToPathEp.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/protpaths-101-104/pathep-[test_vpc_pol_group]]" + - nm_span_src_path_4.current.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/protpaths-101-104/pathep-[test_vpc_pol_group]" + +# TEST QUERY SOURCE PATHS + +- name: Query span source group path span_src_path_1 + cisco.aci.aci_access_span_src_group_src_path: + <<: *span_src_path_1 + state: query + register: query_one + +- name: Query all span source group paths + cisco.aci.aci_access_span_src_group_src_path: + <<: *aci_info + state: query + register: query_all + +- name: Verify querying access span sources + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current | length == 1 + - query_one.current.0.spanRsSrcToPathEp.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - query_one.current.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - query_all is not changed + - query_all.current | length >= 4 + +# TEST ERRORS SOURCE PATHS + +- name: Add access span source path 5 of type Virtual Port Channel + cisco.aci.aci_access_span_src_group_src_path: + <<: *aci_info + source_group: span_src_group_1 + source: span_src_1 + pod: 1 + nodes: + - 101 + - 102 + - 104 + path_ep: test_vpc_pol_group + state: present + ignore_errors: true + register: err_too_many_nodes + +- name: Verify errors on incorrect input + ansible.builtin.assert: + that: + - err_too_many_nodes.msg == "3 nodes have been provided, where a maximum of 2 nodes is allowed." + +# TEST REMOVAL SOURCE PATHS + +- name: Remove span source group ( checkmode ) + cisco.aci.aci_access_span_src_group_src_path: &remove_span_src_path_1 + <<: *span_src_path_1 + state: absent + check_mode: true + register: cm_remove_span_src_path_1 + +- name: Remove span source group + cisco.aci.aci_access_span_src_group_src_path: + <<: *remove_span_src_path_1 + register: nm_remove_span_src_path_1 + +- name: Remove span source group again + cisco.aci.aci_access_span_src_group_src_path: + <<: *remove_span_src_path_1 + register: nm_remove_span_src_path_1_again + +- name: Verify remove access span destination groups + ansible.builtin.assert: + that: + - cm_remove_span_src_path_1 is changed + - cm_remove_span_src_path_1.current | length == 1 + - cm_remove_span_src_path_1.previous | length == 1 + - cm_remove_span_src_path_1.previous.0.spanRsSrcToPathEp.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - cm_remove_span_src_path_1.previous.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - cm_remove_span_src_path_1.current.0.spanRsSrcToPathEp.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - cm_remove_span_src_path_1.current.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - cm_remove_span_src_path_1.proposed == {} + - nm_remove_span_src_path_1 is changed + - nm_remove_span_src_path_1.current == [] + - nm_remove_span_src_path_1.previous | length == 1 + - nm_remove_span_src_path_1.previous.0.spanRsSrcToPathEp.attributes.dn == "uni/infra/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - nm_remove_span_src_path_1.previous.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - nm_remove_span_src_path_1_again is not changed + - nm_remove_span_src_path_1_again.current == [] + - nm_remove_span_src_path_1_again.previous == [] + +# CLEAN TEST ENVIRONMENT AFTER TESTS + +- name: Query all span source groups ( clean after ) + cisco.aci.aci_access_span_src_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean access span source groups ( clean after ) + cisco.aci.aci_access_span_src_group: + <<: *aci_info + source_group: "{{ item.spanSrcGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Query all span destination groups ( clean after ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean access span destination groups ( clean after ) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aep_to_domain/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_aep_to_domain/tasks/main.yml index a69d255ff..2a4f6f23e 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_aep_to_domain/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aep_to_domain/tasks/main.yml @@ -8,6 +8,18 @@ msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined +- name: Set vars + ansible.builtin.set_fact: + aci_info: &aci_info + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug # required debug due to asserts done on url which are only present in debug mode + + - name: Verify Cloud and Non-Cloud Sites in use. include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml @@ -17,55 +29,43 @@ # CLEAN ENVIRONMENT - name: Remove AEP to domain binding cisco.aci.aci_aep_to_domain: &binding_absent - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' + <<: *aci_info aep: test_aep domain: phys_dom domain_type: phys state: absent + - name: Delete AEP + cisco.aci.aci_aep: + <<: *aci_info + aep: test_aep + description: Test AEP + state: absent + - name: Create AEP cisco.aci.aci_aep: - host: "{{ aci_hostname }}" - username: "{{ aci_username }}" - password: "{{ aci_password }}" - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' + <<: *aci_info aep: test_aep description: Test AEP state: present - name: Create physical domain cisco.aci.aci_domain: - host: "{{ aci_hostname }}" - username: "{{ aci_username }}" - password: "{{ aci_password }}" - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' + <<: *aci_info domain: phys_dom domain_type: phys state: present + - name: Ensure vmm domain exist + cisco.aci.aci_rest: + <<: *aci_info + path: api/mo/uni/vmmp-VMware/dom-anstest.json + content: {"vmmDomP": {"attributes": {}}} # ADD BINDING - name: Add AEP to domain binding (check_mode) cisco.aci.aci_aep_to_domain: &binding_present - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' + <<: *aci_info aep: test_aep domain: phys_dom domain_type: phys @@ -104,17 +104,67 @@ - cm_add_binding_again is not changed - nm_add_binding_again is not changed + - name: Add AEP to domain type not vmm with vm provider (error) + cisco.aci.aci_aep_to_domain: + <<: *aci_info + aep: test_aep + domain: phys_dom + domain_type: phys + vm_provider: vmware + ignore_errors: true + register: err_not_vmm_with_vm_provider + + - name: Add AEP to domain with type fc + cisco.aci.aci_aep_to_domain: + <<: *aci_info + aep: test_aep + domain: fc_dom + domain_type: fc + register: nm_fc_type + + - name: Add AEP to domain with type l2dom + cisco.aci.aci_aep_to_domain: + <<: *aci_info + aep: test_aep + domain: l2dom_dom + domain_type: l2dom + register: nm_l2dom_type + + - name: Add AEP to domain with type l3dom + cisco.aci.aci_aep_to_domain: + <<: *aci_info + aep: test_aep + domain: l3dom_dom + domain_type: l3dom + register: nm_l3dom_type + + - name: Add AEP to domain with type vmm + cisco.aci.aci_aep_to_domain: + <<: *aci_info + aep: test_aep + domain: anstest + domain_type: vmm + vm_provider: vmware + register: nm_vmm_type + + - name: Verify bindings with domain types + assert: + that: + - err_not_vmm_with_vm_provider is not changed + - err_not_vmm_with_vm_provider.msg == "Domain type 'phys' cannot have a 'vm_provider'" + - nm_fc_type is changed + - nm_fc_type.current.0.infraRsDomP.attributes.tDn == "uni/fc-fc_dom" + - nm_l2dom_type is changed + - nm_l2dom_type.current.0.infraRsDomP.attributes.tDn == "uni/l2dom-l2dom_dom" + - nm_l3dom_type is changed + - nm_l3dom_type.current.0.infraRsDomP.attributes.tDn == "uni/l3dom-l3dom_dom" + - nm_vmm_type is changed + - nm_vmm_type.current.0.infraRsDomP.attributes.tDn == "uni/vmmp-VMware/dom-anstest" # QUERY ALL BINDINGS - name: Query all AEP to domain bindings (check_mode) cisco.aci.aci_aep_to_domain: &binding_query - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' + <<: *aci_info state: query check_mode: true register: cm_query_all_bindings diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_subnet/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_subnet/tasks/main.yml index 10f00990c..4bc8e26c4 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_subnet/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_subnet/tasks/main.yml @@ -8,6 +8,24 @@ msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Query system information + cisco.aci.aci_system: + <<: *aci_info + id: 1 + state: query + register: version + - name: Verify Cloud and Non-Cloud Sites in use. include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml @@ -16,17 +34,17 @@ block: # block specifies execution of tasks within, based on conditions - name: ensure tenant exists for tests to kick off cisco.aci.aci_tenant: &aci_tenant_present - host: "{{ aci_hostname }}" - username: "{{ aci_username }}" - password: "{{ aci_password }}" - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug - state: present + <<: *aci_info tenant: ansible_test register: tenant_present + - name: Query system information + cisco.aci.aci_system: + <<: *aci_info + id: 1 + state: query + register: version + - name: ensure bd exists for tests to kick off cisco.aci.aci_bd: &aci_bd_present <<: *aci_tenant_present @@ -60,7 +78,7 @@ <<: *aci_subnet_present register: create_subnet - - name: create new subnet - creation works + - name: create new subnet - creation works (with no ip_data_plane_learning - APIC version < 5.0) cisco.aci.aci_bd_subnet: &aci_subnet2_present <<: *aci_subnet2_absent state: present @@ -69,6 +87,19 @@ route_profile: default route_profile_l3_out: default register: create_subnet2 + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: create new subnet - creation works (with ip_data_plane_learning - APIC version >= 5.0) + cisco.aci.aci_bd_subnet: + <<: *aci_subnet2_present + state: present + descr: Ansible Test + scope: [private, shared] + route_profile: default + route_profile_l3_out: default + ip_data_plane_learning: disabled + register: create_subnet2_5 + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: create subnet again - idempotency works cisco.aci.aci_bd_subnet: @@ -96,7 +127,7 @@ register: create_incomplete_data ignore_errors: true - - name: asserts for subnet creation tasks + - name: assert for subnet creation tasks assert: that: - create_check_mode is changed @@ -106,11 +137,6 @@ - create_subnet is changed - create_subnet.current.0.fvSubnet.attributes.annotation == 'orchestrator:ansible' - create_subnet.previous == [] - - create_subnet2 is changed - - create_subnet2.sent == create_subnet2.proposed - - create_subnet2.sent.fvSubnet.attributes.scope == "private,shared" - - create_subnet2.sent.fvSubnet.children.0.fvRsBDSubnetToProfile.attributes.tnL3extOutName == 'default' - - create_subnet2.sent.fvSubnet.children.0.fvRsBDSubnetToProfile.attributes.tnRtctrlProfileName == 'default' - create_idempotency is not changed - create_idempotency.previous != [] - modify_subnet is changed @@ -123,6 +149,28 @@ - create_incomplete_data is failed - 'create_incomplete_data.msg == "state is present but all of the following are missing: bd"' + - name: assert for subnet for task with version < 5 + assert: + that: + - create_subnet2 is changed + - create_subnet2.sent == create_subnet2.proposed + - create_subnet2.sent.fvSubnet.attributes.scope == "private,shared" + - create_subnet2.sent.fvSubnet.children.0.fvRsBDSubnetToProfile.attributes.tnL3extOutName == 'default' + - create_subnet2.sent.fvSubnet.children.0.fvRsBDSubnetToProfile.attributes.tnRtctrlProfileName == 'default' + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: assert for subnet ip_data_learning for task with version >=5 + assert: + that: + - create_subnet.current.0.fvSubnet.attributes.ipDPLearning == 'enabled' + - create_subnet2_5 is changed + - create_subnet2_5.current.0.fvSubnet.attributes.ipDPLearning == 'disabled' + - create_subnet2_5.sent == create_subnet2_5.proposed + - create_subnet2_5.sent.fvSubnet.attributes.scope == "private,shared" + - create_subnet2_5.sent.fvSubnet.children.0.fvRsBDSubnetToProfile.attributes.tnL3extOutName == 'default' + - create_subnet2_5.sent.fvSubnet.children.0.fvRsBDSubnetToProfile.attributes.tnRtctrlProfileName == 'default' + when: version.current.0.topSystem.attributes.version is version('5', '>=') + - name: get all subnets cisco.aci.aci_bd_subnet: &aci_query <<: *aci_tenant_present @@ -203,6 +251,28 @@ - '"query-target-filter=eq(fvSubnet.ip,\"10.100.100.1/24\")" in get_subnets_gateway.filter_string' - '"class/fvSubnet.json" in get_subnets_gateway.url' + - name: error handling for ipv4 subnet with wrong mask + cisco.aci.aci_bd_subnet: + <<: *aci_bd_present + gateway: 10.100.100.1 + mask: 33 + ignore_errors: true + register: error_mask_ipv4 + + - name: error handling for ipv6 subnet with wrong mask + cisco.aci.aci_bd_subnet: + <<: *aci_bd_present + gateway: "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + mask: 129 + ignore_errors: true + register: error_mask_ipv6 + + - name: asserts for mask error handling + assert: + that: + - error_mask_ipv4.msg == "Valid Subnet Masks are 0 to 32 for IPv4 Addresses" + - error_mask_ipv6.msg == "Valid Subnet Masks are 0 to 128 for IPv6 Addresses" + - name: delete subnet - check mode works cisco.aci.aci_bd_subnet: <<: *aci_subnet_absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_to_l3out/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_to_l3out/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_to_l3out/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_to_l3out/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_to_l3out/tasks/main.yml new file mode 100644 index 000000000..7d1313fb2 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_to_l3out/tasks/main.yml @@ -0,0 +1,202 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + cisco.aci.aci_tenant: &aci_tenant_absent + <<: *aci_info + state: absent + tenant: ansible_test + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Create tenant + cisco.aci.aci_tenant: &aci_tenant_present + <<: *aci_tenant_absent + state: present + + - name: Create vrf + cisco.aci.aci_vrf: &aci_vrf_present + <<: *aci_tenant_present + vrf: anstest + + - name: Create first L3out + cisco.aci.aci_l3out: &aci_l3_out_present + <<: *aci_vrf_present + l3out: ansible_l3out + domain: ansible_dom + state: present + + - name: Create second L3out + cisco.aci.aci_l3out: &aci_l3_out_present_2 + <<: *aci_vrf_present + l3out: ansible_l3out_2 + domain: ansible_dom + state: present + + - name: Create first bd + cisco.aci.aci_bd: &aci_bd_present + <<: *aci_tenant_present + bd: anstest + + - name: Create second bd + cisco.aci.aci_bd: &aci_bd_present_2 + <<: *aci_tenant_present + bd: anstest_2 + + - name: Ensure first binding bd_to_l3out does not exist + cisco.aci.aci_bd_to_l3out: &aci_bd_to_l3out_absent + <<: *aci_tenant_present + bd: anstest + l3out: ansible_l3out + state: absent + + - name: Ensure second binding bd_to_l3out does not exist + cisco.aci.aci_bd_to_l3out: &aci_bd_to_l3out_absent_2 + <<: *aci_tenant_present + bd: anstest_2 + l3out: ansible_l3out_2 + state: absent + + - name: bind bd to L3out - first binding (check_mode) + cisco.aci.aci_bd_to_l3out: &aci_bd_to_l3out_present + <<: *aci_bd_to_l3out_absent + state: present + check_mode: true + register: cm_bd_to_l3out + + - name: bind bd to L3out - first binding (normal_mode) + cisco.aci.aci_bd_to_l3out: + <<: *aci_bd_to_l3out_present + register: nm_bd_to_l3out + + - name: bind bd to L3out again - testing idempotency + cisco.aci.aci_bd_to_l3out: + <<: *aci_bd_to_l3out_present + register: bd_to_l3out_idempotency + + - name: bind bd to L3out - second binding + cisco.aci.aci_bd_to_l3out: &aci_bd_to_l3out_present_2 + <<: *aci_bd_to_l3out_absent_2 + state: present + register: nm_bd_to_l3out_2 + + - name: asserts for creation tasks + assert: + that: + - cm_bd_to_l3out is changed + - cm_bd_to_l3out.previous == [] + - cm_bd_to_l3out.current == [] + - nm_bd_to_l3out is changed + - nm_bd_to_l3out.current.0.fvRsBDToOut.attributes.dn == "uni/tn-ansible_test/BD-anstest/rsBDToOut-ansible_l3out" + - nm_bd_to_l3out.current.0.fvRsBDToOut.attributes.tnL3extOutName == "ansible_l3out" + - bd_to_l3out_idempotency is not changed + - nm_bd_to_l3out_2 is changed + - nm_bd_to_l3out_2.current.0.fvRsBDToOut.attributes.dn == "uni/tn-ansible_test/BD-anstest_2/rsBDToOut-ansible_l3out_2" + - nm_bd_to_l3out_2.current.0.fvRsBDToOut.attributes.tnL3extOutName == "ansible_l3out_2" + + - name: Query all bds bound to l3outs + cisco.aci.aci_bd_to_l3out: + <<: *aci_tenant_present + state: query + register: query_all_bd_to_l3out + + - name: Query first bd bound to first l3out + cisco.aci.aci_bd_to_l3out: + <<: *aci_bd_to_l3out_present + state: query + register: query_first_bd_to_l3out + + - name: asserts query tasks + assert: + that: + - query_all_bd_to_l3out is not changed + - '"fvRsBDToOut" in query_all_bd_to_l3out.filter_string' + - query_all_bd_to_l3out.current.0.fvTenant.children | length >= 2 + - query_all_bd_to_l3out.current.0.fvTenant.children.0.fvBD.attributes.name == "anstest_2" + - query_all_bd_to_l3out.current.0.fvTenant.children.0.fvBD.children.0.fvRsBDToOut.attributes.tRn == "out-ansible_l3out_2" + - query_all_bd_to_l3out.current.0.fvTenant.children.1.fvBD.attributes.name == "anstest" + - query_all_bd_to_l3out.current.0.fvTenant.children.1.fvBD.children.0.fvRsBDToOut.attributes.tRn == "out-ansible_l3out" + - query_first_bd_to_l3out is not changed + - '"tn-ansible_test/BD-anstest/rsBDToOut-ansible_l3out.json" in query_first_bd_to_l3out.url' + + - name: unbind bd to l3out - first binding (check_mode) + cisco.aci.aci_bd_to_l3out: + <<: *aci_bd_to_l3out_present + state: absent + check_mode: true + register: cm_unbind_bd_to_l3out + + - name: unbind bd to l3out - first binding (normal_mode) + cisco.aci.aci_bd_to_l3out: + <<: *aci_bd_to_l3out_present + state: absent + register: nm_unbind_bd_to_l3out + + - name: unbind bd to l3out again - testing idempotency + cisco.aci.aci_bd_to_l3out: + <<: *aci_bd_to_l3out_present + state: absent + register: unbind_bd_to_l3out_idempotency + + - name: unbind bd to l3out - second binding + cisco.aci.aci_bd_to_l3out: + <<: *aci_bd_to_l3out_present_2 + state: absent + register: nm_unbind_bd_to_l3out_2 + + - name: asserts for deletion tasks + assert: + that: + - cm_unbind_bd_to_l3out is changed + - cm_unbind_bd_to_l3out.proposed == {} + - nm_unbind_bd_to_l3out is changed + - nm_unbind_bd_to_l3out.previous != [] + - nm_unbind_bd_to_l3out.method == "DELETE" + - unbind_bd_to_l3out_idempotency is not changed + - unbind_bd_to_l3out_idempotency.previous == [] + - nm_unbind_bd_to_l3out_2 is changed + - nm_unbind_bd_to_l3out_2.previous != [] + - nm_unbind_bd_to_l3out_2.method == "DELETE" + + - name: delete bd - cleanup before ending tests + cisco.aci.aci_bd: + <<: *aci_bd_present + state: absent + + - name: delete l3out - cleanup before ending tests + cisco.aci.aci_l3out: + <<: *aci_l3_out_present + state: absent + + - name: delete vrf - cleanup before ending tests + cisco.aci.aci_vrf: + <<: *aci_vrf_present + state: absent + + - name: delete tenant - cleanup before ending tests + cisco.aci.aci_tenant: + <<: *aci_tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_best_path_policy/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_best_path_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_best_path_policy/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_best_path_policy/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_best_path_policy/tasks/main.yml new file mode 100644 index 000000000..d0eae2666 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_best_path_policy/tasks/main.yml @@ -0,0 +1,140 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a BGP best path policy (check_mode) + aci_bgp_best_path_policy: &aci_bgp_best_path_policy_present + <<: *aci_info + tenant: ansible_tenant + bgp_best_path_policy: ansible_bgp_best_path_policy_1 + best_path_control: enable + description: BGP best path policy 1 for ansible_tenant tenant + state: present + check_mode: true + register: cm_add_bgp_best_path_policy + + - name: Add a BGP best path policy (normal_mode) + aci_bgp_best_path_policy: + <<: *aci_bgp_best_path_policy_present + register: nm_add_bgp_best_path_policy + + - name: Add the first BGP best path policy again - testing idempotency + aci_bgp_best_path_policy: + <<: *aci_bgp_best_path_policy_present + register: nm_add_bgp_best_path_policy_idempotency + + - name: Add a second BGP best path policy (normal_mode) + aci_bgp_best_path_policy: + <<: *aci_info + tenant: ansible_tenant + bgp_best_path_policy: ansible_bgp_best_path_policy_2 + best_path_control: disable + description: BGP best path policy 2 for ansible_tenant tenant + state: present + register: nm_add_bgp_best_path_policy_2 + + - name: Asserts for BGP best path policys creation tasks + assert: + that: + - cm_add_bgp_best_path_policy is changed + - cm_add_bgp_best_path_policy.previous == [] + - cm_add_bgp_best_path_policy.current == [] + - nm_add_bgp_best_path_policy is changed + - nm_add_bgp_best_path_policy.current.0.bgpBestPathCtrlPol.attributes.name == "ansible_bgp_best_path_policy_1" + - nm_add_bgp_best_path_policy.current.0.bgpBestPathCtrlPol.attributes.ctrl == "asPathMultipathRelax" + - nm_add_bgp_best_path_policy_idempotency is not changed + - nm_add_bgp_best_path_policy_2 is changed + - nm_add_bgp_best_path_policy_2.previous == [] + - nm_add_bgp_best_path_policy_2.current.0.bgpBestPathCtrlPol.attributes.name == "ansible_bgp_best_path_policy_2" + - nm_add_bgp_best_path_policy_2.current.0.bgpBestPathCtrlPol.attributes.ctrl == "" + + - name: Query all BGP best path policies + aci_bgp_best_path_policy: + <<: *aci_info + state: query + register: query_all_bgp_best_path_policy + + - name: Query ansible_bgp_best_path_policy_1 + aci_bgp_best_path_policy: + <<: *aci_bgp_best_path_policy_present + state: query + register: query_ansible_bgp_best_path_policy_1 + + - name: Asserts query tasks + assert: + that: + - query_all_bgp_best_path_policy is not changed + - query_all_bgp_best_path_policy.current|length >= 2 + - query_ansible_bgp_best_path_policy_1 is not changed + - query_ansible_bgp_best_path_policy_1.current.0.bgpBestPathCtrlPol.attributes.name == "ansible_bgp_best_path_policy_1" + - query_ansible_bgp_best_path_policy_1.current.0.bgpBestPathCtrlPol.attributes.ctrl == "asPathMultipathRelax" + + - name: Remove BGP best path policy (check_mode) + aci_bgp_best_path_policy: &bgp_best_path_policy_absent + <<: *aci_bgp_best_path_policy_present + state: absent + check_mode: true + register: cm_remove_bgp_best_path_policy + + - name: Remove BGP best path policy (normal_mode) + aci_bgp_best_path_policy: + <<: *bgp_best_path_policy_absent + register: nm_remove_bgp_best_path_policy + + - name: Remove BGP best path policy - testing idempotency + aci_bgp_best_path_policy: + <<: *bgp_best_path_policy_absent + register: nm_remove_bgp_best_path_policy_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_bgp_best_path_policy is changed + - cm_remove_bgp_best_path_policy.proposed == {} + - nm_remove_bgp_best_path_policy is changed + - nm_remove_bgp_best_path_policy.previous != [] + - nm_remove_bgp_best_path_policy.method == "DELETE" + - nm_remove_bgp_best_path_policy_idempotency is not changed + - nm_remove_bgp_best_path_policy_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_timers_policy/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_timers_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_timers_policy/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_timers_policy/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_timers_policy/tasks/main.yml new file mode 100644 index 000000000..0c7cdd77d --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_timers_policy/tasks/main.yml @@ -0,0 +1,155 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a BGP timers policy (check_mode) + aci_bgp_timers_policy: &aci_bgp_timers_policy_present + <<: *aci_info + tenant: ansible_tenant + bgp_timers_policy: ansible_bgp_timers_policy_1 + graceful_restart_controls: complete + hold_interval: 360 + keepalive_interval: 120 + max_as_limit: 1 + stale_interval: 600 + description: BGP timers policy 1 for ansible_tenant tenant + state: present + check_mode: true + register: cm_add_bgp_timers_policy + + - name: Add a BGP timers policy (normal_mode) + aci_bgp_timers_policy: + <<: *aci_bgp_timers_policy_present + register: nm_add_bgp_timers_policy + + - name: Add the first BGP timers policy again - testing idempotency + aci_bgp_timers_policy: + <<: *aci_bgp_timers_policy_present + register: nm_add_bgp_timers_policy_idempotency + + - name: Add a second BGP timers policy (normal_mode) + aci_bgp_timers_policy: + <<: *aci_info + tenant: ansible_tenant + bgp_timers_policy: ansible_bgp_timers_policy_2 + description: BGP timers policy 2 for ansible_tenant tenant + state: present + register: nm_add_bgp_timers_policy_2 + + - name: Asserts for BGP timers policys creation tasks + assert: + that: + - cm_add_bgp_timers_policy is changed + - cm_add_bgp_timers_policy.previous == [] + - cm_add_bgp_timers_policy.current == [] + - nm_add_bgp_timers_policy is changed + - nm_add_bgp_timers_policy.current.0.bgpCtxPol.attributes.name == "ansible_bgp_timers_policy_1" + - nm_add_bgp_timers_policy.current.0.bgpCtxPol.attributes.grCtrl == "" + - nm_add_bgp_timers_policy.current.0.bgpCtxPol.attributes.holdIntvl == "360" + - nm_add_bgp_timers_policy.current.0.bgpCtxPol.attributes.kaIntvl == "120" + - nm_add_bgp_timers_policy.current.0.bgpCtxPol.attributes.maxAsLimit == "1" + - nm_add_bgp_timers_policy.current.0.bgpCtxPol.attributes.staleIntvl == "600" + - nm_add_bgp_timers_policy_idempotency is not changed + - nm_add_bgp_timers_policy_2 is changed + - nm_add_bgp_timers_policy_2.previous == [] + - nm_add_bgp_timers_policy_2.current.0.bgpCtxPol.attributes.name == "ansible_bgp_timers_policy_2" + - nm_add_bgp_timers_policy_2.current.0.bgpCtxPol.attributes.grCtrl == "helper" + - nm_add_bgp_timers_policy_2.current.0.bgpCtxPol.attributes.holdIntvl == "180" + - nm_add_bgp_timers_policy_2.current.0.bgpCtxPol.attributes.kaIntvl == "60" + - nm_add_bgp_timers_policy_2.current.0.bgpCtxPol.attributes.maxAsLimit == "0" + - nm_add_bgp_timers_policy_2.current.0.bgpCtxPol.attributes.staleIntvl == "default" + + - name: Query all BGP timers policies + aci_bgp_timers_policy: + <<: *aci_info + state: query + register: query_all_bgp_timers_policy + + - name: Query ansible_bgp_timers_policy_1 + aci_bgp_timers_policy: + <<: *aci_bgp_timers_policy_present + state: query + register: query_ansible_bgp_timers_policy_1 + + - name: Asserts query tasks + assert: + that: + - query_all_bgp_timers_policy is not changed + - query_all_bgp_timers_policy.current|length >= 2 + - query_ansible_bgp_timers_policy_1 is not changed + - query_ansible_bgp_timers_policy_1.current.0.bgpCtxPol.attributes.name == "ansible_bgp_timers_policy_1" + - query_ansible_bgp_timers_policy_1.current.0.bgpCtxPol.attributes.grCtrl == "" + - query_ansible_bgp_timers_policy_1.current.0.bgpCtxPol.attributes.holdIntvl == "360" + - query_ansible_bgp_timers_policy_1.current.0.bgpCtxPol.attributes.kaIntvl == "120" + - query_ansible_bgp_timers_policy_1.current.0.bgpCtxPol.attributes.maxAsLimit == "1" + - query_ansible_bgp_timers_policy_1.current.0.bgpCtxPol.attributes.staleIntvl == "600" + + - name: Remove BGP timers policy (check_mode) + aci_bgp_timers_policy: &bgp_timers_policy_absent + <<: *aci_bgp_timers_policy_present + state: absent + check_mode: true + register: cm_remove_bgp_timers_policy + + - name: Remove BGP timers policy (normal_mode) + aci_bgp_timers_policy: + <<: *bgp_timers_policy_absent + register: nm_remove_bgp_timers_policy + + - name: Remove BGP timers policy - testing idempotency + aci_bgp_timers_policy: + <<: *bgp_timers_policy_absent + register: nm_remove_bgp_timers_policy_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_bgp_timers_policy is changed + - cm_remove_bgp_timers_policy.proposed == {} + - nm_remove_bgp_timers_policy is changed + - nm_remove_bgp_timers_policy.previous != [] + - nm_remove_bgp_timers_policy.method == "DELETE" + - nm_remove_bgp_timers_policy_idempotency is not changed + - nm_remove_bgp_timers_policy_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_config_rollback/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_rollback/tasks/main.yml index df4c64069..9b43c9cfc 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_config_rollback/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_rollback/tasks/main.yml @@ -20,6 +20,9 @@ state: absent tenant: ansible_test +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + - name: create a snapshot cisco.aci.aci_config_snapshot: &create_snapshot <<: *aci_tenant_absent @@ -49,62 +52,128 @@ state: query register: snapshots -- name: sort snapshot list - set_fact: - sorted_snapshots: '{{ snapshots.current.0.configSnapshotCont.children | sort(attribute="configSnapshot.attributes.createTime", reverse=True) }}' - -- name: compare snapshots - cisco.aci.aci_config_rollback: &preview_rollback - <<: *create_snapshot - state: preview - compare_export_policy: anstest - compare_snapshot: "{{ sorted_snapshots[0].configSnapshot.attributes.name }}" - snapshot: "{{ sorted_snapshots[1].configSnapshot.attributes.name }}" - register: rollback_preview - -- name: rollback to snapshot with missing parameters - cisco.aci.aci_config_rollback: &aci_rollback - <<: *create_snapshot - state: rollback - snapshot: "{{ sorted_snapshots[1].configSnapshot.attributes.name }}" - ignore_errors: true - register: rollback_missing_param - -- name: rollback to snapshot - cisco.aci.aci_config_rollback: - <<: *aci_rollback - import_policy: anstest - import_type: replace - import_mode: atomic - register: rollback_rollback - -- name: pause execution to let rollback take effect - pause: - seconds: 15 - -- name: ensure tenant doesn't exist after rollback - cisco.aci.aci_tenant: - <<: *aci_tenant_absent - register: tenant_removed - -- debug: - msg: '{{ rollback_preview }}' - -- name: rollback assertions - assert: - that: - - rollback_preview is not changed - - rollback_preview.preview.polUni.children[0].fvTenant.attributes.name == 'ansible_test' - - rollback_preview.preview.polUni.children[0].fvTenant.attributes.status == 'created' - - '"snapshots.diff.xml" in rollback_preview.url' - - rollback_missing_param is failed - - 'rollback_missing_param.msg == "state is rollback but all of the following are missing: import_policy"' - - rollback_rollback is changed - - '"ce2_" in rollback_rollback.sent.configImportP.attributes.fileName' - - '".tar.gz" in rollback_rollback.sent.configImportP.attributes.fileName' - - '"ce2_" in rollback_rollback.proposed.configImportP.attributes.fileName' - - '".tar.gz" in rollback_rollback.proposed.configImportP.attributes.fileName' - - '"fabric/configimp-anstest.json" in rollback_rollback.url' - - tenant_removed is not changed - - tenant_removed.previous == [] - - create_snapshot_annotation_check.current.0.configExportP.attributes.annotation == 'orchestrator:ansible' +- name: Execute tasks only for non-cloud sites + when: query_cloud.current != [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Snapshot compare does not work for cloud site since only 1 item is returned in configSnapshotCont + # TODO further investigate why cloud sites behave differently in saving snapshots + - name: verify only one snapshot is returned + ansible.builtin.assert: + that: + - snapshots.current.0.configSnapshotCont.children | length == 1 + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Snapshot compare does not work for cloud site since only 1 item is returned in configSnapshotCont + - name: sort snapshot list + ansible.builtin.set_fact: + sorted_snapshots: '{{ snapshots.current.0.configSnapshotCont.children | sort(attribute="configSnapshot.attributes.createTime", reverse=True) }}' + + - name: Uninstall lxml for error checking + ansible.builtin.pip: &lxml + name: lxml + state: absent + ignore_errors: true # ignore errors to because of multiple executions for hosts at the same time + + - name: Uninstall xmljson for error checking + ansible.builtin.pip: &xmljson + name: xmljson + state: absent + ignore_errors: true # ignore errors to because of multiple executions for hosts at the same time + + - name: compare snapshots + cisco.aci.aci_config_rollback: &preview_rollback + <<: *create_snapshot + state: preview + compare_export_policy: anstest + compare_snapshot: "{{ sorted_snapshots[0].configSnapshot.attributes.name }}" + snapshot: "{{ sorted_snapshots[1].configSnapshot.attributes.name }}" + register: rollback_preview_xml + + - name: Install lxml + ansible.builtin.pip: + <<: *lxml + state: present + ignore_errors: true # ignore errors to because of multiple executions for hosts at the same time + + - name: Install xmljson + ansible.builtin.pip: + <<: *xmljson + state: present + ignore_errors: true # ignore errors to because of multiple executions for hosts at the same time + + - name: compare snapshots + cisco.aci.aci_config_rollback: + <<: *preview_rollback + register: rollback_preview_json + + - name: compare snapshots with wrong compare_snapshot (error) + cisco.aci.aci_config_rollback: + <<: *preview_rollback + compare_snapshot: wrong_snap + ignore_errors: true + register: err_rollback_preview_json + + - name: rollback to snapshot with missing parameters + cisco.aci.aci_config_rollback: &aci_rollback + <<: *create_snapshot + state: rollback + snapshot: "{{ sorted_snapshots[1].configSnapshot.attributes.name }}" + ignore_errors: true + register: rollback_missing_param + + - name: rollback to not existing snapshot for "tar.gz" append and "run-" removal testing + cisco.aci.aci_config_rollback: + <<: *aci_rollback + snapshot: "not-existing-snapshot.tar.gz" + import_policy: anstest + import_type: replace + import_mode: atomic + register: not_existing_rollback + ignore_errors: true + + - name: rollback to snapshot + cisco.aci.aci_config_rollback: + <<: *aci_rollback + import_policy: anstest + import_type: replace + import_mode: atomic + register: rollback_rollback + + - name: pause execution to let rollback take effect + pause: + seconds: 15 + + - name: ensure tenant doesn't exist after rollback + cisco.aci.aci_tenant: + <<: *aci_tenant_absent + register: tenant_removed + + - debug: + msg: '{{ rollback_preview_json }}' + + - name: rollback assertions + assert: + that: + - rollback_preview_xml is not changed + - '"ansible_test" in rollback_preview_xml.preview' + - '"created" in rollback_preview_xml.preview' + - '"snapshots.diff.xml" in rollback_preview_xml.url' + - err_rollback_preview_json.status == 400 + - err_rollback_preview_json.response == "HTTP Error 400{{":"}} Bad Request" + - rollback_preview_json is not changed + - rollback_preview_json.preview.polUni.children[0].fvTenant.attributes.name == 'ansible_test' + - rollback_preview_json.preview.polUni.children[0].fvTenant.attributes.status == 'created' + - '"snapshots.diff.xml" in rollback_preview_json.url' + - rollback_missing_param is failed + - 'rollback_missing_param.msg == "state is rollback but all of the following are missing: import_policy"' + - rollback_rollback is changed + - '"ce2_" in rollback_rollback.sent.configImportP.attributes.fileName' + - '".tar.gz" in rollback_rollback.sent.configImportP.attributes.fileName' + - '"ce2_" in rollback_rollback.proposed.configImportP.attributes.fileName' + - '".tar.gz" in rollback_rollback.proposed.configImportP.attributes.fileName' + - '"fabric/configimp-anstest.json" in rollback_rollback.url' + - tenant_removed is not changed + - tenant_removed.previous == [] + - create_snapshot_annotation_check.current.0.configExportP.attributes.annotation == 'orchestrator:ansible' diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_config_snapshot/pki/admin.crt b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_snapshot/pki/admin.crt new file mode 100644 index 000000000..cfac5531e --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_snapshot/pki/admin.crt @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICODCCAaGgAwIBAgIJAIt8XMntue0VMA0GCSqGSIb3DQEBCwUAMDQxDjAMBgNV +BAMMBUFkbWluMRUwEwYDVQQKDAxZb3VyIENvbXBhbnkxCzAJBgNVBAYTAlVTMCAX +DTE4MDEwOTAwNTk0NFoYDzIxMTcxMjE2MDA1OTQ0WjA0MQ4wDAYDVQQDDAVBZG1p +bjEVMBMGA1UECgwMWW91ciBDb21wYW55MQswCQYDVQQGEwJVUzCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAohG/7axtt7CbSaMP7r+2mhTKbNgh0Ww36C7Ta14i +v+VmLyKkQHnXinKGhp6uy3Nug+15a+eIu7CrgpBVMQeCiWfsnwRocKcQJWIYDrWl +XHxGQn31yYKR6mylE7Dcj3rMFybnyhezr5D8GcP85YRPmwG9H2hO/0Y1FUnWu9Iw +AQkCAwEAAaNQME4wHQYDVR0OBBYEFD0jLXfpkrU/ChzRvfruRs/fy1VXMB8GA1Ud +IwQYMBaAFD0jLXfpkrU/ChzRvfruRs/fy1VXMAwGA1UdEwQFMAMBAf8wDQYJKoZI +hvcNAQELBQADgYEAOmvre+5tgZ0+F3DgsfxNQqLTrGiBgGCIymPkP/cBXXkNuJyl +3ac7tArHQc7WEA4U2R2rZbEq8FC3UJJm4nUVtCPvEh3G9OhN2xwYev79yt6pIn/l +KU0Td2OpVyo0eLqjoX5u2G90IBWzhyjFbo+CcKMrSVKj1YOdG0E3OuiJf00= +-----END CERTIFICATE----- diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_config_snapshot/pki/admin.key b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_snapshot/pki/admin.key new file mode 100644 index 000000000..63bb00cc0 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_snapshot/pki/admin.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKIRv+2sbbewm0mj +D+6/tpoUymzYIdFsN+gu02teIr/lZi8ipEB514pyhoaerstzboPteWvniLuwq4KQ +VTEHgoln7J8EaHCnECViGA61pVx8RkJ99cmCkepspROw3I96zBcm58oXs6+Q/BnD +/OWET5sBvR9oTv9GNRVJ1rvSMAEJAgMBAAECgYByu3QO0qF9h7X3JEu0Ld4cKBnB +giQ2uJC/et7KxIJ/LOvw9GopBthyt27KwG1ntBkJpkTuAaQHkyNns7vLkNB0S0IR ++owVFEcKYq9VCHTaiQU8TDp24gN+yPTrpRuH8YhDVq5SfVdVuTMgHVQdj4ya4VlF +Gj+a7+ipxtGiLsVGrQJBAM7p0Fm0xmzi+tBOASUAcVrPLcteFIaTBFwfq16dm/ON +00Khla8Et5kMBttTbqbukl8mxFjBEEBlhQqb6EdQQ0sCQQDIhHx1a9diG7y/4DQA +4KvR3FCYwP8PBORlSamegzCo+P1OzxiEo0amX7yQMA5UyiP/kUsZrme2JBZgna8S +p4R7AkEAr7rMhSOPUnMD6V4WgsJ5g1Jp5kqkzBaYoVUUSms5RASz4+cwJVCwTX91 +Y1jcpVIBZmaaY3a0wrx13ajEAa0dOQJBAIpjnb4wqpsEh7VpmJqOdSdGxb1XXfFQ +sA0T1OQYqQnFppWwqrxIL+d9pZdiA1ITnNqyvUFBNETqDSOrUHwwb2cCQGArE+vu +ffPUWQ0j+fiK+covFG8NL7H+26NSGB5+Xsn9uwOGLj7K/YT6CbBtr9hJiuWjM1Al +0V4ltlTuu2mTMaw= +-----END PRIVATE KEY----- diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_config_snapshot/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_snapshot/tasks/main.yml index 22bcbcb79..c9415a86d 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_config_snapshot/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_snapshot/tasks/main.yml @@ -146,3 +146,82 @@ - delete_idempotent.previous == [] - delete_missing_param is failed - 'delete_missing_param.msg == "state is absent but all of the following are missing: snapshot"' + +# Create, query and delete snapshot with certificate authentication Ref# 427 +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + validate_certs: "{{ aci_validate_certs | default(false) }}" + use_ssl: "{{ aci_use_ssl | default(true) }}" + use_proxy: "{{ aci_use_proxy | default(true) }}" + output_level: debug + +- name: Add a user certificate to be used in the test + cisco.aci.aci_aaa_user_certificate: + <<: *aci_info + password: "{{ aci_password }}" + aaa_user: "{{ aci_username }}" + name: admin + certificate: "{{ lookup('file', 'pki/admin.crt') }}" + state: present + +- name: create a snapshot using the private key + cisco.aci.aci_config_snapshot: + <<: *aci_info + private_key: "{{ lookup('file', 'pki/admin.key') }}" + export_policy: anstest + include_secure: false + format: json + description: ansible test + register: create_private_key + +- name: creation assertion tests with private key + assert: + that: + - create_private_key is not failed + - create_private_key is changed + - create_private_key.sent.configExportP.attributes.adminSt == "triggered" + +- name: query the snapshot using the private key + cisco.aci.aci_config_snapshot: + <<: *aci_info + private_key: "{{ lookup('file', 'pki/admin.key') }}" + export_policy: anstest + state: query + register: query_private_key + +- name: generate snapshot name using query_private_key + set_fact: + test_snapshot_private_key: "{{ query_private_key.current.0.configSnapshotCont.children.0.configSnapshot.attributes.rn.strip('snapshot-') }}" + +- name: query assertion tests with private key + assert: + that: + - query_private_key is not failed + - query_private_key is not changed + - '"snapshots-[uni/fabric/configexp-anstest].json" in query_private_key.url' + +- name: delete using the private key + cisco.aci.aci_config_snapshot: + <<: *aci_info + private_key: "{{ lookup('file', 'pki/admin.key') }}" + export_policy: anstest + snapshot: "{{ test_snapshot_private_key }}" + state: absent + register: delete_snapshot_private_key + +- name: delete assertion tests with the private key + assert: + that: + - delete_snapshot_private_key is not failed + - delete_snapshot_private_key is changed + +- name: Remove the user certificate + cisco.aci.aci_aaa_user_certificate: + <<: *aci_info + password: "{{ aci_password }}" + aaa_user: "{{ aci_username }}" + name: admin + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject_to_filter/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject_to_filter/tasks/main.yml index f7e69e620..d21571692 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject_to_filter/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject_to_filter/tasks/main.yml @@ -129,6 +129,13 @@ state: query register: query_binding + - name: query binding with non_existing subject + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_filter_present + state: query + subject: non_existing + register: query_binding_non_existing_subject + - name: query assertions assert: that: @@ -137,6 +144,7 @@ - query_all.current.0.vzRsSubjFiltAtt is defined - query_binding is not changed - query_binding.current != [] + - query_binding_non_existing_subject.current == [] - name: delete subject filter binding - check mode works cisco.aci.aci_contract_subject_to_filter: &aci_subject_filter_absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_dhcp_relay/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_dhcp_relay/tasks/main.yml index 920a24969..da10cc2d8 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_dhcp_relay/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_dhcp_relay/tasks/main.yml @@ -1,5 +1,6 @@ # Test code for the ACI modules # Copyright: (c) 2021, Tim Cragg(@timcragg) +# Copyright: (c) 2023, Akini Ross(@akinross) # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -26,6 +27,12 @@ tenant: ansible_tenant state: absent +- name: Delete Global DHCP relay policy + cisco.aci.aci_dhcp_relay: + <<: *aci_info + name: ansible_global_dhcp_relay + state: absent + - name: Add a new tenant aci_tenant: <<: *aci_info @@ -91,6 +98,32 @@ - update_dhcp_relay.current.0.dhcpRelayP.attributes.owner == "tenant" - update_dhcp_relay.current.0.dhcpRelayP.attributes.descr == "New Ansible DHCP Relay" +- name: Add another DHCP relay policy for query all + cisco.aci.aci_dhcp_relay: + <<: *aci_info + tenant: ansible_tenant + name: ansible_dhcp_relay_2 + state: present + +# CREATE GLOBAL DHCP RELAY +- name: Add a new Global DHCP relay policy + cisco.aci.aci_dhcp_relay: + <<: *aci_info + name: ansible_global_dhcp_relay + description: Ansible Global DHCP Relay + state: present + register: add_global_dhcp_relay + +- name: Verify Global DHCP Relay creation + assert: + that: + - add_global_dhcp_relay is changed + - add_global_dhcp_relay.current.0.dhcpRelayP.attributes.annotation == 'orchestrator:ansible' + - add_global_dhcp_relay.current.0.dhcpRelayP.attributes.dn == "uni/infra/relayp-ansible_global_dhcp_relay" + - add_global_dhcp_relay.current.0.dhcpRelayP.attributes.name == "ansible_global_dhcp_relay" + - add_global_dhcp_relay.current.0.dhcpRelayP.attributes.owner == "infra" + - add_global_dhcp_relay.current.0.dhcpRelayP.attributes.descr == "Ansible Global DHCP Relay" + # QUERY DHCP RELAY - name: Query DHCP relay policy cisco.aci.aci_dhcp_relay: @@ -120,6 +153,36 @@ assert: that: - query_dhcp_relay_all is not changed + - query_dhcp_relay_all.current.0.fvTenant.children | length >= 2 + +# QUERY GLOBAL DHCP RELAY +- name: Query Global DHCP relay policy + cisco.aci.aci_dhcp_relay: + <<: *aci_info + name: ansible_global_dhcp_relay + state: query + register: query_global_dhcp_relay + +- name: Verify Global DHCP Relay query + assert: + that: + - query_global_dhcp_relay is not changed + - query_global_dhcp_relay.current.0.dhcpRelayP.attributes.dn == "uni/infra/relayp-ansible_global_dhcp_relay" + - query_global_dhcp_relay.current.0.dhcpRelayP.attributes.name == "ansible_global_dhcp_relay" + - query_global_dhcp_relay.current.0.dhcpRelayP.attributes.owner == "infra" + - query_global_dhcp_relay.current.0.dhcpRelayP.attributes.descr == "Ansible Global DHCP Relay" + +- name: Query all DHCP relays + cisco.aci.aci_dhcp_relay: + <<: *aci_info + state: query + register: query_global_dhcp_relay_all + +- name: Verify query idempotence for Global DHCP Relay + assert: + that: + - query_global_dhcp_relay_all is not changed + - query_global_dhcp_relay_all.current | length >= 3 # DELETE DHCP RELAY - name: Delete DHCP relay policy @@ -153,6 +216,24 @@ that: - delete_dhcp_relay_again is not changed +# DELETE GLOBAL DHCP RELAY +- name: Delete Global DHCP relay policy + cisco.aci.aci_dhcp_relay: + <<: *aci_info + name: ansible_global_dhcp_relay + state: absent + register: delete_global_dhcp_relay + +- name: Verify Global DHCP Relay deletion + assert: + that: + - delete_global_dhcp_relay is changed + - delete_global_dhcp_relay.current == [] + - delete_global_dhcp_relay.previous.0.dhcpRelayP.attributes.dn == "uni/infra/relayp-ansible_global_dhcp_relay" + - delete_global_dhcp_relay.previous.0.dhcpRelayP.attributes.name == "ansible_global_dhcp_relay" + - delete_global_dhcp_relay.previous.0.dhcpRelayP.attributes.owner == "infra" + - delete_global_dhcp_relay.previous.0.dhcpRelayP.attributes.descr == "Ansible Global DHCP Relay" + # CLEAN ENVIRONMENT AGAIN - name: Remove the ansible_tenant aci_tenant: diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_dhcp_relay_provider/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_dhcp_relay_provider/tasks/main.yml index 2edc45e51..c133e23ba 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_dhcp_relay_provider/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_dhcp_relay_provider/tasks/main.yml @@ -1,5 +1,6 @@ # Test code for the ACI modules # Copyright: (c) 2021, Tim Cragg(@timcragg) +# Copyright: (c) 2023, Akini Ross (@akinross) # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -29,6 +30,12 @@ tenant: ansible_tenant state: absent +- name: Delete Global DHCP relay policy + cisco.aci.aci_dhcp_relay: + <<: *aci_info + name: ansible_global_dhcp_relay + state: absent + - name: Remove l2ext domain cisco.aci.aci_domain: <<: *aci_info @@ -153,6 +160,15 @@ description: Ansible DHCP Relay state: present + # CREATE GLOBAL DHCP RELAY + - name: Add a new Global DHCP relay policy + cisco.aci.aci_dhcp_relay: + <<: *aci_info + name: ansible_global_dhcp_relay + description: Ansible Global DHCP Relay + state: present + register: add_global_dhcp_relay + # CREATE DHCP RELAY PROVIDERS - name: Add a new DHCP relay App EPG provider cisco.aci.aci_dhcp_relay_provider: @@ -361,7 +377,6 @@ - update_dn_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.53" - update_dn_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" - # QUERY DHCP RELAY PROVIDERS - name: Query DHCP relay App EPG provider cisco.aci.aci_dhcp_relay_provider: @@ -405,6 +420,13 @@ dn: "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" state: query register: query_dn_relay_provider + + - name: Query all DHCP relays in ansible_tenant + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + state: query + register: query_all_relay_provider - name: Confirm DHCP relay provider query assert: @@ -425,6 +447,161 @@ - query_dn_relay_provider.current.0.dhcpRsProv.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay/rsprov-[uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2]" - query_dn_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.53" - query_dn_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" + - query_all_relay_provider is not changed + - query_all_relay_provider.current.0.fvTenant.children.0.dhcpRelayP.children | length >= 4 + + # CREATE GLOBAL DHCP RELAY PROVIDERS + - name: Add a new Global DHCP relay App EPG provider without provider tenant (error) + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + relay_policy: ansible_global_dhcp_relay + epg_type: epg + anp: ansible_ap + app_epg: ansible_epg + dhcp_server_addr: 10.20.30.40 + state: present + ignore_errors: true + register: err_global_epg_relay_provider + + - name: Add a new Global DHCP relay App EPG provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + relay_policy: ansible_global_dhcp_relay + epg_type: epg + provider_tenant: ansible_tenant + anp: ansible_ap + app_epg: ansible_epg + dhcp_server_addr: 10.20.30.40 + state: present + register: add_global_epg_relay_provider + + - name: Add a new Global DHCP relay L2out provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + relay_policy: ansible_global_dhcp_relay + epg_type: l2_external + provider_tenant: ansible_tenant + l2out_name: ansible_l2out + external_net: ansible_l2out_ext_net + dhcp_server_addr: 10.20.30.41 + state: present + register: add_global_l2_relay_provider + + - name: Add a new Global DHCP relay L3out provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + relay_policy: ansible_global_dhcp_relay + epg_type: l3_external + provider_tenant: ansible_tenant + l3out_name: ansible_l3out + external_net: ansible_l3out_ext_net + dhcp_server_addr: 10.20.30.42 + state: present + register: add_global_l3_relay_provider + + - name: Add a new Global DHCP relay dn provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + relay_policy: ansible_global_dhcp_relay + epg_type: dn + dn: "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" + dhcp_server_addr: 10.20.30.43 + state: present + register: add_global_dn_relay_provider + + - name: Confirm Global DHCP relay provider creation + assert: + that: + - err_global_epg_relay_provider is failed + - err_global_epg_relay_provider.msg == "provider_tenant is required when epg_type is epg" + - add_global_epg_relay_provider is changed + - add_global_epg_relay_provider.current.0.dhcpRsProv.attributes.annotation == 'orchestrator:ansible' + - add_global_epg_relay_provider.current.0.dhcpRsProv.attributes.dn == "uni/infra/relayp-ansible_global_dhcp_relay/rsprov-[uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg]" + - add_global_epg_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.40" + - add_global_epg_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg" + - add_global_l2_relay_provider is changed + - add_global_l2_relay_provider.current.0.dhcpRsProv.attributes.dn == "uni/infra/relayp-ansible_global_dhcp_relay/rsprov-[uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net]" + - add_global_l2_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.41" + - add_global_l2_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net" + - add_global_l3_relay_provider is changed + - add_global_l3_relay_provider.current.0.dhcpRsProv.attributes.dn == "uni/infra/relayp-ansible_global_dhcp_relay/rsprov-[uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net]" + - add_global_l3_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.42" + - add_global_l3_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net" + - add_global_dn_relay_provider is changed + - add_global_dn_relay_provider.current.0.dhcpRsProv.attributes.dn == "uni/infra/relayp-ansible_global_dhcp_relay/rsprov-[uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2]" + - add_global_dn_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.43" + - add_global_dn_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" + + # QUERY GLOBAL DHCP RELAY PROVIDERS + - name: Query Global DHCP relay App EPG provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + relay_policy: ansible_global_dhcp_relay + provider_tenant: ansible_tenant + epg_type: epg + anp: ansible_ap + app_epg: ansible_epg + state: query + register: query_global_epg_relay_provider + + - name: Query Global DHCP relay L2out provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + relay_policy: ansible_global_dhcp_relay + provider_tenant: ansible_tenant + epg_type: l2_external + l2out_name: ansible_l2out + external_net: ansible_l2out_ext_net + state: query + register: query_global_l2_relay_provider + + - name: Query Global DHCP relay L3out provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + relay_policy: ansible_global_dhcp_relay + provider_tenant: ansible_tenant + epg_type: l3_external + l3out_name: ansible_l3out + external_net: ansible_l3out_ext_net + state: query + register: query_global_l3_relay_provider + + - name: Query Global DHCP relay dn provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + relay_policy: ansible_global_dhcp_relay + epg_type: dn + dn: "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" + state: query + register: query_global_dn_relay_provider + + - name: Query all Global DHCP relay providers + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + state: query + register: query_global_all_relay_provider + + - name: Confirm DHCP relay provider query + assert: + that: + - query_global_epg_relay_provider is not changed + - query_global_epg_relay_provider.current.0.dhcpRsProv.attributes.dn == "uni/infra/relayp-ansible_global_dhcp_relay/rsprov-[uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg]" + - query_global_epg_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.40" + - query_global_epg_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg" + - query_global_l2_relay_provider is not changed + - query_global_l2_relay_provider.current.0.dhcpRsProv.attributes.dn == "uni/infra/relayp-ansible_global_dhcp_relay/rsprov-[uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net]" + - query_global_l2_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.41" + - query_global_l2_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net" + - query_global_l3_relay_provider is not changed + - query_global_l3_relay_provider.current.0.dhcpRsProv.attributes.dn == "uni/infra/relayp-ansible_global_dhcp_relay/rsprov-[uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net]" + - query_global_l3_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.42" + - query_global_l3_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net" + - query_global_dn_relay_provider is not changed + - query_global_dn_relay_provider.current.0.dhcpRsProv.attributes.dn == "uni/infra/relayp-ansible_global_dhcp_relay/rsprov-[uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2]" + - query_global_dn_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.43" + - query_global_dn_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" + - query_global_all_relay_provider is not changed + - query_global_all_relay_provider.current | length >= 8 # DELETE DHCP RELAY PROVIDERS - name: Delete DHCP relay App EPG provider @@ -471,7 +648,6 @@ state: absent register: delete_dn_relay_provider - - name: Confirm DHCP relay provider removal assert: that: @@ -548,6 +724,72 @@ - delete_l3_relay_provider_again is not changed - delete_dn_relay_provider_again is not changed + # DELETE GLOBAL DHCP RELAY PROVIDERS + - name: Delete Global DHCP relay App EPG provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + relay_policy: ansible_global_dhcp_relay + provider_tenant: ansible_tenant + epg_type: epg + anp: ansible_ap + app_epg: ansible_epg + state: absent + register: delete_global_epg_relay_provider + + - name: Delete Global DHCP relay L2out provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + relay_policy: ansible_global_dhcp_relay + provider_tenant: ansible_tenant + epg_type: l2_external + l2out_name: ansible_l2out + external_net: ansible_l2out_ext_net + state: absent + register: delete_global_l2_relay_provider + + - name: Delete Global DHCP relay L3out provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + relay_policy: ansible_global_dhcp_relay + provider_tenant: ansible_tenant + epg_type: l3_external + l3out_name: ansible_l3out + external_net: ansible_l3out_ext_net + state: absent + register: delete_global_l3_relay_provider + + - name: Delete Global DHCP relay dn provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + relay_policy: ansible_global_dhcp_relay + epg_type: dn + dn: "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" + state: absent + register: delete_global_dn_relay_provider + + - name: Confirm DHCP relay provider removal + assert: + that: + - delete_global_epg_relay_provider is changed + - delete_global_epg_relay_provider.current == [] + - delete_global_epg_relay_provider.previous.0.dhcpRsProv.attributes.dn == "uni/infra/relayp-ansible_global_dhcp_relay/rsprov-[uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg]" + - delete_global_epg_relay_provider.previous.0.dhcpRsProv.attributes.addr == "10.20.30.40" + - delete_global_epg_relay_provider.previous.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg" + - delete_global_l2_relay_provider is changed + - delete_global_l2_relay_provider.current == [] + - delete_global_l2_relay_provider.previous.0.dhcpRsProv.attributes.dn == "uni/infra/relayp-ansible_global_dhcp_relay/rsprov-[uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net]" + - delete_global_l2_relay_provider.previous.0.dhcpRsProv.attributes.addr == "10.20.30.41" + - delete_global_l2_relay_provider.previous.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net" + - delete_global_l3_relay_provider is changed + - delete_global_l3_relay_provider.current == [] + - delete_global_l3_relay_provider.previous.0.dhcpRsProv.attributes.dn == "uni/infra/relayp-ansible_global_dhcp_relay/rsprov-[uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net]" + - delete_global_l3_relay_provider.previous.0.dhcpRsProv.attributes.addr == "10.20.30.42" + - delete_global_l3_relay_provider.previous.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net" + - delete_global_dn_relay_provider is changed + - delete_global_dn_relay_provider.previous.0.dhcpRsProv.attributes.dn == "uni/infra/relayp-ansible_global_dhcp_relay/rsprov-[uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2]" + - delete_global_dn_relay_provider.previous.0.dhcpRsProv.attributes.addr == "10.20.30.43" + - delete_global_dn_relay_provider.previous.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" + # CLEAN ENVIRONMENT AGAIN - name: Remove the ansible_tenant aci_tenant: @@ -555,6 +797,12 @@ tenant: ansible_tenant state: absent + - name: Delete Global DHCP relay policy + cisco.aci.aci_dhcp_relay: + <<: *aci_info + name: ansible_global_dhcp_relay + state: absent + - name: Remove l2ext domain cisco.aci.aci_domain: <<: *aci_info diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_domain/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_domain/tasks/main.yml index 2d3de4dd0..af9c1026b 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_domain/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_domain/tasks/main.yml @@ -26,7 +26,6 @@ <<: *aci_info profile_name: ansible_dns_profile state: absent - delegate_to: localhost # ADD DNS PROFILE - name: Add DNS profile @@ -34,7 +33,6 @@ <<: *aci_info profile_name: ansible_dns_profile state: present - delegate_to: localhost # ADD DNS DOMAIN - name: Add a new DNS domain @@ -44,7 +42,6 @@ domain: example.com default: false state: present - delegate_to: localhost register: add_dns_domain - name: Verify DNS domain creation @@ -64,7 +61,6 @@ domain: example.com default: false state: present - delegate_to: localhost register: add_dns_domain_again - name: Verify DNS domain creation idempotence @@ -83,7 +79,6 @@ domain: example.com default: true state: present - delegate_to: localhost register: update_dns_domain - name: Verify DNS domain update @@ -101,7 +96,6 @@ dns_profile: ansible_dns_profile domain: example.com state: query - delegate_to: localhost register: query_dns_domain - name: Verify DNS domain attributes @@ -118,7 +112,6 @@ <<: *aci_info dns_profile: ansible_dns_profile state: query - delegate_to: localhost register: query_dns_domain_all - name: Verify DNS domain query idempotence @@ -133,7 +126,6 @@ dns_profile: ansible_dns_profile domain: example.com state: absent - delegate_to: localhost register: delete_dns_domain - name: Verify DNS domain deletion @@ -152,7 +144,6 @@ dns_profile: ansible_dns_profile domain: example.com state: absent - delegate_to: localhost register: delete_dns_domain_again - name: Verify DNS domain deletion idempotence @@ -166,4 +157,3 @@ <<: *aci_info profile_name: ansible_dns_profile state: absent - delegate_to: localhost diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_provider/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_provider/tasks/main.yml index 8deca651c..3e31d2b52 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_provider/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_provider/tasks/main.yml @@ -26,7 +26,6 @@ <<: *aci_info profile_name: ansible_dns_profile state: absent - delegate_to: localhost # ADD DNS PROFILE - name: Add DNS profile @@ -34,7 +33,6 @@ <<: *aci_info profile_name: ansible_dns_profile state: present - delegate_to: localhost # ADD DNS PROVIDER - name: Add a new DNS provider @@ -44,7 +42,6 @@ addr: 10.20.30.40 preferred: false state: present - delegate_to: localhost register: add_dns_provider - name: Verify DNS provider creation @@ -64,7 +61,6 @@ addr: 10.20.30.40 preferred: false state: present - delegate_to: localhost register: add_dns_provider_again - name: Verify DNS provider creation idempotence @@ -83,7 +79,6 @@ addr: 10.20.30.40 preferred: true state: present - delegate_to: localhost register: update_dns_provider - name: Verify DNS provider update @@ -101,7 +96,6 @@ dns_profile: ansible_dns_profile addr: 10.20.30.40 state: query - delegate_to: localhost register: query_dns_provider - name: Verify DNS provider attributes @@ -118,7 +112,6 @@ <<: *aci_info dns_profile: ansible_dns_profile state: query - delegate_to: localhost register: query_dns_provider_all - name: Verify DNS provider query idempotence @@ -133,7 +126,6 @@ dns_profile: ansible_dns_profile addr: 10.20.30.40 state: absent - delegate_to: localhost register: delete_dns_provider - name: Verify DNS provider deletion @@ -152,7 +144,6 @@ dns_profile: ansible_dns_profile addr: 10.20.30.40 state: absent - delegate_to: localhost register: delete_dns_provider_again - name: Verify DNS provider deletion idempotence @@ -166,4 +157,3 @@ <<: *aci_info profile_name: ansible_dns_profile state: absent - delegate_to: localhost diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_domain_to_vlan_pool/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain_to_vlan_pool/tasks/main.yml index 8c31fd4cc..ab10856a8 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_domain_to_vlan_pool/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain_to_vlan_pool/tasks/main.yml @@ -3,6 +3,22 @@ # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + ansible.builtin.set_fact: + aci_info: &aci_info + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + - name: Verify Cloud and Non-Cloud Sites in use. include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml @@ -12,41 +28,36 @@ # CLEAN ENVIRONMENT - name: Remove domain to VLAN pool binding cisco.aci.aci_domain_to_vlan_pool: &binding_absent - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' + <<: *aci_info domain: phys_dom domain_type: phys pool: test_pool pool_allocation_mode: dynamic state: absent - - name: Remove physical domain + - name: Remove domains cisco.aci.aci_domain: - host: "{{ aci_hostname }}" - username: "{{ aci_username }}" - password: "{{ aci_password }}" - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' - domain: phys_dom - domain_type: phys + <<: *aci_info + domain: "{{ item.domain }}" + domain_type: "{{ item.domain_type }}" + state: absent + loop: + - {domain: phys_dom, domain_type: phys} + - {domain: fc_dom, domain_type: fc} + - {domain: l2dom_dom, domain_type: l2dom} + - {domain: l3dom_dom, domain_type: l3dom} + + - name: Remove VMM domain + cisco.aci.aci_domain: + <<: *aci_info + domain: anstest + domain_type: vmm + vm_provider: vmware state: absent - name: Create VLAN pool cisco.aci.aci_vlan_pool: - host: "{{ aci_hostname }}" - username: "{{ aci_username }}" - password: "{{ aci_password }}" - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' + <<: *aci_info pool: test_pool pool_allocation_mode: dynamic description: Test VLAN pool @@ -56,13 +67,7 @@ # ADD BINDING - name: Add domain to VLAN pool binding (check_mode) cisco.aci.aci_domain_to_vlan_pool: &binding_present - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' + <<: *aci_info domain: phys_dom domain_type: phys pool: test_pool @@ -105,17 +110,67 @@ - cm_add_binding_again is not changed - nm_add_binding_again is not changed + - name: Add domain to VLAN pool binding with domain type not vmm and with vm provider (error) + cisco.aci.aci_domain_to_vlan_pool: + <<: *binding_present + domain: phys_dom + domain_type: phys + vm_provider: vmware + ignore_errors: true + register: err_not_vmm_with_vm_provider + + - name: Add domain to VLAN pool binding with domain type fc + cisco.aci.aci_domain_to_vlan_pool: + <<: *binding_present + domain: fc_dom + domain_type: fc + pool_allocation_mode: static + register: nm_fc_type + + - name: Add domain to VLAN pool binding with domain type l2dom + cisco.aci.aci_domain_to_vlan_pool: + <<: *binding_present + domain: l2dom_dom + domain_type: l2dom + register: nm_l2dom_type + + - name: Add domain to VLAN pool binding with domain type l3dom + cisco.aci.aci_domain_to_vlan_pool: + <<: *binding_present + domain: l3dom_dom + domain_type: l3dom + register: nm_l3dom_type + + - name: Add domain to VLAN pool binding with domain type vmm + cisco.aci.aci_domain_to_vlan_pool: + <<: *binding_present + domain: anstest + domain_type: vmm + vm_provider: vmware + register: nm_vmm_type + + - name: Verify bindings with domain types + assert: + that: + - err_not_vmm_with_vm_provider is not changed + - err_not_vmm_with_vm_provider.msg == "Domain type 'phys' cannot have a 'vm_provider'" + - nm_fc_type is changed + - nm_fc_type.current.0.fcDomP.attributes.dn == "uni/fc-fc_dom" + - nm_fc_type.current.0.fcDomP.children.0.infraRsVlanNs.attributes.tDn == "uni/infra/vlanns-[test_pool]-static" + - nm_l2dom_type is changed + - nm_l2dom_type.current.0.l2extDomP.attributes.dn == "uni/l2dom-l2dom_dom" + - nm_l2dom_type.current.0.l2extDomP.children.0.infraRsVlanNs.attributes.tDn == "uni/infra/vlanns-[test_pool]-dynamic" + - nm_l3dom_type is changed + - nm_l3dom_type.current.0.l3extDomP.attributes.dn == "uni/l3dom-l3dom_dom" + - nm_l3dom_type.current.0.l3extDomP.children.0.infraRsVlanNs.attributes.tDn == "uni/infra/vlanns-[test_pool]-dynamic" + - nm_vmm_type is changed + - nm_vmm_type.current.0.vmmDomP.attributes.dn == "uni/vmmp-VMware/dom-anstest" + - nm_vmm_type.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == "uni/infra/vlanns-[test_pool]-dynamic" # QUERY ALL BINDINGS - name: Query all domain to VLAN pool bindings (check_mode) cisco.aci.aci_domain_to_vlan_pool: &binding_query - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' + <<: *aci_info domain_type: phys pool_allocation_mode: dynamic state: query diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/vsan.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/vsan.yml index 7bdc332c5..06df26232 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/vsan.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/vsan.yml @@ -1,20 +1,97 @@ -- name: ensure vsan pool exists for tests to kick off +- name: Set vars + ansible.builtin.set_fact: + aci_info: &aci_info + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +- name: create vsan pool anstest cisco.aci.aci_encap_pool: &aci_pool_present - host: "{{ aci_hostname }}" - username: "{{ aci_username }}" - password: "{{ aci_password }}" - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' + <<: *aci_info + pool: anstest + pool_type: vsan + pool_allocation_mode: static + description: Ansible Test + +- name: add range to vsan pool anstest (check mode) + cisco.aci.aci_encap_pool_range: &aci_vsan_range + <<: *aci_info pool: anstest pool_type: vsan - allocation_mode: static + pool_allocation_mode: static + range_start: 20 + range_end: 40 description: Ansible Test - state: present + check_mode: true + register: cm_vsan_present + +- name: add range to vsan pool anstest (error) + cisco.aci.aci_encap_pool_range: + <<: *aci_vsan_range + range_start: 4092 + range_end: 4099 + register: err_vsan_range + ignore_errors: true + +- name: add range to vsan pool anstest + cisco.aci.aci_encap_pool_range: + <<: *aci_vsan_range + register: nm_vsan_present + +- name: add range to vsan pool anstest again + cisco.aci.aci_encap_pool_range: + <<: *aci_vsan_range + register: nm_vsan_present_again + +- name: delete range from vsan pool anstest + cisco.aci.aci_encap_pool_range: + <<: *aci_vsan_range + state: absent + register: rm_vsan_present + +- name: present assertions + ansible.builtin.assert: + that: + - cm_vsan_present is changed + - cm_vsan_present.current == [] + - cm_vsan_present.proposed.fvnsVsanEncapBlk.attributes.annotation == "orchestrator:ansible" + - cm_vsan_present.proposed.fvnsVsanEncapBlk.attributes.descr == "Ansible Test" + - cm_vsan_present.proposed.fvnsVsanEncapBlk.attributes.dn == "uni/infra/vsanns-[anstest]-static/vsanfrom-[vsan-20]-to-[vsan-40]" + - cm_vsan_present.proposed.fvnsVsanEncapBlk.attributes.from == "vsan-20" + - cm_vsan_present.proposed.fvnsVsanEncapBlk.attributes.to == "vsan-40" + - err_vsan_range is not changed + - err_vsan_range.msg == 'vsan pools must have "range_start" and "range_end" values between 1 and 4093' + - nm_vsan_present is changed + - nm_vsan_present.previous == [] + - nm_vsan_present.current.0.fvnsVsanEncapBlk.attributes.annotation == "orchestrator:ansible" + - nm_vsan_present.current.0.fvnsVsanEncapBlk.attributes.descr == "Ansible Test" + - nm_vsan_present.current.0.fvnsVsanEncapBlk.attributes.dn == "uni/infra/vsanns-[anstest]-static/vsanfrom-[vsan-20]-to-[vsan-40]" + - nm_vsan_present.current.0.fvnsVsanEncapBlk.attributes.from == "vsan-20" + - nm_vsan_present.current.0.fvnsVsanEncapBlk.attributes.to == "vsan-40" + - nm_vsan_present_again is not changed + - nm_vsan_present_again.previous.0.fvnsVsanEncapBlk.attributes.annotation == "orchestrator:ansible" + - nm_vsan_present_again.previous.0.fvnsVsanEncapBlk.attributes.descr == "Ansible Test" + - nm_vsan_present_again.previous.0.fvnsVsanEncapBlk.attributes.dn == "uni/infra/vsanns-[anstest]-static/vsanfrom-[vsan-20]-to-[vsan-40]" + - nm_vsan_present_again.previous.0.fvnsVsanEncapBlk.attributes.from == "vsan-20" + - nm_vsan_present_again.previous.0.fvnsVsanEncapBlk.attributes.to == "vsan-40" + - nm_vsan_present_again.current.0.fvnsVsanEncapBlk.attributes.annotation == "orchestrator:ansible" + - nm_vsan_present_again.current.0.fvnsVsanEncapBlk.attributes.descr == "Ansible Test" + - nm_vsan_present_again.current.0.fvnsVsanEncapBlk.attributes.dn == "uni/infra/vsanns-[anstest]-static/vsanfrom-[vsan-20]-to-[vsan-40]" + - nm_vsan_present_again.current.0.fvnsVsanEncapBlk.attributes.from == "vsan-20" + - nm_vsan_present_again.current.0.fvnsVsanEncapBlk.attributes.to == "vsan-40" + - rm_vsan_present is changed + - rm_vsan_present.previous.0.fvnsVsanEncapBlk.attributes.annotation == "orchestrator:ansible" + - rm_vsan_present.previous.0.fvnsVsanEncapBlk.attributes.descr == "Ansible Test" + - rm_vsan_present.previous.0.fvnsVsanEncapBlk.attributes.dn == "uni/infra/vsanns-[anstest]-static/vsanfrom-[vsan-20]-to-[vsan-40]" + - rm_vsan_present.previous.0.fvnsVsanEncapBlk.attributes.from == "vsan-20" + - rm_vsan_present.previous.0.fvnsVsanEncapBlk.attributes.to == "vsan-40" + - rm_vsan_present.current == [] -- name: cleanup vsan pool +- name: delete vsan pool anstest cisco.aci.aci_encap_pool: <<: *aci_pool_present state: absent - when: pool_present is changed diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/vxlan.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/vxlan.yml index e5e301916..43a4ff788 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/vxlan.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/vxlan.yml @@ -1,19 +1,104 @@ -- name: ensure vxlan pool exists for tests to kick off +- name: Set vars + ansible.builtin.set_fact: + aci_info: &aci_info + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +- name: create vxlan pool anstest cisco.aci.aci_encap_pool: &aci_pool_present - host: "{{ aci_hostname }}" - username: "{{ aci_username }}" - password: "{{ aci_password }}" - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' + <<: *aci_info + pool: anstest + pool_type: vxlan + description: Ansible Test + +- name: add range to vxlan pool anstest (check mode) + cisco.aci.aci_encap_pool_range: &aci_vxlan_range + <<: *aci_info pool: anstest pool_type: vxlan + range_start: 5000 + range_end: 5010 description: Ansible Test - state: present + check_mode: true + register: cm_vxlan_present + +- name: add range to vxlan pool anstest with pool_allocation_mode (error) + cisco.aci.aci_encap_pool_range: + <<: *aci_vxlan_range + allocation_mode: static + register: err_vxlan_pool_alloc + ignore_errors: true + +- name: add range to vxlan pool anstest (error) + cisco.aci.aci_encap_pool_range: + <<: *aci_vxlan_range + range_start: 4092 + range_end: 4099 + register: err_vxlan_range + ignore_errors: true + +- name: add range to vxlan pool anstest + cisco.aci.aci_encap_pool_range: + <<: *aci_vxlan_range + register: nm_vxlan_present + +- name: add range to vxlan pool anstest again + cisco.aci.aci_encap_pool_range: + <<: *aci_vxlan_range + register: nm_vxlan_present_again + +- name: delete range from vxlan pool anstest + cisco.aci.aci_encap_pool_range: + <<: *aci_vxlan_range + state: absent + register: rm_vxlan_present + +- name: present assertions + ansible.builtin.assert: + that: + - cm_vxlan_present is changed + - cm_vxlan_present.current == [] + - cm_vxlan_present.proposed.fvnsEncapBlk.attributes.annotation == "orchestrator:ansible" + - cm_vxlan_present.proposed.fvnsEncapBlk.attributes.descr == "Ansible Test" + - cm_vxlan_present.proposed.fvnsEncapBlk.attributes.dn == "uni/infra/vxlanns-anstest/from-[vxlan-5000]-to-[vxlan-5010]" + - cm_vxlan_present.proposed.fvnsEncapBlk.attributes.from == "vxlan-5000" + - cm_vxlan_present.proposed.fvnsEncapBlk.attributes.to == "vxlan-5010" + - err_vxlan_pool_alloc is not changed + - err_vxlan_pool_alloc.msg == 'vxlan pools do not support setting the "allocation_mode"; please omit this parameter for vxlan pools' + - err_vxlan_range is not changed + - err_vxlan_range.msg == 'vxlan pools must have "range_start" and "range_end" values between 5000 and 16777215' + - nm_vxlan_present is changed + - nm_vxlan_present.previous == [] + - nm_vxlan_present.current.0.fvnsEncapBlk.attributes.annotation == "orchestrator:ansible" + - nm_vxlan_present.current.0.fvnsEncapBlk.attributes.descr == "Ansible Test" + - nm_vxlan_present.current.0.fvnsEncapBlk.attributes.dn == "uni/infra/vxlanns-anstest/from-[vxlan-5000]-to-[vxlan-5010]" + - nm_vxlan_present.current.0.fvnsEncapBlk.attributes.from == "vxlan-5000" + - nm_vxlan_present.current.0.fvnsEncapBlk.attributes.to == "vxlan-5010" + - nm_vxlan_present_again is not changed + - nm_vxlan_present_again.previous.0.fvnsEncapBlk.attributes.annotation == "orchestrator:ansible" + - nm_vxlan_present_again.previous.0.fvnsEncapBlk.attributes.descr == "Ansible Test" + - nm_vxlan_present_again.previous.0.fvnsEncapBlk.attributes.dn == "uni/infra/vxlanns-anstest/from-[vxlan-5000]-to-[vxlan-5010]" + - nm_vxlan_present_again.previous.0.fvnsEncapBlk.attributes.from == "vxlan-5000" + - nm_vxlan_present_again.previous.0.fvnsEncapBlk.attributes.to == "vxlan-5010" + - nm_vxlan_present_again.current.0.fvnsEncapBlk.attributes.annotation == "orchestrator:ansible" + - nm_vxlan_present_again.current.0.fvnsEncapBlk.attributes.descr == "Ansible Test" + - nm_vxlan_present_again.current.0.fvnsEncapBlk.attributes.dn == "uni/infra/vxlanns-anstest/from-[vxlan-5000]-to-[vxlan-5010]" + - nm_vxlan_present_again.current.0.fvnsEncapBlk.attributes.from == "vxlan-5000" + - nm_vxlan_present_again.current.0.fvnsEncapBlk.attributes.to == "vxlan-5010" + - rm_vxlan_present is changed + - rm_vxlan_present.previous.0.fvnsEncapBlk.attributes.annotation == "orchestrator:ansible" + - rm_vxlan_present.previous.0.fvnsEncapBlk.attributes.descr == "Ansible Test" + - rm_vxlan_present.previous.0.fvnsEncapBlk.attributes.dn == "uni/infra/vxlanns-anstest/from-[vxlan-5000]-to-[vxlan-5010]" + - rm_vxlan_present.previous.0.fvnsEncapBlk.attributes.from == "vxlan-5000" + - rm_vxlan_present.previous.0.fvnsEncapBlk.attributes.to == "vxlan-5010" + - rm_vxlan_present.current == [] -- name: cleanup vxlan pool +- name: delete vxlan pool anstest cisco.aci.aci_encap_pool: <<: *aci_pool_present state: absent - when: pool_present is changed diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_monitoring_policy/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_monitoring_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_monitoring_policy/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_monitoring_policy/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_monitoring_policy/tasks/main.yml new file mode 100644 index 000000000..1671e252e --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_monitoring_policy/tasks/main.yml @@ -0,0 +1,161 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Akini Ross (akinross@cisco.com) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + ansible.builtin.fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + ansible.builtin.set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + aci_tenant: ansible_test + +- name: Verify Cloud and Non-Cloud Sites in use. + ansible.builtin.include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: + - query_cloud.current == [] + block: + + # CLEAN TEST ENVIRONMENT + + - name: Ensure clean tenant configuration + cisco.aci.aci_tenant: + <<: *aci_info + tenant: "{{ aci_tenant }}" + state: "{{ item }}" + loop: + - absent + - present + + # TEST CREATE EPG MONITORING POLICY + + - name: Add epg monitoring policy 1 ( check mode ) + cisco.aci.aci_epg_monitoring_policy: &add_epg_monitoring_policy_1 + <<: *aci_info + tenant: "{{ aci_tenant }}" + monitoring_policy: monitoring_policy_1 + state: present + check_mode: true + register: cm_add_epg_monitoring_policy_1 + + - name: Add epg monitoring policy 1 + cisco.aci.aci_epg_monitoring_policy: + <<: *add_epg_monitoring_policy_1 + register: nm_add_epg_monitoring_policy_1 + + - name: Add epg monitoring policy 1 again + cisco.aci.aci_epg_monitoring_policy: + <<: *add_epg_monitoring_policy_1 + register: nm_add_epg_monitoring_policy_1_again + + - name: Verify add epg monitoring policy 1 + ansible.builtin.assert: + that: + - cm_add_epg_monitoring_policy_1 is changed + - cm_add_epg_monitoring_policy_1.current == [] + - cm_add_epg_monitoring_policy_1.previous == [] + - cm_add_epg_monitoring_policy_1.proposed.monEPGPol.attributes.name == "monitoring_policy_1" + - nm_add_epg_monitoring_policy_1 is changed + - nm_add_epg_monitoring_policy_1.previous == [] + - nm_add_epg_monitoring_policy_1.current.0.monEPGPol.attributes.name == "monitoring_policy_1" + - nm_add_epg_monitoring_policy_1.current.0.monEPGPol.attributes.descr == "" + - nm_add_epg_monitoring_policy_1_again is not changed + - nm_add_epg_monitoring_policy_1_again.previous.0.monEPGPol.attributes.name == "monitoring_policy_1" + - nm_add_epg_monitoring_policy_1_again.previous.0.monEPGPol.attributes.descr == "" + - nm_add_epg_monitoring_policy_1_again.current.0.monEPGPol.attributes.name == "monitoring_policy_1" + - nm_add_epg_monitoring_policy_1_again.current.0.monEPGPol.attributes.descr == "" + + - name: Change epg monitoring policy 1 + cisco.aci.aci_epg_monitoring_policy: + <<: *add_epg_monitoring_policy_1 + description: "changed description" + register: nm_change_epg_monitoring_policy_1 + + - name: Verify change epg monitoring policy 1 + ansible.builtin.assert: + that: + - nm_change_epg_monitoring_policy_1 is changed + - nm_change_epg_monitoring_policy_1.previous.0.monEPGPol.attributes.name == "monitoring_policy_1" + - nm_change_epg_monitoring_policy_1.previous.0.monEPGPol.attributes.descr == "" + - nm_change_epg_monitoring_policy_1.current.0.monEPGPol.attributes.name == "monitoring_policy_1" + - nm_change_epg_monitoring_policy_1.current.0.monEPGPol.attributes.descr == "changed description" + + - name: Add two more epg monitoring policies + cisco.aci.aci_epg_monitoring_policy: + <<: *aci_info + tenant: "{{ aci_tenant }}" + monitoring_policy: "{{ item }}" + state: present + loop: + - monitoring_policy_2 + - monitoring_policy_3 + + # TEST QUERY EPG MONITORING POLICY + + - name: Query epg monitoring policy 1 + cisco.aci.aci_epg_monitoring_policy: + <<: *add_epg_monitoring_policy_1 + state: query + register: query_one + + - name: Query all epg monitoring policies ( class query ) + cisco.aci.aci_epg_monitoring_policy: + <<: *aci_info + state: query + register: query_all + + - name: Verify query epg monitoring policies + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current | length == 1 + - query_one.current.0.monEPGPol.attributes.name == "monitoring_policy_1" + - query_all is not changed + - query_all.current | length >= 4 + - query_all.current.0.monEPGPol.attributes.name == "default" + - query_all.current.1.monEPGPol.attributes.name == "monitoring_policy_1" + - query_all.current.2.monEPGPol.attributes.name == "monitoring_policy_2" + - query_all.current.3.monEPGPol.attributes.name == "monitoring_policy_3" + + # TEST REMOVAL EPG MONITORING POLICY + + - name: Remove aepg monitoring policy 1 ( check mode ) + cisco.aci.aci_epg_monitoring_policy: &remove_epg_monitoring_policy_1 + <<: *add_epg_monitoring_policy_1 + state: absent + check_mode: true + register: cm_remove_epg_monitoring_policy_1 + + - name: Remove epg monitoring policy 1 + cisco.aci.aci_epg_monitoring_policy: + <<: *remove_epg_monitoring_policy_1 + register: nm_remove_epg_monitoring_policy_1 + + - name: Remove epg monitoring policy 1 again + cisco.aci.aci_epg_monitoring_policy: + <<: *remove_epg_monitoring_policy_1 + register: nm_remove_epg_monitoring_policy_1_again + + - name: Verify removal epg monitoring policies + ansible.builtin.assert: + that: + - cm_remove_epg_monitoring_policy_1 is changed + - cm_remove_epg_monitoring_policy_1.proposed == {} + - nm_remove_epg_monitoring_policy_1 is changed + - nm_remove_epg_monitoring_policy_1.previous.0.monEPGPol.attributes.name == "monitoring_policy_1" + - nm_remove_epg_monitoring_policy_1.current == [] + - nm_remove_epg_monitoring_policy_1_again is not changed + - nm_remove_epg_monitoring_policy_1_again.previous == [] + - nm_remove_epg_monitoring_policy_1_again.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_subnet/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_subnet/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_subnet/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_subnet/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_subnet/tasks/main.yml new file mode 100644 index 000000000..07fb1d304 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_subnet/tasks/main.yml @@ -0,0 +1,258 @@ +# Test code for the ACI modules + +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Query system information + aci_system: + <<: *aci_info + id: 1 + state: query + register: version + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: ensure tenant does not exists + cisco.aci.aci_tenant: &aci_tenant_absent + <<: *aci_info + state: absent + tenant: ansible_test + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: ensure tenant exists for tests to kick off + cisco.aci.aci_tenant: &aci_tenant_present + <<: *aci_tenant_absent + state: present + tenant: ansible_test + register: tenant_present + + - name: ensure ap exists for tests to kick off + cisco.aci.aci_ap: &aci_ap_present + <<: *aci_tenant_present + ap: anstest + register: ap_present + + - name: ensure epg exists for tests to kick off + cisco.aci.aci_epg: &aci_epg_present + <<: *aci_ap_present + epg: anstest + register: epg_present + + - name: create subnet - check mode works + cisco.aci.aci_epg_subnet: &aci_subnet_present + <<: *aci_epg_present + state: present + subnet_name: anstest + gateway: 10.100.100.1 + mask: 24 + descr: Ansible Test + check_mode: true + register: create_check_mode + + - name: create subnet - creation works + cisco.aci.aci_epg_subnet: + <<: *aci_subnet_present + register: create_subnet + + - name: create new subnet with IpDP_learning disabled - APIC version >= 5.0 + cisco.aci.aci_epg_subnet: + <<: *aci_epg_present + state: present + descr: Ansible Test + gateway: 10.100.101.1 + mask: 32 + scope: [private, shared] + route_profile: default + route_profile_l3out: default + subnet_control: no_default_gateway + ip_data_plane_learning: disabled + register: create_subnet2_5 + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + - name: create new subnet - creation works for APIC version < 5.0 + cisco.aci.aci_epg_subnet: &aci_subnet2_present + <<: *aci_epg_present + state: present + descr: Ansible Test + gateway: 10.100.101.1 + mask: 32 + scope: [private, shared] + route_profile: default + route_profile_l3out: default + subnet_control: no_default_gateway + register: create_subnet2 + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: create subnet again with IpDP_learning disabled - idempotency works for APIC version >= 5 + cisco.aci.aci_epg_subnet: + <<: *aci_subnet2_present + ip_data_plane_learning: disabled + register: create_idempotency_5 + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + - name: create subnet again - idempotency works for APIC version < 5 + cisco.aci.aci_epg_subnet: + <<: *aci_subnet2_present + register: create_idempotency + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: create subnet with bad scope - failure message works + cisco.aci.aci_epg_subnet: + <<: *aci_subnet_present + scope: [private, public] + register: create_bad_scope + ignore_errors: true + + - name: create subnet without all necessary params - failure message works + cisco.aci.aci_epg_subnet: + <<: *aci_subnet_present + epg: "{{ fake_var | default(omit) }}" + register: create_incomplete_data + ignore_errors: true + + - name: create subnet without valid mask - failure message works + cisco.aci.aci_epg_subnet: + <<: *aci_subnet_present + mask: 130 + register: create_wrong_mask + ignore_errors: true + + - name: asserts for subnet creation tasks + assert: + that: + - create_check_mode is changed + - create_check_mode.sent.fvSubnet.attributes.descr == create_subnet.sent.fvSubnet.attributes.descr == 'Ansible Test' + - create_check_mode.sent.fvSubnet.attributes.ip == create_subnet.sent.fvSubnet.attributes.ip == '10.100.100.1/24' + - create_check_mode.sent.fvSubnet.attributes.name == create_subnet.sent.fvSubnet.attributes.name == 'anstest' + - create_subnet is changed + - create_subnet.current.0.fvSubnet.attributes.annotation == 'orchestrator:ansible' + - create_subnet.previous == [] + - create_bad_scope is failed + - create_bad_scope.msg.startswith("Parameter 'scope' cannot be both 'private' and 'public'") + - create_incomplete_data is failed + - 'create_incomplete_data.msg == "state is present but all of the following are missing: epg"' + - create_wrong_mask is failed + - create_wrong_mask.msg == "Valid Subnet Masks are 0 to 32 for IPv4 Addresses and 0 to 128 for IPv6 addresses" + + - name: assert for subnet IpDPlearning tasks version >=5 + assert: + that: + - create_subnet2_5 is changed + - create_subnet2_5.current.0.fvSubnet.attributes.ctrl == 'no-default-gateway' + - create_subnet2_5.sent == create_subnet2_5.proposed + - create_subnet2_5.sent.fvSubnet.attributes.scope == "private,shared" + - create_subnet2_5.sent.fvSubnet.children.0.fvRsBDSubnetToProfile.attributes.tnL3extOutName == 'default' + - create_subnet2_5.sent.fvSubnet.children.0.fvRsBDSubnetToProfile.attributes.tnRtctrlProfileName == 'default' + - create_idempotency_5 is not changed + - create_idempotency_5.previous != [] + - create_subnet.current.0.fvSubnet.attributes.ipDPLearning == 'enabled' + - create_subnet2_5.current.0.fvSubnet.attributes.ipDPLearning == 'disabled' + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + - name: assert for subnet IpDPlearning tasks version < 5 + assert: + that: + - create_subnet2 is changed + - create_subnet2.current.0.fvSubnet.attributes.ctrl == 'no-default-gateway' + - create_subnet2.sent == create_subnet2.proposed + - create_subnet2.sent.fvSubnet.attributes.scope == "private,shared" + - create_subnet2.sent.fvSubnet.children.0.fvRsBDSubnetToProfile.attributes.tnL3extOutName == 'default' + - create_subnet2.sent.fvSubnet.children.0.fvRsBDSubnetToProfile.attributes.tnRtctrlProfileName == 'default' + - create_idempotency is not changed + - create_idempotency.previous != [] + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: get all in epg + cisco.aci.aci_epg_subnet: + <<: *aci_epg_present + state: query + register: get_all_epg + + - name: get specific subnet + cisco.aci.aci_epg_subnet: + <<: *aci_subnet_present + state: query + register: get_subnet + + - name: get all subnets matching gateway + cisco.aci.aci_epg_subnet: + <<: *aci_subnet_present + state: query + tenant: "{{ fake_var | default(omit) }}" + ap: "{{ fake_var | default(omit) }}" + epg: "{{ fake_var | default(omit) }}" + register: get_subnets_gateway + + - name: asserts for query tasks + assert: + that: + - get_all_epg is not changed + - '"rsp-subtree-class=fvRsBDSubnetToProfile,fvRsNdPfxPol,fvSubnet" in get_all_epg.filter_string' + - '"tn-ansible_test/ap-anstest/epg-anstest.json" in get_all_epg.url' + - get_subnet is not changed + - get_subnet.current | length == 1 + - '"tn-ansible_test/ap-anstest/epg-anstest/subnet-[10.100.100.1/24].json" in get_subnet.url' + - get_subnets_gateway is not changed + - '"query-target-filter=eq(fvSubnet.ip,\"10.100.100.1/24\")" in get_subnets_gateway.filter_string' + - '"class/fvSubnet.json" in get_subnets_gateway.url' + + - name: delete subnet - check mode works + cisco.aci.aci_epg_subnet: + <<: *aci_subnet_present + state: absent + check_mode: true + register: delete_check_mode + + - name: delete subnet - delete works + cisco.aci.aci_epg_subnet: + <<: *aci_subnet_present + state: absent + register: delete_subnet + + - name: delete subnet - cleanup + cisco.aci.aci_epg_subnet: + <<: *aci_subnet2_present + state: absent + + - name: delete subnet again - idempotency works + cisco.aci.aci_epg_subnet: + <<: *aci_subnet2_present + state: absent + register: delete_idempotency + + - name: asserts for deletion task + assert: + that: + - delete_check_mode is changed + - delete_check_mode.proposed == {} + - delete_subnet is changed + - delete_subnet.previous != [] + - delete_subnet.method == "DELETE" + - delete_idempotency is not changed + - delete_idempotency.previous == [] + + - name: delete tenant - cleanup before ending tests + cisco.aci.aci_tenant: + <<: *aci_tenant_present + state: absent + when: tenant_present is changed diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_interface_policy_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_interface_policy_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_interface_policy_group/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_interface_policy_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_interface_policy_group/tasks/main.yml new file mode 100644 index 000000000..9f871da6b --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_interface_policy_group/tasks/main.yml @@ -0,0 +1,346 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Sabari Jaganathan (@sajagana) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: "Please define the following variables: aci_hostname, aci_username and aci_password." + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +# SET VARS +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: "{{ aci_validate_certs | default(false) }}" + use_ssl: "{{ aci_use_ssl | default(true) }}" + use_proxy: "{{ aci_use_proxy | default(true) }}" + output_level: '{{ aci_output_level | default("info") }}' + +- name: Query system information + cisco.aci.aci_system: + <<: *aci_info + id: 1 + state: query + register: version + +- name: Ensure leaf_policy_group does not exist + aci_fabric_interface_policy_group: + <<: *aci_info + name: leaf_policy_group + type: leaf + state: absent + +- name: Ensure spine_policy_group does not exist + aci_fabric_interface_policy_group: + <<: *aci_info + name: spine_policy_group + type: spine + state: absent + +- name: Add a leaf fabric interface policy group with check mode + aci_fabric_interface_policy_group: &cm_leaf_policy_group_present + <<: *aci_info + name: leaf_policy_group + type: leaf + descr: leaf_policy_group created + state: present + check_mode: true + register: cm_leaf_policy_group_present + +- name: Add a leaf fabric interface policy group with normal mode + aci_fabric_interface_policy_group: &nm_leaf_policy_group_present + <<: *cm_leaf_policy_group_present + dwdm_policy: default + link_level_policy: default + link_flap_policy: default + l3_interface_policy: default + macsec_policy: default + monitoring_policy: default + register: nm_leaf_policy_group_present + +- name: Add a leaf fabric interface policy group with normal mode again + aci_fabric_interface_policy_group: + <<: *nm_leaf_policy_group_present + register: nm_leaf_policy_group_present_again + +- name: Add a spine fabric interface policy group with check mode + aci_fabric_interface_policy_group: &cm_spine_policy_group_present + <<: *aci_info + name: spine_policy_group + type: spine + descr: spine_policy_group created + dwdm_policy: default + link_level_policy: default + link_flap_policy: default + l3_interface_policy: default + macsec_policy: default + monitoring_policy: default + state: present + check_mode: true + register: cm_spine_policy_group_present + +- name: Execute tasks only for ACI v6.0(2h)+ + when: version.current.0.topSystem.attributes.version is version('6.0(2h)', '>=') + block: + - name: Add a spine fabric interface policy group with transceiver_policy_tdn + aci_fabric_interface_policy_group: &tp_spine_policy_group_present + <<: *aci_info + name: spine_policy_group + type: spine + descr: spine_policy_group created + transceiver_policy_tdn: "uni/fabric/zrfab-default" + state: present + register: tp_spine_policy_group_present + + - name: Remove the transceiver_policy from the spine fabric interface policy group + aci_fabric_interface_policy_group: + <<: *aci_info + name: spine_policy_group + type: spine + descr: spine_policy_group created + transceiver_policy_tdn: "" + state: present + register: tp_spine_policy_group_absent + + - name: Assertions check for add fabric interface policy groups + assert: + that: + - tp_spine_policy_group_present is changed + - tp_spine_policy_group_absent is changed + - tp_spine_policy_group_present.current.0.fabricSpPortPGrp.children | selectattr('fabricRsOpticsFabIfPol.attributes.tDn', 'defined') | selectattr('fabricRsOpticsFabIfPol.attributes.tDn', 'equalto', "uni/fabric/zrfab-default") + - tp_spine_policy_group_absent.current.0.fabricSpPortPGrp.children | selectattr('fabricRsOpticsFabIfPol.attributes.tDn', 'defined') | selectattr('fabricRsOpticsFabIfPol.attributes.tDn', 'equalto', "") + +- name: Add a spine fabric interface policy group with normal mode + aci_fabric_interface_policy_group: + <<: *cm_spine_policy_group_present + register: nm_spine_policy_group_present + +- name: Add a spine fabric interface policy group with normal mode again + aci_fabric_interface_policy_group: + <<: *cm_spine_policy_group_present + register: nm_spine_policy_group_present_again + +- name: Update a spine fabric interface policy group with check mode + aci_fabric_interface_policy_group: &cm_spine_policy_group_update + <<: *cm_spine_policy_group_present + descr: spine_policy_group updated + dwdm_policy: "" + link_level_policy: "" + link_flap_policy: "" + l3_interface_policy: "" + macsec_policy: "" + monitoring_policy: "" + check_mode: true + register: cm_spine_policy_group_update + +- name: Update a spine fabric interface policy group with normal mode + aci_fabric_interface_policy_group: + <<: *cm_spine_policy_group_update + register: nm_spine_policy_group_update + +- name: Update a spine fabric interface policy group with normal mode again + aci_fabric_interface_policy_group: + <<: *cm_spine_policy_group_update + register: nm_spine_policy_group_update_again + +- name: Assertions check for add fabric interface policy groups + assert: + that: + - cm_leaf_policy_group_present is changed + - cm_leaf_policy_group_present.current == [] + - cm_leaf_policy_group_present.previous == [] + - cm_leaf_policy_group_present.mo.fabricLePortPGrp.attributes.name == "leaf_policy_group" + - cm_leaf_policy_group_present.mo.fabricLePortPGrp.attributes.descr == "leaf_policy_group created" + - nm_leaf_policy_group_present is changed + - nm_leaf_policy_group_present.current != [] + - nm_leaf_policy_group_present.previous == [] + - nm_leaf_policy_group_present.current.0.fabricLePortPGrp.attributes.name == "leaf_policy_group" + - nm_leaf_policy_group_present.current.0.fabricLePortPGrp.attributes.descr == "leaf_policy_group created" + - nm_leaf_policy_group_present.current.0.fabricLePortPGrp.attributes.dn == "uni/fabric/funcprof/leportgrp-leaf_policy_group" + - nm_leaf_policy_group_present.current.0.fabricLePortPGrp.children | length >= 6 + - nm_leaf_policy_group_present_again is not changed + - nm_leaf_policy_group_present_again.current != [] + - nm_leaf_policy_group_present_again.previous != [] + - nm_leaf_policy_group_present_again.current.0.fabricLePortPGrp.attributes.name == nm_leaf_policy_group_present_again.previous.0.fabricLePortPGrp.attributes.name == "leaf_policy_group" + - nm_leaf_policy_group_present_again.current.0.fabricLePortPGrp.attributes.descr == nm_leaf_policy_group_present_again.previous.0.fabricLePortPGrp.attributes.descr == "leaf_policy_group created" + - nm_leaf_policy_group_present_again.current.0.fabricLePortPGrp.attributes.dn == nm_leaf_policy_group_present_again.previous.0.fabricLePortPGrp.attributes.dn == "uni/fabric/funcprof/leportgrp-leaf_policy_group" + - cm_spine_policy_group_present is changed + - cm_spine_policy_group_present.current == [] + - cm_spine_policy_group_present.previous == [] + - cm_spine_policy_group_present.mo.fabricSpPortPGrp.attributes.name == "spine_policy_group" + - cm_spine_policy_group_present.mo.fabricSpPortPGrp.attributes.descr == "spine_policy_group created" + - nm_spine_policy_group_present is changed + - nm_spine_policy_group_present.current != [] + - nm_spine_policy_group_present.current.0.fabricSpPortPGrp.attributes.name == "spine_policy_group" + - nm_spine_policy_group_present.current.0.fabricSpPortPGrp.attributes.descr == "spine_policy_group created" + - nm_spine_policy_group_present.current.0.fabricSpPortPGrp.attributes.dn == "uni/fabric/funcprof/spportgrp-spine_policy_group" + - nm_spine_policy_group_present.current.0.fabricSpPortPGrp.children | length >= 6 + - nm_spine_policy_group_present.current.0.fabricSpPortPGrp.children | selectattr('fabricRsDwdmFabIfPol.attributes.tnDwdmFabIfPolName', 'defined') | selectattr('fabricRsDwdmFabIfPol.attributes.tnDwdmFabIfPolName', 'equalto', "default") + - nm_spine_policy_group_present.current.0.fabricSpPortPGrp.children | selectattr('fabricRsFIfPol.attributes.tnFabricFIfPolName', 'defined') | selectattr('fabricRsFIfPol.attributes.tnFabricFIfPolName', 'equalto', "default") + - nm_spine_policy_group_present.current.0.fabricSpPortPGrp.children | selectattr('fabricRsFLinkFlapPol.attributes.tnFabricFLinkFlapPolName', 'defined') | selectattr('fabricRsFLinkFlapPol.attributes.tnFabricFLinkFlapPolName', 'equalto', "default") + - nm_spine_policy_group_present.current.0.fabricSpPortPGrp.children | selectattr('fabricRsL3IfPol.attributes.tnL3IfPolName', 'defined') | selectattr('fabricRsL3IfPol.attributes.tnL3IfPolName', 'equalto', "default") + - nm_spine_policy_group_present.current.0.fabricSpPortPGrp.children | selectattr('fabricRsMacsecFabIfPol.attributes.tnMacsecFabIfPolName', 'defined') | selectattr('fabricRsMacsecFabIfPol.attributes.tnMacsecFabIfPolName', 'equalto', "default") + - nm_spine_policy_group_present.current.0.fabricSpPortPGrp.children | selectattr('fabricRsMonIfFabricPol.attributes.tnMonFabricPolName', 'defined') | selectattr('fabricRsMonIfFabricPol.attributes.tnMonFabricPolName', 'equalto', "default") + - nm_spine_policy_group_present_again is not changed + - nm_spine_policy_group_present_again.current != [] + - nm_spine_policy_group_present_again.previous != [] + - nm_spine_policy_group_present_again.current.0.fabricSpPortPGrp.attributes.name == nm_spine_policy_group_present_again.previous.0.fabricSpPortPGrp.attributes.name == "spine_policy_group" + - nm_spine_policy_group_present_again.current.0.fabricSpPortPGrp.attributes.descr == nm_spine_policy_group_present_again.previous.0.fabricSpPortPGrp.attributes.descr == "spine_policy_group created" + - nm_spine_policy_group_present_again.current.0.fabricSpPortPGrp.attributes.dn == nm_spine_policy_group_present_again.previous.0.fabricSpPortPGrp.attributes.dn == "uni/fabric/funcprof/spportgrp-spine_policy_group" + - cm_spine_policy_group_update is changed + - cm_spine_policy_group_update.previous.0.fabricSpPortPGrp.attributes.descr == "spine_policy_group created" + - cm_spine_policy_group_update.current.0.fabricSpPortPGrp.attributes.descr == "spine_policy_group created" + - nm_spine_policy_group_update is changed + - nm_spine_policy_group_update.previous.0.fabricSpPortPGrp.attributes.descr == "spine_policy_group created" + - nm_spine_policy_group_update.current.0.fabricSpPortPGrp.attributes.descr == "spine_policy_group updated" + - nm_spine_policy_group_update.previous.0.fabricSpPortPGrp.children | selectattr('fabricRsDwdmFabIfPol.attributes.tnDwdmFabIfPolName', 'defined') | selectattr('fabricRsDwdmFabIfPol.attributes.tnDwdmFabIfPolName', 'equalto', "default") + - nm_spine_policy_group_update.previous.0.fabricSpPortPGrp.children | selectattr('fabricRsFIfPol.attributes.tnFabricFIfPolName', 'defined') | selectattr('fabricRsFIfPol.attributes.tnFabricFIfPolName', 'equalto', "default") + - nm_spine_policy_group_update.previous.0.fabricSpPortPGrp.children | selectattr('fabricRsFLinkFlapPol.attributes.tnFabricFLinkFlapPolName', 'defined') | selectattr('fabricRsFLinkFlapPol.attributes.tnFabricFLinkFlapPolName', 'equalto', "default") + - nm_spine_policy_group_update.previous.0.fabricSpPortPGrp.children | selectattr('fabricRsL3IfPol.attributes.tnL3IfPolName', 'defined') | selectattr('fabricRsL3IfPol.attributes.tnL3IfPolName', 'equalto', "default") + - nm_spine_policy_group_update.previous.0.fabricSpPortPGrp.children | selectattr('fabricRsMacsecFabIfPol.attributes.tnMacsecFabIfPolName', 'defined') | selectattr('fabricRsMacsecFabIfPol.attributes.tnMacsecFabIfPolName', 'equalto', "default") + - nm_spine_policy_group_update.previous.0.fabricSpPortPGrp.children | selectattr('fabricRsMonIfFabricPol.attributes.tnMonFabricPolName', 'defined') | selectattr('fabricRsMonIfFabricPol.attributes.tnMonFabricPolName', 'equalto', "default") + - nm_spine_policy_group_update.current.0.fabricSpPortPGrp.children | selectattr('fabricRsDwdmFabIfPol.attributes.tnDwdmFabIfPolName', 'defined') | selectattr('fabricRsDwdmFabIfPol.attributes.tnDwdmFabIfPolName', 'equalto', "") + - nm_spine_policy_group_update.current.0.fabricSpPortPGrp.children | selectattr('fabricRsFIfPol.attributes.tnFabricFIfPolName', 'defined') | selectattr('fabricRsFIfPol.attributes.tnFabricFIfPolName', 'equalto', "") + - nm_spine_policy_group_update.current.0.fabricSpPortPGrp.children | selectattr('fabricRsFLinkFlapPol.attributes.tnFabricFLinkFlapPolName', 'defined') | selectattr('fabricRsFLinkFlapPol.attributes.tnFabricFLinkFlapPolName', 'equalto', "") + - nm_spine_policy_group_update.current.0.fabricSpPortPGrp.children | selectattr('fabricRsL3IfPol.attributes.tnL3IfPolName', 'defined') | selectattr('fabricRsL3IfPol.attributes.tnL3IfPolName', 'equalto', "") + - nm_spine_policy_group_update.current.0.fabricSpPortPGrp.children | selectattr('fabricRsMacsecFabIfPol.attributes.tnMacsecFabIfPolName', 'defined') | selectattr('fabricRsMacsecFabIfPol.attributes.tnMacsecFabIfPolName', 'equalto', "") + - nm_spine_policy_group_update.current.0.fabricSpPortPGrp.children | selectattr('fabricRsMonIfFabricPol.attributes.tnMonFabricPolName', 'defined') | selectattr('fabricRsMonIfFabricPol.attributes.tnMonFabricPolName', 'equalto', "") + - nm_spine_policy_group_update_again is not changed + - nm_spine_policy_group_update_again.previous.0.fabricSpPortPGrp.attributes.descr == "spine_policy_group updated" + - nm_spine_policy_group_update_again.current.0.fabricSpPortPGrp.attributes.descr == "spine_policy_group updated" + +- name: Invalid test - add a fabric interface policy group without type + aci_fabric_interface_policy_group: + <<: *aci_info + name: nt_spine_policy_group + descr: negative test nt_spine_policy_group + state: present + register: nt_without_type + ignore_errors: true + +- name: Invalid test - add a fabric interface policy group without name + aci_fabric_interface_policy_group: + <<: *aci_info + type: spine + descr: negative test spine_policy_group + state: present + register: nt_without_name + ignore_errors: true + +- name: Assertions check for invalid test - add fabric interface policy groups + assert: + that: + - nt_without_type is not changed + - nt_without_type.msg == "missing required arguments{{':'}} type" + - nt_without_name is not changed + - nt_without_name.msg == "state is present but all of the following are missing{{':'}} name" + +- name: Query a leaf fabric interface policy group with name + aci_fabric_interface_policy_group: + <<: *aci_info + name: leaf_policy_group + type: leaf + state: query + register: query_leaf_policy_group + +- name: Query all leaf fabric interface policy groups + aci_fabric_interface_policy_group: + <<: *aci_info + type: leaf + state: query + register: query_all_leaf_policy_group + +- name: Query a spine fabric interface policy group with name + aci_fabric_interface_policy_group: + <<: *aci_info + name: spine_policy_group + type: spine + state: query + register: query_a_spine_policy_group + +- name: Query all spine fabric interface policy groups + aci_fabric_interface_policy_group: + <<: *aci_info + type: spine + state: query + register: query_all_spine_policy_group + +- name: Assertions check for query a fabric interface policy groups + assert: + that: + - query_leaf_policy_group is not changed + - query_leaf_policy_group.current != [] + - query_leaf_policy_group.current.0.fabricLePortPGrp.attributes.name == "leaf_policy_group" + - query_leaf_policy_group.current.0.fabricLePortPGrp.attributes.dn == "uni/fabric/funcprof/leportgrp-leaf_policy_group" + - query_leaf_policy_group.current.0.fabricLePortPGrp.attributes.descr == "leaf_policy_group created" + - query_all_leaf_policy_group is not changed + - query_all_leaf_policy_group.current != [] + - query_all_leaf_policy_group.current | length >= 1 + - query_a_spine_policy_group is not changed + - query_a_spine_policy_group.current != [] + - query_a_spine_policy_group.current.0.fabricSpPortPGrp.attributes.name == "spine_policy_group" + - query_a_spine_policy_group.current.0.fabricSpPortPGrp.attributes.dn == "uni/fabric/funcprof/spportgrp-spine_policy_group" + - query_a_spine_policy_group.current.0.fabricSpPortPGrp.attributes.descr == "spine_policy_group updated" + - query_all_spine_policy_group is not changed + - query_all_spine_policy_group.current != [] + - query_all_spine_policy_group.current | length >= 1 + +- name: Remove a leaf fabric interface policy group with check mode + aci_fabric_interface_policy_group: &cm_leaf_policy_group_absent + <<: *cm_leaf_policy_group_present + state: absent + check_mode: true + register: cm_leaf_policy_group_absent + +- name: Remove a leaf fabric interface policy group with normal mode + aci_fabric_interface_policy_group: + <<: *cm_leaf_policy_group_absent + register: nm_leaf_policy_group_absent + +- name: Remove a leaf fabric interface policy group with normal mode again + aci_fabric_interface_policy_group: + <<: *cm_leaf_policy_group_absent + register: nm_leaf_policy_group_absent_again + +- name: Remove a spine fabric interface policy group with check mode + aci_fabric_interface_policy_group: &cm_spine_policy_group_absent + <<: *cm_spine_policy_group_present + state: absent + check_mode: true + register: cm_spine_policy_group_absent + +- name: Remove a spine fabric interface policy group with normal mode + aci_fabric_interface_policy_group: + <<: *cm_spine_policy_group_absent + register: nm_spine_policy_group_absent + +- name: Remove a spine fabric interface policy group with normal mode again + aci_fabric_interface_policy_group: + <<: *cm_spine_policy_group_absent + register: nm_spine_policy_group_absent_again + +- name: Assertions check for remove a fabric interface policy groups + assert: + that: + - cm_leaf_policy_group_absent is changed + - cm_leaf_policy_group_absent.current != [] + - cm_leaf_policy_group_absent.previous != [] + - nm_leaf_policy_group_absent is changed + - nm_leaf_policy_group_absent.current == [] + - nm_leaf_policy_group_absent.previous != [] + - nm_leaf_policy_group_absent_again is not changed + - nm_leaf_policy_group_absent_again.current == [] + - nm_leaf_policy_group_absent_again.previous == [] + - cm_spine_policy_group_absent is changed + - cm_spine_policy_group_absent.current != [] + - cm_spine_policy_group_absent.previous != [] + - nm_spine_policy_group_absent is changed + - nm_spine_policy_group_absent.current == [] + - nm_spine_policy_group_absent.previous != [] + - nm_spine_policy_group_absent_again is not changed + - nm_spine_policy_group_absent_again.current == [] + - nm_spine_policy_group_absent_again.previous == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_node/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_node/tasks/main.yml index 36e065e5b..552661556 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_node/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_node/tasks/main.yml @@ -1,5 +1,6 @@ # Test code for the ACI modules # Copyright: (c) 2017, Bruno Calogero <brunocalogero@hotmail.com> +# Copyright: (c) 2023, Gaspard Micol <gmicol@cisco.com> # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -8,38 +9,52 @@ msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' # CLEAN ENVIRONMENT - name: Remove fabric node cisco.aci.aci_fabric_node: &aci_fabric_node_absent - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' + <<: *aci_info serial: ansible_test node_id: 105 state: absent +- name: Remove fabric node 2 + cisco.aci.aci_fabric_node: &aci_fabric_node_absent_2 + <<: *aci_info + serial: ansible_test_2 + node_id: 106 + state: absent # ADD FABRIC NODE -- name: Add fabric node (check_mode) +- name: Add fabric node with tier-2 leaf (check_mode) cisco.aci.aci_fabric_node: &aci_fabric_node_present - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug - serial: ansible_test - node_id: 105 + <<: *aci_fabric_node_absent switch: anstest + role: leaf + node_type: tier_2 state: present check_mode: true - register: cm_add_fabric_node + register: cm_add_fabric_node_tier_2 + +- name: Add fabric node with remote leaf + cisco.aci.aci_fabric_node: &aci_fabric_node_present_2 + <<: *aci_fabric_node_absent_2 + switch: anstest_2 + role: leaf + node_type: remote + remote_leaf_pool_id: 2 + state: present + register: nm_add_fabric_node_remote - name: Add fabric node (normal mode) cisco.aci.aci_fabric_node: *aci_fabric_node_present @@ -54,15 +69,44 @@ cisco.aci.aci_fabric_node: *aci_fabric_node_present register: nm_add_fabric_node_again +- name: test error - mutually exclusive attributes + cisco.aci.aci_fabric_node: + <<: *aci_fabric_node_present_2 + node_type: tier_2 + register: test_error_mutually_exclusive + ignore_errors: true + +- name: test error - check failure when changing node type + cisco.aci.aci_fabric_node: + <<: *aci_fabric_node_present + node_type: virtual + register: test_error_change__node_type + ignore_errors: true + +- name: test error - check failure when changing Pool Id + cisco.aci.aci_fabric_node: + <<: *aci_fabric_node_present_2 + remote_leaf_pool_id: 3 + register: test_error_change_Pool_Id + ignore_errors: true + - name: Verify add_fabric_node assert: that: - - cm_add_fabric_node is changed + - cm_add_fabric_node_tier_2 is changed - nm_add_fabric_node is changed - nm_add_fabric_node.current.0.fabricNodeIdentP.attributes.annotation == 'orchestrator:ansible' + - nm_add_fabric_node.current.0.fabricNodeIdentP.attributes.role == 'leaf' + - nm_add_fabric_node.current.0.fabricNodeIdentP.attributes.nodeType == 'tier-2-leaf' + - nm_add_fabric_node_remote is changed + - nm_add_fabric_node_remote.current.0.fabricNodeIdentP.attributes.nodeType == 'remote-leaf-wan' + - nm_add_fabric_node_remote.current.0.fabricNodeIdentP.attributes.extPoolId == '2' # FIXME: Module is not idempotent - cm_add_fabric_node_again is not changed - nm_add_fabric_node_again is not changed + - test_error_mutually_exclusive.msg == "External Pool Id is not compatible with a node type other than 'remote'." + - test_error_change__node_type.error.text == "Create-only and naming props cannot be modified after creation, class=fabricNodeIdentP, prop=nodeType" + - test_error_change_Pool_Id.error.text == "Create-only and naming props cannot be modified after creation, class=fabricNodeIdentP, prop=extPoolId" # CHANGE FABRIC NODE @@ -150,7 +194,7 @@ - name: Query our fabric_node cisco.aci.aci_fabric_node: <<: *aci_fabric_node_query - serial: ansible_test # might need node_id too + serial: ansible_test check_mode: true register: cm_query_fabric_node diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_node_control/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_node_control/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_node_control/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_node_control/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_node_control/tasks/main.yml new file mode 100644 index 000000000..f41c69150 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_node_control/tasks/main.yml @@ -0,0 +1,179 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Tim Cragg (@timcragg) +# Copyright: (c) 2023, Akini Ross (@akinross) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +# CLEAN ENVIRONMENT +- name: Pre-Test Clean Environment of Fabric Node Controls + cisco.aci.aci_fabric_node_control: + <<: *aci_info + name: "{{ item }}" + state: absent + loop: + - ansible_fabric_node_control_1 + - ansible_fabric_node_control_2 + - ansible_fabric_node_control_3 + +# CREATE FABRIC NODE CONTROL +- name: Create Fabric Node Control (check mode) + cisco.aci.aci_fabric_node_control: &aci_fabric_node_control + <<: *aci_info + name: ansible_fabric_node_control_1 + check_mode: true + register: cm_create_fabric_node_control + +- name: Create Fabric Node Control (normal mode) + cisco.aci.aci_fabric_node_control: + <<: *aci_fabric_node_control + register: nm_create_fabric_node_control + +- name: Create Fabric Node Control again + cisco.aci.aci_fabric_node_control: + <<: *aci_fabric_node_control + register: nm_create_fabric_node_control_again + +- name: Verify Fabric Node Control creation + ansible.builtin.assert: + that: + - cm_create_fabric_node_control is changed + - cm_create_fabric_node_control.current == [] + - cm_create_fabric_node_control.previous == [] + - cm_create_fabric_node_control.proposed.fabricNodeControl.attributes.name == "ansible_fabric_node_control_1" + - nm_create_fabric_node_control is changed + - nm_create_fabric_node_control.previous == [] + - nm_create_fabric_node_control.current.0.fabricNodeControl.attributes.control == "" + - nm_create_fabric_node_control.current.0.fabricNodeControl.attributes.descr == "" + - nm_create_fabric_node_control.current.0.fabricNodeControl.attributes.featureSel == "telemetry" + - nm_create_fabric_node_control.current.0.fabricNodeControl.attributes.name == "ansible_fabric_node_control_1" + - nm_create_fabric_node_control_again is not changed + - nm_create_fabric_node_control_again.current.0.fabricNodeControl.attributes.control == "" + - nm_create_fabric_node_control_again.current.0.fabricNodeControl.attributes.descr == "" + - nm_create_fabric_node_control_again.current.0.fabricNodeControl.attributes.featureSel == "telemetry" + - nm_create_fabric_node_control_again.current.0.fabricNodeControl.attributes.name == "ansible_fabric_node_control_1" + - nm_create_fabric_node_control_again.previous.0.fabricNodeControl.attributes.control == "" + - nm_create_fabric_node_control_again.previous.0.fabricNodeControl.attributes.descr == "" + - nm_create_fabric_node_control_again.previous.0.fabricNodeControl.attributes.featureSel == "telemetry" + - nm_create_fabric_node_control_again.previous.0.fabricNodeControl.attributes.name == "ansible_fabric_node_control_1" + +# UPDATE FABRIC NODE CONTROL +- name: Update Fabric Node Control + cisco.aci.aci_fabric_node_control: + <<: *aci_fabric_node_control + description: Updated Ansible Test Fabric Node Control + enable_dom: true + feature_selection: analytics + register: update_fabric_node_control + +- name: Verify Fabric Node Control update + ansible.builtin.assert: + that: + - update_fabric_node_control is changed + - update_fabric_node_control.current.0.fabricNodeControl.attributes.control == "Dom" + - update_fabric_node_control.current.0.fabricNodeControl.attributes.descr == "Updated Ansible Test Fabric Node Control" + - update_fabric_node_control.current.0.fabricNodeControl.attributes.featureSel == "analytics" + - update_fabric_node_control.current.0.fabricNodeControl.attributes.name == "ansible_fabric_node_control_1" + - update_fabric_node_control.previous.0.fabricNodeControl.attributes.control == "" + - update_fabric_node_control.previous.0.fabricNodeControl.attributes.descr == "" + - update_fabric_node_control.previous.0.fabricNodeControl.attributes.featureSel == "telemetry" + - update_fabric_node_control.previous.0.fabricNodeControl.attributes.name == "ansible_fabric_node_control_1" + +# QUERY FABRIC NODE CONTROL +- name: Create another Fabric Node Control + cisco.aci.aci_fabric_node_control: + <<: *aci_info + name: "{{ item }}" + feature_selection: netflow + loop: + - ansible_fabric_node_control_2 + - ansible_fabric_node_control_3 + +- name: Query a Fabric Node Control + cisco.aci.aci_fabric_node_control: + <<: *aci_fabric_node_control + state: query + register: query_one + +- name: Query all Fabric Node Controls + cisco.aci.aci_fabric_node_control: + <<: *aci_info + state: query + register: query_all + +- name: Verify Fabric Node Control queries + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current | length == 1 + - query_one.current.0.fabricNodeControl.attributes.control == "Dom" + - query_one.current.0.fabricNodeControl.attributes.descr == "Updated Ansible Test Fabric Node Control" + - query_one.current.0.fabricNodeControl.attributes.featureSel == "analytics" + - query_one.current.0.fabricNodeControl.attributes.name == "ansible_fabric_node_control_1" + - query_all is not changed + - query_all.current | length > 3 + +# REMOVE FABRIC NODE CONTROL +- name: Remove Fabric Node Control (check mode) + cisco.aci.aci_fabric_node_control: + <<: *aci_fabric_node_control + state: absent + register: cm_remove_fabric_node_control + check_mode: true + +- name: Remove Fabric Node Control + cisco.aci.aci_fabric_node_control: + <<: *aci_fabric_node_control + state: absent + register: nm_remove_fabric_node_control + +- name: Remove Fabric Node Control again + cisco.aci.aci_fabric_node_control: + <<: *aci_fabric_node_control + state: absent + register: nm__remove_fabric_node_control_again + +- name: Verify Fabric Node Control removal + ansible.builtin.assert: + that: + - cm_remove_fabric_node_control is changed + - cm_remove_fabric_node_control.proposed == {} + - cm_remove_fabric_node_control.previous.0.fabricNodeControl.attributes.control == "Dom" + - cm_remove_fabric_node_control.previous.0.fabricNodeControl.attributes.descr == "Updated Ansible Test Fabric Node Control" + - cm_remove_fabric_node_control.previous.0.fabricNodeControl.attributes.featureSel == "analytics" + - cm_remove_fabric_node_control.previous.0.fabricNodeControl.attributes.name == "ansible_fabric_node_control_1" + - nm_remove_fabric_node_control is changed + - nm_remove_fabric_node_control.current == [] + - nm_remove_fabric_node_control.previous.0.fabricNodeControl.attributes.control == "Dom" + - nm_remove_fabric_node_control.previous.0.fabricNodeControl.attributes.descr == "Updated Ansible Test Fabric Node Control" + - nm_remove_fabric_node_control.previous.0.fabricNodeControl.attributes.featureSel == "analytics" + - nm_remove_fabric_node_control.previous.0.fabricNodeControl.attributes.name == "ansible_fabric_node_control_1" + - nm__remove_fabric_node_control_again is not changed + - nm__remove_fabric_node_control_again.current == [] + - nm__remove_fabric_node_control_again.previous == [] + +# CLEAN ENVIRONMENT +- name: PPost-Test Clean Environment of Fabric Node Controls + cisco.aci.aci_fabric_node_control: + <<: *aci_info + name: "{{ item }}" + state: absent + loop: + - ansible_fabric_node_control_1 + - ansible_fabric_node_control_2 + - ansible_fabric_node_control_3 diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_pod_selector/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_pod_selector/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_pod_selector/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_pod_selector/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_pod_selector/tasks/main.yml new file mode 100644 index 000000000..ca9fb8209 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_pod_selector/tasks/main.yml @@ -0,0 +1,305 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Tim Cragg (@timcragg) +# Copyright: (c) 2023, Akini Ross (@akinross) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +# CLEAN EXISTING ENVIRONMENT +- name: Ensure Fabric Pod Selectors are absent before testing + cisco.aci.aci_fabric_pod_selector: + <<: *aci_info + name: "{{ item.name }}" + pod_profile: default + type: "{{ item.type }}" + state: absent + loop: + - {name: ansible_fabric_pod_pol_sel_1, type: all} + - {name: ansible_fabric_pod_pol_sel_2, type: range} + - {name: ansible_fabric_pod_pol_sel_3, type: range} + - {name: default, type: all} + +- name: Ensure a Pod Policy Group exists before testing + cisco.aci.aci_fabric_pod_policy_group: + <<: *aci_info + name: ansible_fabric_pod_pol_grp_1 + +# CREATE FABRIC POD SELECTOR TYPE ALL +- name: Create Fabric Pod Selector without blocks (check mode) + cisco.aci.aci_fabric_pod_selector: &fabric_pod_sel_without_blocks + <<: *aci_info + name: ansible_fabric_pod_pol_sel_1 + type: all + pod_profile: default + description: Created Ansible Pod Selector + check_mode: true + register: cm_create_fabric_pod_sel_without_blocks + +- name: Create Fabric Pod Selector without blocks + cisco.aci.aci_fabric_pod_selector: + <<: *fabric_pod_sel_without_blocks + register: nm_create_fabric_pod_sel_without_blocks + +- name: Create Fabric Pod Selector without blocks again + cisco.aci.aci_fabric_pod_selector: + <<: *fabric_pod_sel_without_blocks + register: nm_create_fabric_pod_sel_without_blocks_again + +- name: Verify create of Pod Selector + ansible.builtin.assert: + that: + - cm_create_fabric_pod_sel_without_blocks is changed + - cm_create_fabric_pod_sel_without_blocks.current == [] + - cm_create_fabric_pod_sel_without_blocks.previous == [] + - cm_create_fabric_pod_sel_without_blocks.proposed.fabricPodS.attributes.annotation == "orchestrator:ansible" + - cm_create_fabric_pod_sel_without_blocks.proposed.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - cm_create_fabric_pod_sel_without_blocks.proposed.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_1-typ-ALL" + - cm_create_fabric_pod_sel_without_blocks.proposed.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_1" + - cm_create_fabric_pod_sel_without_blocks.proposed.fabricPodS.attributes.type == "ALL" + - nm_create_fabric_pod_sel_without_blocks is changed + - nm_create_fabric_pod_sel_without_blocks.current.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - nm_create_fabric_pod_sel_without_blocks.current.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - nm_create_fabric_pod_sel_without_blocks.current.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_1-typ-ALL" + - nm_create_fabric_pod_sel_without_blocks.current.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_1" + - nm_create_fabric_pod_sel_without_blocks.current.0.fabricPodS.attributes.type == "ALL" + - nm_create_fabric_pod_sel_without_blocks.previous == [] + - nm_create_fabric_pod_sel_without_blocks.proposed.fabricPodS.attributes.annotation == "orchestrator:ansible" + - nm_create_fabric_pod_sel_without_blocks.proposed.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - nm_create_fabric_pod_sel_without_blocks.proposed.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_1-typ-ALL" + - nm_create_fabric_pod_sel_without_blocks.proposed.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_1" + - nm_create_fabric_pod_sel_without_blocks.proposed.fabricPodS.attributes.type == "ALL" + - nm_create_fabric_pod_sel_without_blocks_again is not changed + - nm_create_fabric_pod_sel_without_blocks_again.current.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - nm_create_fabric_pod_sel_without_blocks_again.current.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - nm_create_fabric_pod_sel_without_blocks_again.current.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_1-typ-ALL" + - nm_create_fabric_pod_sel_without_blocks_again.current.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_1" + - nm_create_fabric_pod_sel_without_blocks_again.current.0.fabricPodS.attributes.type == "ALL" + - nm_create_fabric_pod_sel_without_blocks_again.previous.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - nm_create_fabric_pod_sel_without_blocks_again.previous.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - nm_create_fabric_pod_sel_without_blocks_again.previous.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_1-typ-ALL" + - nm_create_fabric_pod_sel_without_blocks_again.previous.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_1" + - nm_create_fabric_pod_sel_without_blocks_again.previous.0.fabricPodS.attributes.type == "ALL" + +# REMOVE FABRIC POD SELECTOR +- name: Remove Fabric Pod Selector without blocks (check mode) + cisco.aci.aci_fabric_pod_selector: + <<: *fabric_pod_sel_without_blocks + state: absent + check_mode: true + register: cm_remove_fabric_pod_sel_without_blocks + +- name: Remove Fabric Pod Selector without blocks + cisco.aci.aci_fabric_pod_selector: + <<: *fabric_pod_sel_without_blocks + state: absent + register: nm_remove_fabric_pod_sel_without_blocks + +- name: Remove Fabric Pod Selector without blocks again + cisco.aci.aci_fabric_pod_selector: + <<: *fabric_pod_sel_without_blocks + state: absent + register: nm_remove_fabric_pod_sel_without_blocks_again + +- name: Verify removal of Pod Selector + ansible.builtin.assert: + that: + - cm_remove_fabric_pod_sel_without_blocks is changed + - cm_remove_fabric_pod_sel_without_blocks.proposed == {} + - cm_remove_fabric_pod_sel_without_blocks.current.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - cm_remove_fabric_pod_sel_without_blocks.current.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - cm_remove_fabric_pod_sel_without_blocks.current.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_1-typ-ALL" + - cm_remove_fabric_pod_sel_without_blocks.current.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_1" + - cm_remove_fabric_pod_sel_without_blocks.current.0.fabricPodS.attributes.type == "ALL" + - cm_remove_fabric_pod_sel_without_blocks.previous.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - cm_remove_fabric_pod_sel_without_blocks.previous.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - cm_remove_fabric_pod_sel_without_blocks.previous.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_1-typ-ALL" + - cm_remove_fabric_pod_sel_without_blocks.previous.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_1" + - cm_remove_fabric_pod_sel_without_blocks.previous.0.fabricPodS.attributes.type == "ALL" + - nm_remove_fabric_pod_sel_without_blocks is changed + - nm_remove_fabric_pod_sel_without_blocks.proposed == {} + - nm_remove_fabric_pod_sel_without_blocks.current == [] + - nm_remove_fabric_pod_sel_without_blocks.previous.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - nm_remove_fabric_pod_sel_without_blocks.previous.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - nm_remove_fabric_pod_sel_without_blocks.previous.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_1-typ-ALL" + - nm_remove_fabric_pod_sel_without_blocks.previous.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_1" + - nm_remove_fabric_pod_sel_without_blocks.previous.0.fabricPodS.attributes.type == "ALL" + - nm_remove_fabric_pod_sel_without_blocks_again is not changed + - nm_remove_fabric_pod_sel_without_blocks_again.current == [] + - nm_remove_fabric_pod_sel_without_blocks_again.previous == [] + +# CREATE & UPDATE FABRIC POD SELECTOR TYPE RANGE +- name: Create Fabric Pod Selector with blocks and policy + cisco.aci.aci_fabric_pod_selector: &fabric_pod_sel_blocks + <<: *fabric_pod_sel_without_blocks + name: ansible_fabric_pod_pol_sel_2 + type: range + blocks: "2" + policy_group: ansible_fabric_pod_pol_grp + register: nm_update_fabric_pod_sel_with_blocks + +- name: Create Fabric Pod Selector with blocks and policy again + cisco.aci.aci_fabric_pod_selector: + <<: *fabric_pod_sel_blocks + blocks: "2" + register: nm_update_fabric_pod_sel_with_blocks_again + +- name: Update Fabric Pod Selector with blocks and policy again with different notation + cisco.aci.aci_fabric_pod_selector: + <<: *fabric_pod_sel_blocks + blocks: "2-2" + register: nm_update_fabric_pod_sel_with_blocks_again_different_notation + +- name: Update Fabric Pod Selector with changed blocks range + cisco.aci.aci_fabric_pod_selector: &fabric_pod_sel_blocks_range + <<: *fabric_pod_sel_blocks + blocks: "2-3,5,8-11" + register: nm_update_fabric_pod_sel_with_blocks_range + +- name: Update Fabric Pod Selector with removal of policy group + cisco.aci.aci_fabric_pod_selector: + <<: *fabric_pod_sel_blocks_range + policy_group: "" + register: nm_update_fabric_pod_sel_with_blocks_no_policy + +- name: Verify update of Pod Selector + ansible.builtin.assert: + that: + - nm_update_fabric_pod_sel_with_blocks is changed + - nm_update_fabric_pod_sel_with_blocks.current.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - nm_update_fabric_pod_sel_with_blocks.current.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - nm_update_fabric_pod_sel_with_blocks.current.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_2-typ-range" + - nm_update_fabric_pod_sel_with_blocks.current.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_2" + - nm_update_fabric_pod_sel_with_blocks.current.0.fabricPodS.attributes.type == "range" + - nm_update_fabric_pod_sel_with_blocks.current.0.fabricPodS.children.0.fabricRsPodPGrp.attributes.tDn == "uni/fabric/funcprof/podpgrp-ansible_fabric_pod_pol_grp" + - nm_update_fabric_pod_sel_with_blocks.current.0.fabricPodS.children.1.fabricPodBlk.attributes.from_ == "2" + - nm_update_fabric_pod_sel_with_blocks.current.0.fabricPodS.children.1.fabricPodBlk.attributes.to_ == "2" + - nm_update_fabric_pod_sel_with_blocks.previous == [] + - nm_update_fabric_pod_sel_with_blocks_again is not changed + - nm_update_fabric_pod_sel_with_blocks_again.current.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - nm_update_fabric_pod_sel_with_blocks_again.current.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - nm_update_fabric_pod_sel_with_blocks_again.current.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_2-typ-range" + - nm_update_fabric_pod_sel_with_blocks_again.current.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_2" + - nm_update_fabric_pod_sel_with_blocks_again.current.0.fabricPodS.attributes.type == "range" + - nm_update_fabric_pod_sel_with_blocks_again.current.0.fabricPodS.children.0.fabricRsPodPGrp.attributes.tDn == "uni/fabric/funcprof/podpgrp-ansible_fabric_pod_pol_grp" + - nm_update_fabric_pod_sel_with_blocks_again.current.0.fabricPodS.children.1.fabricPodBlk.attributes.from_ == "2" + - nm_update_fabric_pod_sel_with_blocks_again.current.0.fabricPodS.children.1.fabricPodBlk.attributes.to_ == "2" + - nm_update_fabric_pod_sel_with_blocks_again.previous.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - nm_update_fabric_pod_sel_with_blocks_again.previous.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - nm_update_fabric_pod_sel_with_blocks_again.previous.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_2-typ-range" + - nm_update_fabric_pod_sel_with_blocks_again.previous.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_2" + - nm_update_fabric_pod_sel_with_blocks_again.previous.0.fabricPodS.attributes.type == "range" + - nm_update_fabric_pod_sel_with_blocks_again.previous.0.fabricPodS.children.0.fabricRsPodPGrp.attributes.tDn == "uni/fabric/funcprof/podpgrp-ansible_fabric_pod_pol_grp" + - nm_update_fabric_pod_sel_with_blocks_again.previous.0.fabricPodS.children.1.fabricPodBlk.attributes.from_ == "2" + - nm_update_fabric_pod_sel_with_blocks_again.previous.0.fabricPodS.children.1.fabricPodBlk.attributes.to_ == "2" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation is not changed + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.current.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.current.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.current.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_2-typ-range" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.current.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_2" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.current.0.fabricPodS.attributes.type == "range" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.current.0.fabricPodS.children.0.fabricRsPodPGrp.attributes.tDn == "uni/fabric/funcprof/podpgrp-ansible_fabric_pod_pol_grp" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.current.0.fabricPodS.children.1.fabricPodBlk.attributes.from_ == "2" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.current.0.fabricPodS.children.1.fabricPodBlk.attributes.to_ == "2" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.previous.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.previous.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.previous.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_2-typ-range" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.previous.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_2" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.previous.0.fabricPodS.attributes.type == "range" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.previous.0.fabricPodS.children.0.fabricRsPodPGrp.attributes.tDn == "uni/fabric/funcprof/podpgrp-ansible_fabric_pod_pol_grp" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.previous.0.fabricPodS.children.1.fabricPodBlk.attributes.from_ == "2" + - nm_update_fabric_pod_sel_with_blocks_again_different_notation.previous.0.fabricPodS.children.1.fabricPodBlk.attributes.to_ == "2" + - nm_update_fabric_pod_sel_with_blocks_range is changed + - nm_update_fabric_pod_sel_with_blocks_range.current.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - nm_update_fabric_pod_sel_with_blocks_range.current.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - nm_update_fabric_pod_sel_with_blocks_range.current.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_2-typ-range" + - nm_update_fabric_pod_sel_with_blocks_range.current.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_2" + - nm_update_fabric_pod_sel_with_blocks_range.current.0.fabricPodS.attributes.type == "range" + - nm_update_fabric_pod_sel_with_blocks_range.current.0.fabricPodS.children.0.fabricRsPodPGrp.attributes.tDn == "uni/fabric/funcprof/podpgrp-ansible_fabric_pod_pol_grp" + - nm_update_fabric_pod_sel_with_blocks_range.current.0.fabricPodS.children | length == 4 + - nm_update_fabric_pod_sel_with_blocks_range.previous.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - nm_update_fabric_pod_sel_with_blocks_range.previous.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - nm_update_fabric_pod_sel_with_blocks_range.previous.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_2-typ-range" + - nm_update_fabric_pod_sel_with_blocks_range.previous.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_2" + - nm_update_fabric_pod_sel_with_blocks_range.previous.0.fabricPodS.attributes.type == "range" + - nm_update_fabric_pod_sel_with_blocks_range.previous.0.fabricPodS.children.0.fabricRsPodPGrp.attributes.tDn == "uni/fabric/funcprof/podpgrp-ansible_fabric_pod_pol_grp" + - nm_update_fabric_pod_sel_with_blocks_range.previous.0.fabricPodS.children.1.fabricPodBlk.attributes.from_ == "2" + - nm_update_fabric_pod_sel_with_blocks_range.previous.0.fabricPodS.children.1.fabricPodBlk.attributes.to_ == "2" + - nm_update_fabric_pod_sel_with_blocks_no_policy is changed + - nm_update_fabric_pod_sel_with_blocks_no_policy.current.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - nm_update_fabric_pod_sel_with_blocks_no_policy.current.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - nm_update_fabric_pod_sel_with_blocks_no_policy.current.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_2-typ-range" + - nm_update_fabric_pod_sel_with_blocks_no_policy.current.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_2" + - nm_update_fabric_pod_sel_with_blocks_no_policy.current.0.fabricPodS.attributes.type == "range" + - nm_update_fabric_pod_sel_with_blocks_no_policy.current.0.fabricPodS.children | length == 3 + - nm_update_fabric_pod_sel_with_blocks_no_policy.previous.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - nm_update_fabric_pod_sel_with_blocks_no_policy.previous.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - nm_update_fabric_pod_sel_with_blocks_no_policy.previous.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_2-typ-range" + - nm_update_fabric_pod_sel_with_blocks_no_policy.previous.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_2" + - nm_update_fabric_pod_sel_with_blocks_no_policy.previous.0.fabricPodS.attributes.type == "range" + - nm_update_fabric_pod_sel_with_blocks_no_policy.previous.0.fabricPodS.children.0.fabricRsPodPGrp.attributes.tDn == "uni/fabric/funcprof/podpgrp-ansible_fabric_pod_pol_grp" + - nm_update_fabric_pod_sel_with_blocks_no_policy.previous.0.fabricPodS.children | length == 4 + +# QUERY FABRIC POD SELECTOR +- name: Create another Fabric Pod Selector + cisco.aci.aci_fabric_pod_selector: + <<: *fabric_pod_sel_blocks + name: ansible_fabric_pod_pol_sel_3 + blocks: "6" + +- name: Query a Fabric Pod Selector + cisco.aci.aci_fabric_pod_selector: + <<: *fabric_pod_sel_blocks + state: query + register: query_one + +- name: Query all Fabric Pod Selectors + cisco.aci.aci_fabric_pod_selector: + <<: *aci_info + state: query + register: query_all + +- name: Verify queries of Fabric Pod Selectors + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current | length == 1 + - query_one.current.0.fabricPodS.attributes.annotation == "orchestrator:ansible" + - query_one.current.0.fabricPodS.attributes.descr == "Created Ansible Pod Selector" + - query_one.current.0.fabricPodS.attributes.dn == "uni/fabric/podprof-default/pods-ansible_fabric_pod_pol_sel_2-typ-range" + - query_one.current.0.fabricPodS.attributes.name == "ansible_fabric_pod_pol_sel_2" + - query_one.current.0.fabricPodS.attributes.type == "range" + - query_one.current.0.fabricPodS.children | length == 3 + - query_all is not changed + - query_all.current | length >= 2 + +# ERRORS +- name: Create Fabric Pod Selector with type range and without blocks (error) + cisco.aci.aci_fabric_pod_selector: + <<: *aci_info + name: ansible_fabric_pod_pol_sel_2 + type: range + pod_profile: default + register: err_range_without_blocks + ignore_errors: true + +- name: Verify errors of Fabric Pod Selectors + ansible.builtin.assert: + that: + - err_range_without_blocks is not changed + - err_range_without_blocks is failed + - err_range_without_blocks.msg == "The 'blocks' parameter is required when the 'type' parameter is set to 'range' and 'state' parameter is set to 'present'." diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_scheduler/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_scheduler/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_scheduler/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_scheduler/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_scheduler/tasks/main.yml new file mode 100644 index 000000000..daf5e8956 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_scheduler/tasks/main.yml @@ -0,0 +1,158 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Clean Environment + - name: Ensure first scheduler does not exist + aci_fabric_scheduler: &aci_fabric_scheduler_absent + <<: *aci_info + name: anstest_scheduler_reccuring + description: ACI scheduler test + windowname: Recurring + recurring: True + concurCap: 20 + hour: 13 + minute: 30 + day: Tuesday + state: absent + + - name: Ensure second scheduler does not exist + aci_fabric_scheduler: &aci_fabric_scheduler_2_absent + <<: *aci_info + name: anstest_scheduler_oneTime + windowname: OneTime + recurring: False + concurCap: 20 + date: "2023-11-20T24:00:00" + state: absent + + - name: Create first scheduler (check_mode) + aci_fabric_scheduler: &aci_fabric_scheduler_present + <<: *aci_fabric_scheduler_absent + state: present + check_mode: true + register: cm_add_fabric_scheduler_1 + + - name: Create first scheduler (normal_mode) + aci_fabric_scheduler: + <<: *aci_fabric_scheduler_present + register: nm_add_fabric_scheduler_1 + + - name: Create first scheduler again - testing idempotency + aci_fabric_scheduler: + <<: *aci_fabric_scheduler_present + register: idempotency_add_fabric_scheduler_1 + + - name: Create second scheduler + aci_fabric_scheduler: &aci_fabric_scheduler_2_present + <<: *aci_fabric_scheduler_2_absent + state: present + register: nm_add_fabric_scheduler_2 + + - name: Asserts for creation tasks + assert: + that: + - cm_add_fabric_scheduler_1 is changed + - cm_add_fabric_scheduler_1.previous == [] + - cm_add_fabric_scheduler_1.current == [] + - nm_add_fabric_scheduler_1 is changed + - nm_add_fabric_scheduler_1.current.0.trigSchedP.attributes.name == "anstest_scheduler_reccuring" + - nm_add_fabric_scheduler_1.current.0.trigSchedP.attributes.descr == "ACI scheduler test" + - nm_add_fabric_scheduler_1.current.0.trigSchedP.children.0.trigRecurrWindowP.attributes.concurCap == "20" + - nm_add_fabric_scheduler_1.current.0.trigSchedP.children.0.trigRecurrWindowP.attributes.day == "Tuesday" + - nm_add_fabric_scheduler_1.current.0.trigSchedP.children.0.trigRecurrWindowP.attributes.hour == "13" + - nm_add_fabric_scheduler_1.current.0.trigSchedP.children.0.trigRecurrWindowP.attributes.minute == "30" + - idempotency_add_fabric_scheduler_1 is not changed + - nm_add_fabric_scheduler_2 is changed + - nm_add_fabric_scheduler_2.current.0.trigSchedP.attributes.name == "anstest_scheduler_oneTime" + - nm_add_fabric_scheduler_2.current.0.trigSchedP.children.0.trigAbsWindowP.attributes.concurCap == "20" + - nm_add_fabric_scheduler_2.current.0.trigSchedP.children.0.trigAbsWindowP.attributes.date == "2023-11-21T00:00:00.000+00:00" + + - name: Query all scheduler + aci_fabric_scheduler: + <<: *aci_info + state: query + register: query_all_fabric_scheduler + + - name: Query first scheduler + aci_fabric_scheduler: + <<: *aci_fabric_scheduler_present + state: query + register: query_first_fabric_scheduler + + - name: Asserts for query tasks + assert: + that: + - query_all_fabric_scheduler is not changed + - query_all_fabric_scheduler.current | length >= 2 + - '"trigAbsWindowP,trigRecurrWindowP" in query_all_fabric_scheduler.filter_string' + - '"class/trigSchedP.json" in query_all_fabric_scheduler.url' + - query_first_fabric_scheduler is not changed + - query_first_fabric_scheduler.current.0.trigSchedP.attributes.name == "anstest_scheduler_reccuring" + - query_first_fabric_scheduler.current.0.trigSchedP.attributes.descr == "ACI scheduler test" + - query_first_fabric_scheduler.current.0.trigSchedP.children.0.trigRecurrWindowP.attributes.concurCap == "20" + - query_first_fabric_scheduler.current.0.trigSchedP.children.0.trigRecurrWindowP.attributes.day == "Tuesday" + - query_first_fabric_scheduler.current.0.trigSchedP.children.0.trigRecurrWindowP.attributes.hour == "13" + - query_first_fabric_scheduler.current.0.trigSchedP.children.0.trigRecurrWindowP.attributes.minute == "30" + + - name: Delete first scheduler (check_mode) + aci_fabric_scheduler: + <<: *aci_fabric_scheduler_present + state: absent + check_mode: true + register: cm_delete_fabric_scheduler_1 + + - name: Delete first scheduler (normal_mode) + aci_fabric_scheduler: + <<: *aci_fabric_scheduler_present + state: absent + register: nm_delete_fabric_scheduler_1 + + - name: Delete first scheduler again - testing idempotency + aci_fabric_scheduler: + <<: *aci_fabric_scheduler_present + state: absent + register: idempotency_delete_maintenance_group_1 + + - name: Delete second scheduler (normal_mode) + aci_fabric_scheduler: + <<: *aci_fabric_scheduler_2_present + state: absent + register: nm_delete_fabric_scheduler_2 + + - name: Asserts for deletion tasks + assert: + that: + - cm_delete_fabric_scheduler_1 is changed + - cm_delete_fabric_scheduler_1.proposed == {} + - nm_delete_fabric_scheduler_1 is changed + - nm_delete_fabric_scheduler_1.previous != [] + - nm_delete_fabric_scheduler_1.current == [] + - idempotency_delete_maintenance_group_1 is not changed + - idempotency_delete_maintenance_group_1.previous == [] + - nm_delete_fabric_scheduler_2 is changed + - nm_delete_fabric_scheduler_2.previous != [] + - nm_delete_fabric_scheduler_2.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_dst_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_dst_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_dst_group/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_dst_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_dst_group/tasks/main.yml new file mode 100644 index 000000000..a67026daa --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_dst_group/tasks/main.yml @@ -0,0 +1,264 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Akini Ross (akinross@cisco.com) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + ansible.builtin.set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +# CLEAN TEST ENVIRONMENT BEFORE TESTS + +- name: Query all fabric span destination groups ( clean before ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span destination groups ( clean before ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +# TEST CREATE AND UPDATE DESTINATION GROUPS + +- name: Add fabric span destination group 1 ( check mode ) + cisco.aci.aci_fabric_span_dst_group: &add_ansible_group_1 + <<: *aci_info + destination_group: ansible_group_1 + description: test span epg + destination_epg: + destination_ip: 10.0.0.1 + source_ip: 10.0.2.1 + tenant: ansible_test + ap: ansible_test + epg: ansible_test + state: present + check_mode: true + register: cm_add_ansible_group_1 + +- name: Add fabric span destination group 1 + cisco.aci.aci_fabric_span_dst_group: + <<: *add_ansible_group_1 + register: nm_add_ansible_group_1 + +- name: Add fabric span destination group 1 again + cisco.aci.aci_fabric_span_dst_group: + <<: *add_ansible_group_1 + register: nm_add_ansible_group_1_again + +- name: Verify add fabric span destination group 1 + ansible.builtin.assert: + that: + - cm_add_ansible_group_1 is changed + - cm_add_ansible_group_1.current == [] + - cm_add_ansible_group_1.previous == [] + - cm_add_ansible_group_1.proposed.spanDestGrp.attributes.name == "ansible_group_1" + - cm_add_ansible_group_1.proposed.spanDestGrp.attributes.descr == "test span epg" + - cm_add_ansible_group_1.proposed.spanDestGrp.children.0.spanDest.attributes.name == "ansible_group_1" + - cm_add_ansible_group_1.proposed.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ip == "10.0.0.1" + - cm_add_ansible_group_1.proposed.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.srcIpPrefix == "10.0.2.1" + - cm_add_ansible_group_1.proposed.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.tDn == "uni/tn-ansible_test/ap-ansible_test/epg-ansible_test" + - nm_add_ansible_group_1 is changed + - nm_add_ansible_group_1.previous == [] + - nm_add_ansible_group_1.current.0.spanDestGrp.attributes.name == "ansible_group_1" + - nm_add_ansible_group_1.current.0.spanDestGrp.attributes.descr == "test span epg" + - nm_add_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.attributes.name == "ansible_group_1" + - nm_add_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.dscp == "unspecified" + - nm_add_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.flowId == "1" + - nm_add_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ip == "10.0.0.1" + - nm_add_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.mtu == "1518" + - nm_add_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.srcIpPrefix == "10.0.2.1" + - nm_add_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.tDn == "uni/tn-ansible_test/ap-ansible_test/epg-ansible_test" + - nm_add_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ttl == "64" + - nm_add_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ver == "ver2" + - nm_add_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.verEnforced == "no" + - nm_add_ansible_group_1_again is not changed + - nm_add_ansible_group_1_again.current.0.spanDestGrp.attributes.name == "ansible_group_1" + - nm_add_ansible_group_1_again.current.0.spanDestGrp.attributes.descr == "test span epg" + - nm_add_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.attributes.name == "ansible_group_1" + - nm_add_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.dscp == "unspecified" + - nm_add_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.flowId == "1" + - nm_add_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ip == "10.0.0.1" + - nm_add_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.mtu == "1518" + - nm_add_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.srcIpPrefix == "10.0.2.1" + - nm_add_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.tDn == "uni/tn-ansible_test/ap-ansible_test/epg-ansible_test" + - nm_add_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ttl == "64" + - nm_add_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ver == "ver2" + - nm_add_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.verEnforced == "no" + +- name: Change fabric span destination group 1 + cisco.aci.aci_fabric_span_dst_group: &change_ansible_group_1 + <<: *aci_info + destination_group: ansible_group_1 + description: changed test span epg + destination_epg: + destination_ip: 10.0.0.2 + source_ip: 10.0.2.2 + tenant: ansible_test + ap: ansible_test + epg: ansible_test + version_enforced: true + span_version: version_1 + ttl: 4 + mtu: 1500 + flow_id: 2 + dscp: "VA" + register: change_ansible_group_1 + +- name: Apply same changes to fabric span destination group 1 + cisco.aci.aci_fabric_span_dst_group: + <<: *change_ansible_group_1 + register: change_ansible_group_1_again + +- name: Verify change fabric span destination group 1 + ansible.builtin.assert: + that: + - change_ansible_group_1 is changed + - change_ansible_group_1.previous.0.spanDestGrp.attributes.name == "ansible_group_1" + - change_ansible_group_1.previous.0.spanDestGrp.attributes.descr == "test span epg" + - change_ansible_group_1.previous.0.spanDestGrp.children.0.spanDest.attributes.name == "ansible_group_1" + - change_ansible_group_1.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.dscp == "unspecified" + - change_ansible_group_1.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.flowId == "1" + - change_ansible_group_1.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ip == "10.0.0.1" + - change_ansible_group_1.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.mtu == "1518" + - change_ansible_group_1.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.srcIpPrefix == "10.0.2.1" + - change_ansible_group_1.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.tDn == "uni/tn-ansible_test/ap-ansible_test/epg-ansible_test" + - change_ansible_group_1.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ttl == "64" + - change_ansible_group_1.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ver == "ver2" + - change_ansible_group_1.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.verEnforced == "no" + - change_ansible_group_1.current.0.spanDestGrp.attributes.name == "ansible_group_1" + - change_ansible_group_1.current.0.spanDestGrp.attributes.descr == "changed test span epg" + - change_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.attributes.name == "ansible_group_1" + - change_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.dscp == "VA" + - change_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.flowId == "2" + - change_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ip == "10.0.0.2" + - change_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.mtu == "1500" + - change_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.srcIpPrefix == "10.0.2.2" + - change_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.tDn == "uni/tn-ansible_test/ap-ansible_test/epg-ansible_test" + - change_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ttl == "4" + - change_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ver == "ver1" + - change_ansible_group_1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.verEnforced == "yes" + - change_ansible_group_1_again is not changed + - change_ansible_group_1_again.previous.0.spanDestGrp.attributes.name == "ansible_group_1" + - change_ansible_group_1_again.previous.0.spanDestGrp.attributes.descr == "changed test span epg" + - change_ansible_group_1_again.previous.0.spanDestGrp.children.0.spanDest.attributes.name == "ansible_group_1" + - change_ansible_group_1_again.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.dscp == "VA" + - change_ansible_group_1_again.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.flowId == "2" + - change_ansible_group_1_again.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ip == "10.0.0.2" + - change_ansible_group_1_again.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.mtu == "1500" + - change_ansible_group_1_again.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.srcIpPrefix == "10.0.2.2" + - change_ansible_group_1_again.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.tDn == "uni/tn-ansible_test/ap-ansible_test/epg-ansible_test" + - change_ansible_group_1_again.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ttl == "4" + - change_ansible_group_1_again.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ver == "ver1" + - change_ansible_group_1_again.previous.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.verEnforced == "yes" + - change_ansible_group_1_again.current.0.spanDestGrp.attributes.name == "ansible_group_1" + - change_ansible_group_1_again.current.0.spanDestGrp.attributes.descr == "changed test span epg" + - change_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.attributes.name == "ansible_group_1" + - change_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.dscp == "VA" + - change_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.flowId == "2" + - change_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ip == "10.0.0.2" + - change_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.mtu == "1500" + - change_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.srcIpPrefix == "10.0.2.2" + - change_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.tDn == "uni/tn-ansible_test/ap-ansible_test/epg-ansible_test" + - change_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ttl == "4" + - change_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ver == "ver1" + - change_ansible_group_1_again.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.verEnforced == "yes" + +- name: Add another fabric span destination group 2 for query all + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + destination_group: ansible_group_2 + description: test span epg 2 + destination_epg: + destination_ip: 10.0.0.3 + source_ip: 10.0.2.3 + tenant: ansible_test + ap: ansible_test + epg: ansible_test + state: present + +# TEST QUERY DESTINATION GROUPS + +- name: Query one fabric span destination group 1 + cisco.aci.aci_fabric_span_dst_group: + <<: *add_ansible_group_1 + state: query + register: query_one + +- name: Query all fabric span destination groups + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + state: query + register: query_all + +- name: Verify querying fabric span destination groups + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current | length == 1 + - query_one.current.0.spanDestGrp.attributes.name == "ansible_group_1" + - query_all is not changed + - query_all.current | length >= 2 # greater or equal because there could be configuration present that is not fabric span but is returned in ( class based ) query all + +# TEST REMOVAL DESTINATION GROUPS + +- name: Remove fabric span destination group 1 ( check mode ) + cisco.aci.aci_fabric_span_dst_group: &remove_ansible_group_1 + <<: *add_ansible_group_1 + state: absent + check_mode: true + register: cm_remove_ansible_group_1 + +- name: Remove fabric span destination group 1 + cisco.aci.aci_fabric_span_dst_group: + <<: *remove_ansible_group_1 + register: nm_remove_ansible_group_1 + +- name: Remove fabric span destination group 1 again + cisco.aci.aci_fabric_span_dst_group: + <<: *remove_ansible_group_1 + register: nm_remove_ansible_group_1_again + +- name: Verify remove fabric span destination group 1 + ansible.builtin.assert: + that: + - cm_remove_ansible_group_1 is changed + - cm_remove_ansible_group_1.current | length == 1 + - cm_remove_ansible_group_1.previous | length == 1 + - cm_remove_ansible_group_1.proposed == {} + - nm_remove_ansible_group_1 is changed + - nm_remove_ansible_group_1.current == [] + - nm_remove_ansible_group_1.previous | length == 1 + - nm_remove_ansible_group_1_again is not changed + - nm_remove_ansible_group_1_again.current == [] + - nm_remove_ansible_group_1_again.previous == [] + +# CLEAN TEST ENVIRONMENT AFTER TESTS + +- name: Query all fabric span destination groups ( clean after ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span destination groups ( clean after ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group/tasks/main.yml new file mode 100644 index 000000000..c3e4eb55c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group/tasks/main.yml @@ -0,0 +1,245 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Akini Ross (@akinross) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +# CLEAN TEST ENVIRONMENT BEFORE TESTS + +- name: Query all fabric span source groups ( clean before ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span source groups ( clean before ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + source_group: "{{ item.spanSrcGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Query all fabric span destination groups ( clean before ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span destination groups ( clean before ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Add fabric span destination group 1 ( clean before ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + destination_group: span_dest_1 + description: test span epg + destination_epg: + destination_ip: 10.0.0.1 + source_ip: 10.0.2.1 + tenant: ansible_test + ap: ansible_test + epg: ansible_test + state: present + +# TEST CREATE AND UPDATE SOURCE GROUPS + +- name: Add fabric span source group 1 ( checkmode ) + cisco.aci.aci_fabric_span_src_group: &span_src_1 + <<: *aci_info + source_group: span_src_1 + destination_group: span_dest_1 + state: present + check_mode: true + register: cm_span_src_1 + +- name: Add fabric span source group 1 + cisco.aci.aci_fabric_span_src_group: + <<: *span_src_1 + register: nm_span_src_1 + +- name: Add fabric span source group 1 again + cisco.aci.aci_fabric_span_src_group: + <<: *span_src_1 + register: nm_span_src_1_again + +- name: Verify add fabric span source group 1 + ansible.builtin.assert: + that: + - cm_span_src_1 is changed + - cm_span_src_1.previous == [] + - cm_span_src_1.current == [] + - cm_span_src_1.proposed.spanSrcGrp.attributes.name == "span_src_1" + - cm_span_src_1.proposed.spanSrcGrp.children.0.spanSpanLbl.attributes.name == "span_dest_1" + - nm_span_src_1 is changed + - nm_span_src_1.previous == [] + - nm_span_src_1.current.0.spanSrcGrp.attributes.name == "span_src_1" + - nm_span_src_1.current.0.spanSrcGrp.attributes.descr == "" + - nm_span_src_1.current.0.spanSrcGrp.attributes.adminSt == "enabled" + - nm_span_src_1.current.0.spanSrcGrp.children.0.spanSpanLbl.attributes.name == "span_dest_1" + - nm_span_src_1_again is not changed + - nm_span_src_1_again.previous.0.spanSrcGrp.attributes.name == "span_src_1" + - nm_span_src_1_again.previous.0.spanSrcGrp.attributes.descr == "" + - nm_span_src_1_again.previous.0.spanSrcGrp.attributes.adminSt == "enabled" + - nm_span_src_1_again.previous.0.spanSrcGrp.children.0.spanSpanLbl.attributes.name == "span_dest_1" + - nm_span_src_1_again.current.0.spanSrcGrp.attributes.name == "span_src_1" + - nm_span_src_1_again.current.0.spanSrcGrp.attributes.descr == "" + - nm_span_src_1_again.current.0.spanSrcGrp.attributes.adminSt == "enabled" + - nm_span_src_1_again.current.0.spanSrcGrp.children.0.spanSpanLbl.attributes.name == "span_dest_1" + +- name: Change fabric span source group 1 + cisco.aci.aci_fabric_span_src_group: &change_span_src_1 + <<: *span_src_1 + destination_group: span_dest_2 + description: "changed description" + admin_state: false + register: nm_changed_span_src_1 + +- name: Change fabric span source group 1 again + cisco.aci.aci_fabric_span_src_group: + <<: *change_span_src_1 + register: nm_changed_span_src_1_again + +- name: Verify changed fabric span source group 1 + ansible.builtin.assert: + that: + - nm_changed_span_src_1 is changed + - nm_changed_span_src_1.previous.0.spanSrcGrp.attributes.descr == "" + - nm_changed_span_src_1.previous.0.spanSrcGrp.attributes.adminSt == "enabled" + - nm_changed_span_src_1.previous.0.spanSrcGrp.children.0.spanSpanLbl.attributes.name == "span_dest_1" + - nm_changed_span_src_1.current.0.spanSrcGrp.attributes.descr == "changed description" + - nm_changed_span_src_1.current.0.spanSrcGrp.attributes.adminSt == "disabled" + - nm_changed_span_src_1.current.0.spanSrcGrp.children.0.spanSpanLbl.attributes.name == "span_dest_2" + - nm_changed_span_src_1_again is not changed + - nm_changed_span_src_1_again.previous.0.spanSrcGrp.attributes.descr == "changed description" + - nm_changed_span_src_1_again.previous.0.spanSrcGrp.attributes.adminSt == "disabled" + - nm_changed_span_src_1_again.previous.0.spanSrcGrp.children.0.spanSpanLbl.attributes.name == "span_dest_2" + - nm_changed_span_src_1_again.current.0.spanSrcGrp.attributes.descr == "changed description" + - nm_changed_span_src_1_again.current.0.spanSrcGrp.attributes.adminSt == "disabled" + - nm_changed_span_src_1_again.current.0.spanSrcGrp.children.0.spanSpanLbl.attributes.name == "span_dest_2" + +- name: Add fabric span source group 2 with admin_state to false + cisco.aci.aci_fabric_span_src_group: + <<: *change_span_src_1 + source_group: span_src_2 + destination_group: span_dest_2 + admin_state: false + register: nm_changed_span_src_2_admin_state_false + +- name: Add fabric span source group 3 with admin_state to true + cisco.aci.aci_fabric_span_src_group: + <<: *change_span_src_1 + source_group: span_src_3 + destination_group: span_dest_3 + admin_state: true + register: nm_changed_span_src_3_admin_state_true + +- name: Verify admin_state sets for fabric span source group 2 and 3 + ansible.builtin.assert: + that: + - nm_changed_span_src_2_admin_state_false is changed + - nm_changed_span_src_2_admin_state_false.current.0.spanSrcGrp.attributes.adminSt == "disabled" + - nm_changed_span_src_3_admin_state_true is changed + - nm_changed_span_src_3_admin_state_true.current.0.spanSrcGrp.attributes.adminSt == "enabled" + +# TEST QUERY SOURCE GROUPS + +- name: Query fabric span source group span_src_1 + cisco.aci.aci_fabric_span_src_group: + <<: *change_span_src_1 + state: query + register: query_one + +- name: Query all span source groups + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + state: query + register: query_all + +- name: Verify querying fabric span destination groups + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current | length == 1 + - query_one.current.0.spanSrcGrp.attributes.name == "span_src_1" + - query_all is not changed + - query_all.current | length >= 3 + +# TEST REMOVAL SOURCE GROUPS + +- name: Remove fabric span source group ( checkmode ) + cisco.aci.aci_fabric_span_src_group: &remove_span_src_1 + <<: *change_span_src_1 + state: absent + check_mode: true + register: cm_remove_span_src_1 + +- name: Remove fabric span source group 1 + cisco.aci.aci_fabric_span_src_group: + <<: *remove_span_src_1 + register: nm_remove_span_src_1 + +- name: Remove fabric span source group 1 again + cisco.aci.aci_fabric_span_src_group: + <<: *remove_span_src_1 + register: nm_remove_span_src_1_again + +- name: Verify remove fabric span source group 1 + ansible.builtin.assert: + that: + - cm_remove_span_src_1 is changed + - cm_remove_span_src_1.current | length == 1 + - cm_remove_span_src_1.previous | length == 1 + - cm_remove_span_src_1.proposed == {} + - nm_remove_span_src_1 is changed + - nm_remove_span_src_1.current == [] + - nm_remove_span_src_1.previous | length == 1 + - nm_remove_span_src_1_again is not changed + - nm_remove_span_src_1_again.current == [] + - nm_remove_span_src_1_again.previous == [] + +# CLEAN TEST ENVIRONMENT AFTER TESTS + +- name: Query all fabric span source groups ( clean after ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span source groups ( clean after ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + source_group: "{{ item.spanSrcGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Query all fabric span destination groups ( clean after ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span destination groups ( clean after ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src/tasks/main.yml new file mode 100644 index 000000000..6767e3e89 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src/tasks/main.yml @@ -0,0 +1,396 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Akini Ross (@akinross) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +# CLEAN TEST ENVIRONMENT BEFORE TESTS + +- name: Query all fabric span source groups ( clean before ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span source groups ( clean before ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + source_group: "{{ item.spanSrcGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Query all fabric span destination groups ( clean before ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span destination groups ( clean before ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Add fabric span destination group type epg ( clean before ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + destination_group: span_dest_1 + description: test span epg + destination_epg: + destination_ip: 10.0.0.1 + source_ip: 10.0.2.1 + tenant: ansible_test + ap: ansible_test + epg: ansible_test + state: present + +- name: Add fabric span source groups ( clean before ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + source_group: "{{ item }}" + destination_group: span_dest_1 + state: present + loop: + - span_src_group_1 + - span_src_group_2 + +# TEST CREATE AND UPDATE SOURCE + +- name: Add fabric span source 1 ( checkmode ) + cisco.aci.aci_fabric_span_src_group_src: &fabric_span_src_1 + <<: *aci_info + source_group: span_src_group_1 + source: fabric_span_src_1 + state: present + check_mode: true + register: cm_fabric_span_src_1 + +- name: Add fabric span source 1 + cisco.aci.aci_fabric_span_src_group_src: + <<: *fabric_span_src_1 + register: nm_fabric_span_src_1 + +- name: Add fabric span source 1 again + cisco.aci.aci_fabric_span_src_group_src: + <<: *fabric_span_src_1 + register: nm_fabric_span_src_1_again + +- name: Verify add fabric span source 1 + ansible.builtin.assert: + that: + - cm_fabric_span_src_1 is changed + - cm_fabric_span_src_1.previous == [] + - cm_fabric_span_src_1.current == [] + - cm_fabric_span_src_1.proposed.spanSrc.attributes.name == "fabric_span_src_1" + - cm_fabric_span_src_1.proposed.spanSrc.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-fabric_span_src_1" + - nm_fabric_span_src_1 is changed + - nm_fabric_span_src_1.previous == [] + - nm_fabric_span_src_1.current.0.spanSrc.attributes.name == "fabric_span_src_1" + - nm_fabric_span_src_1.current.0.spanSrc.attributes.descr == "" + - nm_fabric_span_src_1.current.0.spanSrc.attributes.dir == "both" + - nm_fabric_span_src_1.current.0.spanSrc.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-fabric_span_src_1" + - nm_fabric_span_src_1_again is not changed + - nm_fabric_span_src_1_again.previous.0.spanSrc.attributes.name == "fabric_span_src_1" + - nm_fabric_span_src_1_again.previous.0.spanSrc.attributes.descr == "" + - nm_fabric_span_src_1_again.previous.0.spanSrc.attributes.dir == "both" + - nm_fabric_span_src_1_again.previous.0.spanSrc.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-fabric_span_src_1" + - nm_fabric_span_src_1_again.current.0.spanSrc.attributes.name == "fabric_span_src_1" + - nm_fabric_span_src_1_again.current.0.spanSrc.attributes.descr == "" + - nm_fabric_span_src_1_again.current.0.spanSrc.attributes.dir == "both" + - nm_fabric_span_src_1_again.current.0.spanSrc.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-fabric_span_src_1" + +- name: Change fabric span source 1 + cisco.aci.aci_fabric_span_src_group_src: &change_fabric_span_src_1 + <<: *fabric_span_src_1 + source: fabric_span_src_1 + description: "changed description" + direction: both + register: nm_changed_fabric_span_src_1 + +- name: Change fabric span source 1 direction incoming + cisco.aci.aci_fabric_span_src_group_src: + <<: *change_fabric_span_src_1 + direction: incoming + register: nm_changed_fabric_span_src_1_incoming + +- name: Change fabric span source 1 direction outgoing + cisco.aci.aci_fabric_span_src_group_src: &change_fabric_span_src_1_again + <<: *change_fabric_span_src_1 + direction: outgoing + register: nm_changed_fabric_span_src_1_outgoing + +- name: Change fabric span source 1 again + cisco.aci.aci_fabric_span_src_group_src: + <<: *change_fabric_span_src_1_again + register: nm_changed_fabric_span_src_1_again + +- name: Verify changed fabric span source 1 + ansible.builtin.assert: + that: + - nm_changed_fabric_span_src_1 is changed + - nm_changed_fabric_span_src_1.previous.0.spanSrc.attributes.name == "fabric_span_src_1" + - nm_changed_fabric_span_src_1.previous.0.spanSrc.attributes.descr == "" + - nm_changed_fabric_span_src_1.previous.0.spanSrc.attributes.dir == "both" + - nm_changed_fabric_span_src_1.previous.0.spanSrc.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-fabric_span_src_1" + - nm_changed_fabric_span_src_1.current.0.spanSrc.attributes.name == "fabric_span_src_1" + - nm_changed_fabric_span_src_1.current.0.spanSrc.attributes.descr == "changed description" + - nm_changed_fabric_span_src_1.current.0.spanSrc.attributes.dir == "both" + - nm_changed_fabric_span_src_1.current.0.spanSrc.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-fabric_span_src_1" + - nm_changed_fabric_span_src_1_incoming.current.0.spanSrc.attributes.dir == "in" + - nm_changed_fabric_span_src_1_outgoing.current.0.spanSrc.attributes.dir == "out" + - nm_changed_fabric_span_src_1_again is not changed + +- name: Add fabric span source 2 of bd type + cisco.aci.aci_fabric_span_src_group_src: &span_src_bd + <<: *aci_info + source_group: span_src_group_1 + bd: + tenant: tenant1 + bd: bd1 + source: fabric_span_src_2 + state: present + register: nm_fabric_span_src_2 + +- name: Change fabric span source 2 of bd type + cisco.aci.aci_fabric_span_src_group_src: + <<: *span_src_bd + bd: + tenant: tenant1 + bd: bd2 + register: nm_changed_fabric_span_src_2 + +- name: Change fabric span source 2 of bd type to none type + cisco.aci.aci_fabric_span_src_group_src: + <<: *aci_info + source_group: span_src_group_1 + source: fabric_span_src_2 + state: present + register: nm_changed_fabric_span_src_2_type_none + +- name: Add fabric span source 3 of vrf type + cisco.aci.aci_fabric_span_src_group_src: &span_src_vrf + <<: *aci_info + source_group: span_src_group_1 + vrf: + tenant: tenant1 + vrf: vrf1 + source: fabric_span_src_3 + state: present + register: nm_fabric_span_src_3 + +- name: Change fabric span source 3 of vrf type + cisco.aci.aci_fabric_span_src_group_src: + <<: *span_src_vrf + vrf: + tenant: tenant1 + vrf: vrf2 + register: nm_changed_fabric_span_src_3 + +- name: Change fabric span source 3 of vrf type + cisco.aci.aci_fabric_span_src_group_src: + <<: *aci_info + source_group: span_src_group_1 + source: fabric_span_src_3 + state: present + register: nm_changed_fabric_span_src_3_type_none + +- name: Verify changed fabric span source types group 2 and 3 + ansible.builtin.assert: + that: + - nm_fabric_span_src_2 is changed + - nm_fabric_span_src_2.current.0.spanSrc.attributes.name == "fabric_span_src_2" + - nm_fabric_span_src_2.current.0.spanSrc.children.0.spanRsSrcToBD.attributes.tDn == "uni/tn-tenant1/BD-bd1" + - nm_changed_fabric_span_src_2 is changed + - nm_changed_fabric_span_src_2.current.0.spanSrc.attributes.name == "fabric_span_src_2" + - nm_changed_fabric_span_src_2.previous.0.spanSrc.children.0.spanRsSrcToBD.attributes.tDn == "uni/tn-tenant1/BD-bd1" + - nm_changed_fabric_span_src_2.current.0.spanSrc.children.0.spanRsSrcToBD.attributes.tDn == "uni/tn-tenant1/BD-bd2" + - nm_changed_fabric_span_src_2_type_none is changed + - nm_changed_fabric_span_src_2_type_none.previous.0.spanSrc.children.0.spanRsSrcToBD.attributes.tDn == "uni/tn-tenant1/BD-bd2" + - '"children" not in nm_changed_fabric_span_src_2_type_none.current.0.spanSrc' + - nm_fabric_span_src_3 is changed + - nm_fabric_span_src_3.current.0.spanSrc.attributes.name == "fabric_span_src_3" + - nm_fabric_span_src_3.current.0.spanSrc.children.0.spanRsSrcToCtx.attributes.tDn == "uni/tn-tenant1/ctx-vrf1" + - nm_changed_fabric_span_src_3 is changed + - nm_changed_fabric_span_src_3.current.0.spanSrc.attributes.name == "fabric_span_src_3" + - nm_changed_fabric_span_src_3.previous.0.spanSrc.children.0.spanRsSrcToCtx.attributes.tDn == "uni/tn-tenant1/ctx-vrf1" + - nm_changed_fabric_span_src_3.current.0.spanSrc.children.0.spanRsSrcToCtx.attributes.tDn == "uni/tn-tenant1/ctx-vrf2" + - nm_changed_fabric_span_src_3_type_none is changed + - nm_changed_fabric_span_src_3_type_none.previous.0.spanSrc.children.0.spanRsSrcToCtx.attributes.tDn == "uni/tn-tenant1/ctx-vrf2" + - '"children" not in nm_changed_fabric_span_src_3_type_none.current.0.spanSrc' + +- name: Change fabric span source 4 drop_packets true + cisco.aci.aci_fabric_span_src_group_src: + <<: *aci_info + source_group: span_src_group_2 + source: span_src_4 + drop_packets: true + state: present + register: nm_changed_span_src_4_type_drop_packets_true + +- name: Change fabric span source 4 drop_packets false + cisco.aci.aci_fabric_span_src_group_src: + <<: *aci_info + source_group: span_src_group_2 + source: span_src_4 + drop_packets: false + state: present + register: nm_changed_span_src_4_type_drop_packets_false + +- name: Verify changed fabric span source group 1 drop packets + ansible.builtin.assert: + that: + - nm_changed_span_src_4_type_drop_packets_true is changed + - nm_changed_span_src_4_type_drop_packets_true.current.0.spanSrc.attributes.name == "span_src_4" + - nm_changed_span_src_4_type_drop_packets_true.current.0.spanSrc.attributes.spanOnDrop == "yes" + - nm_changed_span_src_4_type_drop_packets_false is changed + - nm_changed_span_src_4_type_drop_packets_false.current.0.spanSrc.attributes.name == "span_src_4" + - nm_changed_span_src_4_type_drop_packets_false.current.0.spanSrc.attributes.spanOnDrop == "no" + +# TEST QUERY SOURCE + +- name: Query fabric span source fabric_span_src_1 + cisco.aci.aci_fabric_span_src_group_src: + <<: *aci_info + source: fabric_span_src_1 + state: query + register: query_one + +- name: Query fabric all span sources + cisco.aci.aci_fabric_span_src_group_src: + <<: *aci_info + state: query + register: query_all + +- name: Verify querying fabric span sources + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current | length == 1 + - query_one.current.0.spanSrc.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-fabric_span_src_1" + - query_all is not changed + - query_all.current | length >= 3 + +# TEST ERRORS SOURCE + +- name: Add fabric span source 4 with bd and vrf ( mutually exclusive error ) + cisco.aci.aci_fabric_span_src_group_src: + <<: *aci_info + source_group: span_src_group_4 + bd: + tenant: tenant1 + bd: bd1 + vrf: + tenant: tenant1 + vrf: vrf1 + source: span_src_4 + state: present + ignore_errors: true + register: err_mutually_exclusive_bd_vrf + +- name: Add fabric span source 4 with bd and drop_packets( drop_packets true error ) + cisco.aci.aci_fabric_span_src_group_src: + <<: *aci_info + source_group: span_src_group_4 + source: span_src_4 + bd: + tenant: tenant1 + bd: bd1 + drop_packets: true + ignore_errors: true + register: err_bd_drop_packets + +- name: Add fabric span source 4 with vrf and drop_packets ( drop_packets true error ) + cisco.aci.aci_fabric_span_src_group_src: + <<: *aci_info + source_group: span_src_group_4 + source: span_src_4 + vrf: + tenant: tenant1 + vrf: vrf1 + drop_packets: true + ignore_errors: true + register: err_vrf_drop_packets + +- name: Verify errors on incorrect input + ansible.builtin.assert: + that: + - err_mutually_exclusive_bd_vrf.msg == "parameters are mutually exclusive{{':'}} vrf|bd" + - err_bd_drop_packets.msg == "It is not allowed to configure 'drop_packets{{':'}} true' when 'bd' is configured on the source." + - err_vrf_drop_packets.msg == "It is not allowed to configure 'drop_packets{{':'}} true' when 'vrf' is configured on the source." + +# TEST REMOVAL SOURCE + +- name: Remove fabric span source 1 ( checkmode ) + cisco.aci.aci_fabric_span_src_group_src: &remove_fabric_span_src_1 + <<: *change_fabric_span_src_1 + state: absent + check_mode: true + register: cm_remove_fabric_span_src_1 + +- name: Remove fabric span source 1 + cisco.aci.aci_fabric_span_src_group_src: + <<: *remove_fabric_span_src_1 + register: nm_remove_fabric_span_src_1 + +- name: Remove fabric span source 1 again + cisco.aci.aci_fabric_span_src_group_src: + <<: *remove_fabric_span_src_1 + register: nm_remove_fabric_span_src_1_again + +- name: Verify remove fabric span source 1 + ansible.builtin.assert: + that: + - cm_remove_fabric_span_src_1 is changed + - cm_remove_fabric_span_src_1.current | length == 1 + - cm_remove_fabric_span_src_1.previous | length == 1 + - cm_remove_fabric_span_src_1.proposed == {} + - nm_remove_fabric_span_src_1 is changed + - nm_remove_fabric_span_src_1.current == [] + - nm_remove_fabric_span_src_1.previous | length == 1 + - nm_remove_fabric_span_src_1_again is not changed + - nm_remove_fabric_span_src_1_again.current == [] + - nm_remove_fabric_span_src_1_again.previous == [] + +# CLEAN TEST ENVIRONMENT AFTER TESTS + +- name: Query all fabric span source groups ( clean after ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span source groups ( clean after ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + source_group: "{{ item.spanSrcGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Query all fabric span destination groups ( clean after ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span destination groups ( clean after ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src_node/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src_node/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src_node/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src_node/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src_node/tasks/main.yml new file mode 100644 index 000000000..0e5ea30b2 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src_node/tasks/main.yml @@ -0,0 +1,238 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Akini Ross (@akinross) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +# CLEAN TEST ENVIRONMENT BEFORE TESTS + +- name: Query all fabric span source groups ( clean before ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span source groups ( clean before ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + source_group: "{{ item.spanSrcGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Query all fabric span destination groups ( clean before ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span destination groups ( clean before ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Add fabric span destination group type epg ( clean before ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + destination_group: span_dest_1 + description: test span epg + destination_epg: + destination_ip: 10.0.0.1 + source_ip: 10.0.2.1 + tenant: ansible_test + ap: ansible_test + epg: ansible_test + state: present + +- name: Add fabric span source group 1 ( clean before ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + source_group: span_src_group_1 + destination_group: span_dest_1 + state: present + +- name: Add fabric span source group source 1 ( clean before ) + cisco.aci.aci_fabric_span_src_group_src: + <<: *aci_info + source_group: span_src_group_1 + source: span_src_1 + drop_packets: true + state: present + +- name: Add fabric span source group source 2 for error handling ( clean before ) + cisco.aci.aci_fabric_span_src_group_src: + <<: *aci_info + source_group: span_src_group_1 + source: span_src_2 + drop_packets: false + state: present + + +# TEST CREATE SOURCE NODES + +- name: Add fabric span source node 1 ( checkmode ) + cisco.aci.aci_fabric_span_src_group_src_node: &span_src_node_1 + <<: *aci_info + source_group: span_src_group_1 + source: span_src_1 + pod: 1 + node: 101 + state: present + check_mode: true + register: cm_span_src_node_1 + +- name: Add fabric span source node 1 + cisco.aci.aci_fabric_span_src_group_src_node: + <<: *span_src_node_1 + register: nm_span_src_node_1 + +- name: Add fabric span source node 1 again + cisco.aci.aci_fabric_span_src_group_src_node: + <<: *span_src_node_1 + register: nm_span_src_node_1_again + +- name: Verify add fabric span source node 1 + ansible.builtin.assert: + that: + - cm_span_src_node_1 is changed + - cm_span_src_node_1.previous == [] + - cm_span_src_node_1.current == [] + - cm_span_src_node_1.proposed.spanRsSrcToNode.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-span_src_1/rssrcToNode-[topology/pod-1/node-101]" + - cm_span_src_node_1.proposed.spanRsSrcToNode.attributes.tDn == "topology/pod-1/node-101" + - nm_span_src_node_1 is changed + - nm_span_src_node_1.current.0.spanRsSrcToNode.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-span_src_1/rssrcToNode-[topology/pod-1/node-101]" + - nm_span_src_node_1.current.0.spanRsSrcToNode.attributes.tDn == "topology/pod-1/node-101" + - nm_span_src_node_1.previous == [] + - nm_span_src_node_1_again is not changed + - nm_span_src_node_1_again.previous.0.spanRsSrcToNode.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-span_src_1/rssrcToNode-[topology/pod-1/node-101]" + - nm_span_src_node_1_again.previous.0.spanRsSrcToNode.attributes.tDn == "topology/pod-1/node-101" + - nm_span_src_node_1_again.current.0.spanRsSrcToNode.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-span_src_1/rssrcToNode-[topology/pod-1/node-101]" + - nm_span_src_node_1_again.current.0.spanRsSrcToNode.attributes.tDn == "topology/pod-1/node-101" + +- name: Add fabric span source node 2 + cisco.aci.aci_fabric_span_src_group_src_node: + <<: *aci_info + source_group: span_src_group_1 + source: span_src_1 + pod: 1 + node: 102 + state: present + +# TEST QUERY SOURCE NODES + +- name: Query fabric span source node 1 + cisco.aci.aci_fabric_span_src_group_src_node: + <<: *span_src_node_1 + state: query + register: query_one + +- name: Query all fabric span source nodes + cisco.aci.aci_fabric_span_src_group_src_node: + <<: *aci_info + state: query + register: query_all + +- name: Verify querying fabric span sources + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current | length == 1 + - query_one.current.0.spanRsSrcToNode.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-span_src_1/rssrcToNode-[topology/pod-1/node-101]" + - query_one.current.0.spanRsSrcToNode.attributes.tDn == "topology/pod-1/node-101" + - query_all is not changed + - query_all.current | length >= 2 + +# TEST REMOVAL SOURCE NODES + +- name: Remove fabric span source node 1 ( checkmode ) + cisco.aci.aci_fabric_span_src_group_src_node: &remove_span_src_node_1 + <<: *span_src_node_1 + state: absent + check_mode: true + register: cm_remove_span_src_node_1 + +- name: Remove fabric span source node 1 + cisco.aci.aci_fabric_span_src_group_src_node: + <<: *remove_span_src_node_1 + register: nm_remove_span_src_node_1 + +- name: Remove fabric span source node 1 again + cisco.aci.aci_fabric_span_src_group_src_node: + <<: *remove_span_src_node_1 + register: nm_remove_span_src_node_1_again + +- name: Verify remove fabric span source node 1 + ansible.builtin.assert: + that: + - cm_remove_span_src_node_1 is changed + - cm_remove_span_src_node_1.current | length == 1 + - cm_remove_span_src_node_1.previous | length == 1 + - cm_remove_span_src_node_1.proposed == {} + - nm_remove_span_src_node_1 is changed + - nm_remove_span_src_node_1.current == [] + - nm_remove_span_src_node_1.previous | length == 1 + - nm_remove_span_src_node_1_again is not changed + - nm_remove_span_src_node_1_again.current == [] + - nm_remove_span_src_node_1_again.previous == [] + +# TEST ERROR SOURCE NODES + +- name: Add fabric span source node 2 (error) + cisco.aci.aci_fabric_span_src_group_src_node: + <<: *aci_info + source_group: span_src_group_1 + source: span_src_2 + pod: 1 + node: 101 + state: present + ignore_errors: true + register: err_drop_packets_on_src + +- name: Verify errors span source node 2 + ansible.builtin.assert: + that: + - err_drop_packets_on_src.msg == "APIC Error 105{{':'}} Node span is supported only with Span on drop configuration" + +# CLEAN TEST ENVIRONMENT AFTER TESTS + +- name: Query all fabric span source groups ( clean after ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span source groups ( clean after ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + source_group: "{{ item.spanSrcGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Query all fabric span destination groups ( clean after ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span destination groups ( clean after ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src_path/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src_path/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src_path/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src_path/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src_path/tasks/main.yml new file mode 100644 index 000000000..e0c772843 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_span_src_group_src_path/tasks/main.yml @@ -0,0 +1,218 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Akini Ross (@akinross) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("debug") }}' + +# CLEAN TEST ENVIRONMENT BEFORE TESTS + +- name: Query all fabric span source groups ( clean before ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span source groups ( clean before ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + source_group: "{{ item.spanSrcGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Query all fabric span destination groups ( clean before ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span destination groups ( clean before ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Add fabric span destination group type epg ( clean before ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + destination_group: span_dest_1 + description: test span epg + destination_epg: + destination_ip: 10.0.0.1 + source_ip: 10.0.2.1 + tenant: ansible_test + ap: ansible_test + epg: ansible_test + state: present + +- name: Add fabric span source group 1 ( clean before ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + source_group: span_src_group_1 + destination_group: span_dest_1 + state: present + +- name: Add fabric span source group source 1 ( clean before ) + cisco.aci.aci_fabric_span_src_group_src: + <<: *aci_info + source_group: span_src_group_1 + source: span_src_1 + state: present + +# TEST CREATE SOURCE PATHS + +- name: Add fabric span source path 1 ( checkmode ) + cisco.aci.aci_fabric_span_src_group_src_path: &span_src_path_1 + <<: *aci_info + source_group: span_src_group_1 + source: span_src_1 + pod: 1 + node: 101 + path_ep: eth1/1 + state: present + check_mode: true + register: cm_span_src_path_1 + +- name: Add fabric span source path 1 + cisco.aci.aci_fabric_span_src_group_src_path: + <<: *span_src_path_1 + register: nm_span_src_path_1 + +- name: Add fabric span source path 1 again + cisco.aci.aci_fabric_span_src_group_src_path: + <<: *span_src_path_1 + register: nm_span_src_path_1_again + +- name: Verify add fabric span source path 1 + ansible.builtin.assert: + that: + - cm_span_src_path_1 is changed + - cm_span_src_path_1.previous == [] + - cm_span_src_path_1.current == [] + - cm_span_src_path_1.proposed.spanRsSrcToPathEp.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - cm_span_src_path_1.proposed.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - nm_span_src_path_1 is changed + - nm_span_src_path_1.current.0.spanRsSrcToPathEp.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - nm_span_src_path_1.current.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - nm_span_src_path_1.previous == [] + - nm_span_src_path_1_again is not changed + - nm_span_src_path_1_again.previous.0.spanRsSrcToPathEp.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - nm_span_src_path_1_again.previous.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - nm_span_src_path_1_again.current.0.spanRsSrcToPathEp.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - nm_span_src_path_1_again.current.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + +- name: Add fabric span source path 2 + cisco.aci.aci_fabric_span_src_group_src_path: + <<: *aci_info + source_group: span_src_group_1 + source: span_src_1 + pod: 1 + node: 102 + path_ep: eth1/2 + state: present + +# TEST QUERY SOURCE PATHS + +- name: Query fabric span source path 1 + cisco.aci.aci_fabric_span_src_group_src_path: + <<: *span_src_path_1 + state: query + register: query_one + +- name: Query all fabric span source paths + cisco.aci.aci_fabric_span_src_group_src_path: + <<: *aci_info + state: query + register: query_all + +- name: Verify querying fabric span sources + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current | length == 1 + - query_one.current.0.spanRsSrcToPathEp.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - query_one.current.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - query_all is not changed + - query_all.current | length >= 2 + +# TEST REMOVAL SOURCE PATHS + +- name: Remove fabric span source path 1 ( checkmode ) + cisco.aci.aci_fabric_span_src_group_src_path: &remove_span_src_path_1 + <<: *span_src_path_1 + state: absent + check_mode: true + register: cm_remove_span_src_path_1 + +- name: Remove fabric span source path 1 + cisco.aci.aci_fabric_span_src_group_src_path: + <<: *remove_span_src_path_1 + register: nm_remove_span_src_path_1 + +- name: Remove fabric span source path 1 again + cisco.aci.aci_fabric_span_src_group_src_path: + <<: *remove_span_src_path_1 + register: nm_remove_span_src_path_1_again + +- name: Verify remove fabric span source path 1 + ansible.builtin.assert: + that: + - cm_remove_span_src_path_1 is changed + - cm_remove_span_src_path_1.current | length == 1 + - cm_remove_span_src_path_1.previous | length == 1 + - cm_remove_span_src_path_1.previous.0.spanRsSrcToPathEp.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - cm_remove_span_src_path_1.previous.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - cm_remove_span_src_path_1.current.0.spanRsSrcToPathEp.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - cm_remove_span_src_path_1.current.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - cm_remove_span_src_path_1.proposed == {} + - nm_remove_span_src_path_1 is changed + - nm_remove_span_src_path_1.current == [] + - nm_remove_span_src_path_1.previous | length == 1 + - nm_remove_span_src_path_1.previous.0.spanRsSrcToPathEp.attributes.dn == "uni/fabric/srcgrp-span_src_group_1/src-span_src_1/rssrcToPathEp-[topology/pod-1/paths-101/pathep-[eth1/1]]" + - nm_remove_span_src_path_1.previous.0.spanRsSrcToPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - nm_remove_span_src_path_1_again is not changed + - nm_remove_span_src_path_1_again.current == [] + - nm_remove_span_src_path_1_again.previous == [] + +# CLEAN TEST ENVIRONMENT AFTER TESTS + +- name: Query all fabric span source groups ( clean after ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span source groups ( clean after ) + cisco.aci.aci_fabric_span_src_group: + <<: *aci_info + source_group: "{{ item.spanSrcGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + +- name: Query all fabric span destination groups ( clean after ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean fabric span destination groups ( clean after ) + cisco.aci.aci_fabric_span_dst_group: + <<: *aci_info + destination_group: "{{ item.spanDestGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_wide_settings/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_wide_settings/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_wide_settings/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_wide_settings/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_wide_settings/tasks/main.yml new file mode 100644 index 000000000..526c8bee0 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_wide_settings/tasks/main.yml @@ -0,0 +1,229 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Tim Cragg (@timcragg) +# Copyright: (c) 2023, Akini Ross (@akinross) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will skip execution for cloud sites + block: + + # STORE EXISTING FABRIC WIDE SETTINGS + - name: Query system information + cisco.aci.aci_system: + <<: *aci_info + id: 1 + state: query + register: version + + - name: Capture existing Fabric Wide Settings + cisco.aci.aci_fabric_wide_settings: + <<: *aci_info + state: query + register: previous_settings + + - name: Clear existing settings + cisco.aci.aci_fabric_wide_settings: + <<: *aci_info + disable_remote_ep_learning: false + enforce_subnet_check: false + enforce_epg_vlan_validation: false + spine_opflex_client_auth: false + spine_ssl_opflex: false + + # SET FABRIC WIDE SETTINGS + - name: Execute tests for ACI v5+ + when: version.current.0.topSystem.attributes.version is version('5', '>=') + block: + + - name: Clear existing settings for ACI v5+ + cisco.aci.aci_fabric_wide_settings: + <<: *aci_info + leaf_opflex_client_auth: false + leaf_ssl_opflex: false + restrict_infra_vlan_traffic: false + opflex_ssl_versions: [ tls_v1.2 ] + + - name: Update Fabric Wide Settings for ACI v5+ (check_mode) + cisco.aci.aci_fabric_wide_settings: &aci_fab_settings_5 + <<: *aci_info + disable_remote_ep_learning: true + enforce_subnet_check: true + enforce_epg_vlan_validation: true + spine_opflex_client_auth: true + leaf_opflex_client_auth: true + spine_ssl_opflex: true + leaf_ssl_opflex: true + restrict_infra_vlan_traffic: true + opflex_ssl_versions: [ tls_v1.1, tls_v1.2 ] + check_mode: true + register: cm_update_fab_settings + + - name: Update Fabric Wide Settings for ACI v5+ + cisco.aci.aci_fabric_wide_settings: + <<: *aci_fab_settings_5 + register: nm_update_fab_settings + + - name: Update Fabric Wide Settings Again for ACI v5+ + cisco.aci.aci_fabric_wide_settings: + <<: *aci_fab_settings_5 + register: nm_update_fab_settings_again + + - name: Verify Fabric Wide Settings for ACI v5+ + ansible.builtin.assert: + that: + - cm_update_fab_settings is changed + - nm_update_fab_settings is changed + - nm_update_fab_settings.current.0.infraSetPol.attributes.unicastXrEpLearnDisable == "yes" + - nm_update_fab_settings.current.0.infraSetPol.attributes.enforceSubnetCheck == "yes" + - nm_update_fab_settings.current.0.infraSetPol.attributes.validateOverlappingVlans == "yes" + - nm_update_fab_settings.current.0.infraSetPol.attributes.domainValidation == previous_settings.current.0.infraSetPol.attributes.domainValidation + - nm_update_fab_settings.current.0.infraSetPol.attributes.opflexpAuthenticateClients == "yes" + - nm_update_fab_settings.current.0.infraSetPol.attributes.opflexpUseSsl == "yes" + - nm_update_fab_settings.current.0.infraSetPol.attributes.reallocateGipo == previous_settings.current.0.infraSetPol.attributes.reallocateGipo + - nm_update_fab_settings.current.0.infraSetPol.attributes.leafOpflexpAuthenticateClients == "yes" + - nm_update_fab_settings.current.0.infraSetPol.attributes.leafOpflexpUseSsl == "yes" + - nm_update_fab_settings.current.0.infraSetPol.attributes.restrictInfraVLANTraffic == "yes" + - nm_update_fab_settings.current.0.infraSetPol.attributes.opflexpSslProtocols == "TLSv1.1,TLSv1.2" + - nm_update_fab_settings.previous.0.infraSetPol.attributes.unicastXrEpLearnDisable == "no" + - nm_update_fab_settings.previous.0.infraSetPol.attributes.enforceSubnetCheck == "no" + - nm_update_fab_settings.previous.0.infraSetPol.attributes.validateOverlappingVlans == "no" + - nm_update_fab_settings.previous.0.infraSetPol.attributes.domainValidation == previous_settings.current.0.infraSetPol.attributes.domainValidation + - nm_update_fab_settings.previous.0.infraSetPol.attributes.opflexpAuthenticateClients == "no" + - nm_update_fab_settings.previous.0.infraSetPol.attributes.opflexpUseSsl == "no" + - nm_update_fab_settings.previous.0.infraSetPol.attributes.reallocateGipo == previous_settings.current.0.infraSetPol.attributes.reallocateGipo + - nm_update_fab_settings.previous.0.infraSetPol.attributes.leafOpflexpAuthenticateClients == "no" + - nm_update_fab_settings.previous.0.infraSetPol.attributes.leafOpflexpUseSsl == "no" + - nm_update_fab_settings.previous.0.infraSetPol.attributes.restrictInfraVLANTraffic == "no" + - nm_update_fab_settings.previous.0.infraSetPol.attributes.opflexpSslProtocols == "TLSv1.2" + - nm_update_fab_settings_again is not changed + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.unicastXrEpLearnDisable == "yes" + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.enforceSubnetCheck == "yes" + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.validateOverlappingVlans == "yes" + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.domainValidation == previous_settings.current.0.infraSetPol.attributes.domainValidation + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.opflexpAuthenticateClients == "yes" + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.opflexpUseSsl == "yes" + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.reallocateGipo == previous_settings.current.0.infraSetPol.attributes.reallocateGipo + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.leafOpflexpAuthenticateClients == "yes" + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.leafOpflexpUseSsl == "yes" + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.restrictInfraVLANTraffic == "yes" + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.opflexpSslProtocols == "TLSv1.1,TLSv1.2" + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.unicastXrEpLearnDisable == "yes" + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.enforceSubnetCheck == "yes" + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.validateOverlappingVlans == "yes" + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.domainValidation == previous_settings.current.0.infraSetPol.attributes.domainValidation + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.opflexpAuthenticateClients == "yes" + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.opflexpUseSsl == "yes" + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.reallocateGipo == previous_settings.current.0.infraSetPol.attributes.reallocateGipo + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.leafOpflexpAuthenticateClients == "yes" + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.leafOpflexpUseSsl == "yes" + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.restrictInfraVLANTraffic == "yes" + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.opflexpSslProtocols == "TLSv1.1,TLSv1.2" + + - name: Execute tests for ACI + when: version.current.0.topSystem.attributes.version is version('5', '<') + block: + + - name: Update Fabric Wide Settings (check_mode) + cisco.aci.aci_fabric_wide_settings: &aci_fab_settings + <<: *aci_info + disable_remote_ep_learning: true + enforce_subnet_check: true + enforce_epg_vlan_validation: true + spine_opflex_client_auth: true + spine_ssl_opflex: true + check_mode: true + register: cm_update_fab_settings + + - name: Update Fabric Wide Settings + cisco.aci.aci_fabric_wide_settings: + <<: *aci_fab_settings + register: nm_update_fab_settings + + - name: Update Fabric Wide Settings Again + cisco.aci.aci_fabric_wide_settings: + <<: *aci_fab_settings + register: nm_update_fab_settings_again + + - name: Verify Fabric Wide Settings + ansible.builtin.assert: + that: + - cm_update_fab_settings is changed + - nm_update_fab_settings is changed + - nm_update_fab_settings.current.0.infraSetPol.attributes.unicastXrEpLearnDisable == "yes" + - nm_update_fab_settings.current.0.infraSetPol.attributes.enforceSubnetCheck == "yes" + - nm_update_fab_settings.current.0.infraSetPol.attributes.validateOverlappingVlans == "yes" + - nm_update_fab_settings.current.0.infraSetPol.attributes.domainValidation == previous_settings.current.0.infraSetPol.attributes.domainValidation + - nm_update_fab_settings.current.0.infraSetPol.attributes.opflexpAuthenticateClients == "yes" + - nm_update_fab_settings.current.0.infraSetPol.attributes.opflexpUseSsl == "yes" + - nm_update_fab_settings.current.0.infraSetPol.attributes.reallocateGipo == previous_settings.current.0.infraSetPol.attributes.reallocateGipo + - nm_update_fab_settings.previous.0.infraSetPol.attributes.unicastXrEpLearnDisable == "no" + - nm_update_fab_settings.previous.0.infraSetPol.attributes.enforceSubnetCheck == "no" + - nm_update_fab_settings.previous.0.infraSetPol.attributes.validateOverlappingVlans == "no" + - nm_update_fab_settings.previous.0.infraSetPol.attributes.domainValidation == previous_settings.current.0.infraSetPol.attributes.domainValidation + - nm_update_fab_settings.previous.0.infraSetPol.attributes.opflexpAuthenticateClients == "no" + - nm_update_fab_settings.previous.0.infraSetPol.attributes.opflexpUseSsl == "no" + - nm_update_fab_settings.previous.0.infraSetPol.attributes.reallocateGipo == previous_settings.current.0.infraSetPol.attributes.reallocateGipo + - nm_update_fab_settings_again is not changed + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.unicastXrEpLearnDisable == "yes" + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.enforceSubnetCheck == "yes" + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.validateOverlappingVlans == "yes" + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.domainValidation == previous_settings.current.0.infraSetPol.attributes.domainValidation + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.opflexpAuthenticateClients == "yes" + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.opflexpUseSsl == "yes" + - nm_update_fab_settings_again.current.0.infraSetPol.attributes.reallocateGipo == previous_settings.current.0.infraSetPol.attributes.reallocateGipo + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.unicastXrEpLearnDisable == "yes" + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.enforceSubnetCheck == "yes" + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.validateOverlappingVlans == "yes" + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.domainValidation == previous_settings.current.0.infraSetPol.attributes.domainValidation + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.opflexpAuthenticateClients == "yes" + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.opflexpUseSsl == "yes" + - nm_update_fab_settings_again.previous.0.infraSetPol.attributes.reallocateGipo == previous_settings.current.0.infraSetPol.attributes.reallocateGipo + + # QUERY FABRIC WIDE SETTINGS + - name: Query Fabric Wide Settings + cisco.aci.aci_fabric_wide_settings: + <<: *aci_info + state: query + register: query_fab + + - name: Verify Fabric Wide Settings queries + ansible.builtin.assert: + that: + - query_fab is not changed + - query_fab.current.0.infraSetPol.attributes.unicastXrEpLearnDisable == "yes" + - query_fab.current.0.infraSetPol.attributes.enforceSubnetCheck == "yes" + - query_fab.current.0.infraSetPol.attributes.validateOverlappingVlans == "yes" + - query_fab.current.0.infraSetPol.attributes.domainValidation == query_fab.current.0.infraSetPol.attributes.domainValidation + - query_fab.current.0.infraSetPol.attributes.opflexpAuthenticateClients == "yes" + - query_fab.current.0.infraSetPol.attributes.opflexpUseSsl == "yes" + - query_fab.current.0.infraSetPol.attributes.reallocateGipo == query_fab.current.0.infraSetPol.attributes.reallocateGipo + + - name: Verify Fabric Wide Settings queries + ansible.builtin.assert: + that: + - query_fab is not changed + - query_fab.current.0.infraSetPol.attributes.leafOpflexpAuthenticateClients == "yes" + - query_fab.current.0.infraSetPol.attributes.leafOpflexpUseSsl == "yes" + - query_fab.current.0.infraSetPol.attributes.restrictInfraVLANTraffic == "yes" + - query_fab.current.0.infraSetPol.attributes.opflexpSslProtocols == "TLSv1.1,TLSv1.2" + when: version.current.0.topSystem.attributes.version is version('5', '>=') diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_file_remote_path/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_file_remote_path/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_file_remote_path/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_file_remote_path/pki/rsa_ansible.key b/ansible_collections/cisco/aci/tests/integration/targets/aci_file_remote_path/pki/rsa_ansible.key new file mode 100644 index 000000000..ac63a0055 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_file_remote_path/pki/rsa_ansible.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDVyLS8/ix6QOH7R83B4WuhsliL6nffBvrkHXXsqViit3OZd+/K +fSrNlZysUvHS4hxfRtJrFQfpkogwXEEupBPF3p0xy7wZzvjjWWJk0NQ8PoVlOhUY +emZTfMX+FFNr9pAjjjaVHb9jCuxko7upAyj8POhhETY2zYoJoa8TR6fLZwIDAQAB +AoGBALo5GzeGMThNTIyW/6Tjt94ifP9kPwcIDYSoJRECczNKmmgVEcxRO/fZW6DA +n+YTEKPuDV059KqB+iAmPKFkS9N41kaq+NUAknlFJPV6Vs3gpvJGqWgu++73dhR5 +cKsHTlK2KBsRtsXnOJ9odKWFjiTnZ1Eyvmhw7ct+Fojb/7ABAkEA9+Wwm+HGlYqw +ghuFaBtNuqC/S2vO6SEfdQvTDQKKO5ROei5m+ryjWj6flbCcG+5dLs8l4Zh3sQUL +kc0RQfHSWQJBANzFkdO6wXXPOw7RhAEP2sA2W2VacMbGynjsoDJXmypeJ7Z+odLb +5gNXET9RA77RY/saIBdwR4JNnku2WnoxU78CQQDhYirVP0vu8H6UfHMpeRGNqdLi +vq0LlrrkDxEe1f1aN/e17HRiaZnXVfKABWeZmXmNMndNifLgtiaTtC+JllRZAkEA +ydAdV0SANvaCETC7j9DzcgP+lm8PatYsHlCIvJxS7m71tKCbw0pbQDBmRtADMXrt +/4vJTEPKSrYzfxiqKstOtwJAXkWXaqVhJeKjbMj1buo6s/1qGIfSrZR/AjozvJ03 +JehevfULS3668jOYJZW6BoNhysx6+Hqf5Id8fB4iDWPQhA== +-----END RSA PRIVATE KEY----- diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_file_remote_path/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_file_remote_path/tasks/main.yml new file mode 100644 index 000000000..ab1560ba6 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_file_remote_path/tasks/main.yml @@ -0,0 +1,231 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Tim Cragg (@timcragg) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +# CLEAN ENVIRONMENT +- name: Remove the ansible_remote_path + cisco.aci.aci_file_remote_path: + <<: *aci_info + name: ansible_file_path + state: absent + +# CREATE FILE REMOTE PATH +- name: Create a File Remote Path (check mode) + cisco.aci.aci_file_remote_path: &aci_path + <<: *aci_info + name: ansible_file_path + description: Test File Path + remote_host: test.example.com + remote_port: 22 + remote_protocol: scp + remote_user: test_user + auth_type: password + remote_path: /tmp + check_mode: true + register: cm_create_path + +- name: Create a File Remote Path + cisco.aci.aci_file_remote_path: + <<: *aci_path + register: nm_create_path + +- name: Create a File Remote Path Again + cisco.aci.aci_file_remote_path: + <<: *aci_path + register: nm_create_path_again + +- name: Create a second File Remote Path + cisco.aci.aci_file_remote_path: + <<: *aci_info + name: ansible_second_file_path + auth_type: password + remote_host: test2.example.com + remote_port: 22 + remote_protocol: scp + remote_path: /tmp + management_epg: oob-default + register: create_second_path + +- name: Create File Remote Path using SSH Key auth + cisco.aci.aci_file_remote_path: + <<: *aci_info + name: ansible_ssh_auth_file_path + auth_type: ssh_key + remote_key: "{{ lookup('file', 'pki/rsa_ansible.key') }}" + remote_host: test3.example.com + remote_port: 22 + remote_protocol: scp + remote_path: /tmp + register: create_key_auth_path + +- name: Verify creation of File Remote Path + ansible.builtin.assert: + that: + - cm_create_path is changed + - nm_create_path is changed + - nm_create_path_again is not changed + - nm_create_path.current.0.fileRemotePath.attributes.name == "ansible_file_path" + - nm_create_path.current.0.fileRemotePath.attributes.descr == "Test File Path" + - nm_create_path.current.0.fileRemotePath.attributes.protocol == "scp" + - nm_create_path.current.0.fileRemotePath.attributes.remotePort == "22" + - nm_create_path.current.0.fileRemotePath.attributes.authType == "usePassword" + - nm_create_path.current.0.fileRemotePath.attributes.userName == "test_user" + - nm_create_path.current.0.fileRemotePath.attributes.remotePath == "/tmp" + - nm_create_path_again.current.0.fileRemotePath.attributes.name == "ansible_file_path" + - nm_create_path_again.current.0.fileRemotePath.attributes.descr == "Test File Path" + - nm_create_path_again.current.0.fileRemotePath.attributes.protocol == "scp" + - nm_create_path_again.current.0.fileRemotePath.attributes.remotePort == "22" + - nm_create_path_again.current.0.fileRemotePath.attributes.authType == "usePassword" + - nm_create_path_again.current.0.fileRemotePath.attributes.userName == "test_user" + - nm_create_path_again.current.0.fileRemotePath.attributes.remotePath == "/tmp" + - create_second_path.current.0.fileRemotePath.children.0.fileRsARemoteHostToEpg.attributes.tDn == "uni/tn-mgmt/mgmtp-default/oob-default" + - create_key_auth_path.current.0.fileRemotePath.attributes.authType == "useSshKeyContents" + +# UPDATE FILE REMOTE PATH +- name: Update File Remote Path + cisco.aci.aci_file_remote_path: + <<: *aci_path + remote_protocol: sftp + remote_user: new_user + remote_password: new_pass + remote_path: /tmp/dummy + register: update_path + +- name: Verify update of File Remote Path + ansible.builtin.assert: + that: + - update_path is changed + - update_path.current.0.fileRemotePath.attributes.name == "ansible_file_path" + - update_path.current.0.fileRemotePath.attributes.descr == "Test File Path" + - update_path.current.0.fileRemotePath.attributes.protocol == "sftp" + - update_path.current.0.fileRemotePath.attributes.authType == "usePassword" + - update_path.current.0.fileRemotePath.attributes.userName == "new_user" + - update_path.current.0.fileRemotePath.attributes.remotePath == "/tmp/dummy" + +# QUERY FILE REMOTE PATH +- name: Query a File Remote Path + cisco.aci.aci_file_remote_path: + <<: *aci_path + state: query + register: query_one + +- name: Query all File Remote Paths + cisco.aci.aci_file_remote_path: + <<: *aci_info + state: query + register: query_all + +- name: Verify File Remote Path queries + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current.0.fileRemotePath.attributes.name == "ansible_file_path" + - query_one.current.0.fileRemotePath.attributes.descr == "Test File Path" + - query_one.current.0.fileRemotePath.attributes.protocol == "sftp" + - query_one.current.0.fileRemotePath.attributes.authType == "usePassword" + - query_one.current.0.fileRemotePath.attributes.userName == "new_user" + - query_one.current.0.fileRemotePath.attributes.remotePath == "/tmp/dummy" + - query_all is not changed + - query_all.current | length > 1 + +# VALIDATE ERROR CHECKING +- name: Create Remote Path with remote_key when auth_type is password + cisco.aci.aci_file_remote_path: + <<: *aci_info + name: incorrect_auth_type1 + remote_host: test2.example.com + remote_port: 22 + remote_protocol: scp + remote_user: test_user + auth_type: password + remote_key: "{{ lookup('file', 'pki/rsa_ansible.key') }}" + remote_path: /tmp + ignore_errors: true + register: incorrect_auth_type1 + +- name: Create Remote Path with passphrase when auth_type is password + cisco.aci.aci_file_remote_path: + <<: *aci_info + name: incorrect_auth_type2 + remote_host: test2.example.com + remote_port: 22 + remote_protocol: scp + remote_user: test_user + auth_type: password + passphrase: ansible_passphrase + remote_path: /tmp + ignore_errors: true + register: incorrect_auth_type2 + +- name: Create Remote Path with password when auth_type is ssh_key + cisco.aci.aci_file_remote_path: + <<: *aci_info + name: incorrect_auth_type3 + remote_host: test2.example.com + remote_port: 22 + remote_protocol: scp + remote_user: test_user + auth_type: ssh_key + remote_password: test_password + remote_path: /tmp + ignore_errors: true + register: incorrect_auth_type3 + +- name: Validate error checking + ansible.builtin.assert: + that: + - incorrect_auth_type1 is failed + - incorrect_auth_type2 is failed + - incorrect_auth_type3 is failed + - incorrect_auth_type1.msg == "remote_key cannot be set if auth_type is password" + - incorrect_auth_type2.msg == "passphrase cannot be set if auth_type is password" + - incorrect_auth_type3.msg == "remote_password cannot be set if auth_type is ssh_key" + +# REMOVE FILE REMOTE PATH +- name: Delete a File Remote Path + cisco.aci.aci_file_remote_path: + <<: *aci_path + state: absent + register: delete + +- name: Delete File Remote Path again + cisco.aci.aci_file_remote_path: + <<: *aci_path + state: absent + register: delete_again + +- name: Verify deletion of File Remote Path + ansible.builtin.assert: + that: + - delete is changed + - delete_again is not changed + - delete.current == [] + +- name: Delete Second File Remote Path + cisco.aci.aci_file_remote_path: + <<: *aci_info + name: ansible_second_file_path + state: absent + +- name: Delete SSH Key Auth File Remote Path + cisco.aci.aci_file_remote_path: + <<: *aci_info + name: ansible_ssh_auth_file_path + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_filter_entry/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_filter_entry/tasks/main.yml index 77093a670..e969111a2 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_filter_entry/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_filter_entry/tasks/main.yml @@ -20,296 +20,492 @@ use_proxy: '{{ aci_use_proxy | default(true) }}' output_level: '{{ aci_output_level | default("debug") }}' -- name: ensure tenant exists for tests to kick off - cisco.aci.aci_tenant: - <<: *aci_info - tenant: ansible_test - state: absent - -- name: ensure tenant exists for tests to kick off - cisco.aci.aci_tenant: &aci_tenant_present - <<: *aci_info - tenant: ansible_test - state: present - register: tenant_present - -- name: ensure filter exists for tests to kick off - cisco.aci.aci_filter: &aci_filter_present - <<: *aci_tenant_present - filter: anstest - register: filter_present - -- name: create filter entry - check mode works - cisco.aci.aci_filter_entry: &aci_entry_present - <<: *aci_filter_present - entry: anstest - description: Ansible Test - ether_type: ip - ip_protocol: tcp - dst_port_start: 80 - dst_port_end: 88 - check_mode: true - register: entry_present_check_mode - -- name: create filter entry - creation works - cisco.aci.aci_filter_entry: - <<: *aci_entry_present - register: entry_present - -- name: create filter entry - idempotency works - cisco.aci.aci_filter_entry: - <<: *aci_entry_present - register: entry_present_idempotent - -- name: update filter entry - update works - cisco.aci.aci_filter_entry: - <<: *aci_entry_present - description: Ansible Test Update - dst_port_start: 80 - dst_port_end: 90 - register: entry_present_update - - name: Verify Cloud and Non-Cloud Sites in use. include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml -- name: create filter entry - test different types - cisco.aci.aci_filter_entry: - <<: *aci_filter_present - entry: anstest2 - ether_type: arp - arp_flag: arp_reply - register: entry_present_2 - when: query_cloud.current == [] # This condition will skip execution for cloud sites - -- name: create filter entry - test different types - cisco.aci.aci_filter_entry: - <<: *aci_filter_present - entry: anstest3 - ether_type: ip - ip_protocol: icmp - icmp_msg_type: echo - register: entry_present_3 - -- name: create filter entry - test different types - cisco.aci.aci_filter_entry: - <<: *aci_filter_present - entry: anstest4 - ether_type: ip - ip_protocol: udp - dst_port: 1000 - register: entry_present_4 - -- name: missing param - failure message works - cisco.aci.aci_filter_entry: - <<: *aci_filter_present - ignore_errors: true - register: present_missing_param - -- name: incompatable params - failure message works - cisco.aci.aci_filter_entry: - <<: *aci_entry_present - dst_port: 99 - ignore_errors: true - register: present_incompatible_params - -- name: present assertions - assert: - that: - - entry_present_check_mode is changed - - entry_present_check_mode.previous == [] - - entry_present_check_mode.sent.vzEntry.attributes.dFromPort == 'http' - - entry_present_check_mode.sent.vzEntry.attributes.dToPort == '88' - - entry_present_check_mode.sent.vzEntry.attributes.descr == 'Ansible Test' - - entry_present_check_mode.sent.vzEntry.attributes.etherT == 'ip' - - entry_present_check_mode.sent.vzEntry.attributes.name == 'anstest' - - entry_present_check_mode.sent.vzEntry.attributes.prot == 'tcp' - - entry_present is changed - - entry_present.current.0.vzEntry.attributes.annotation == 'orchestrator:ansible' - - entry_present.previous == [] - - entry_present.sent == entry_present_check_mode.sent - - entry_present_idempotent is not changed - - entry_present_idempotent.previous != [] - - entry_present_idempotent.sent == {} - - entry_present_update is changed - - entry_present_update.previous != [] - - entry_present_update.sent != entry_present_update.proposed - - entry_present_3 is changed - - entry_present_3.sent.vzEntry.attributes.etherT == 'ip' - - entry_present_3.sent.vzEntry.attributes.icmpv4T == 'echo' - - entry_present_3.sent.vzEntry.attributes.name == 'anstest3' - - entry_present_3.sent.vzEntry.attributes.prot == 'icmp' - - entry_present_4 is changed - - entry_present_4.sent.vzEntry.attributes.dFromPort == '1000' - - entry_present_4.sent.vzEntry.attributes.dToPort == '1000' - - entry_present_4.sent.vzEntry.attributes.etherT == 'ip' - - entry_present_4.sent.vzEntry.attributes.name == 'anstest4' - - entry_present_4.sent.vzEntry.attributes.prot == 'udp' - - present_missing_param is failed - - 'present_missing_param.msg == "state is present but all of the following are missing: entry"' - - present_incompatible_params is failed - - present_incompatible_params.msg.startswith("Parameter") - -- name: present assertions for arp - assert: - that: - - entry_present_2 is changed - - entry_present_2.sent.vzEntry.attributes.arpOpc == 'reply' - - entry_present_2.sent.vzEntry.attributes.etherT == 'arp' - - entry_present_2.sent.vzEntry.attributes.name == 'anstest2' - when: query_cloud.current == [] # This condition will skip execution for cloud sites - -- name: query tenant filter entry - cisco.aci.aci_filter_entry: &aci_query_entry - <<: *aci_entry_present - state: query - register: query_tenant_filter_entry - -- name: query filter entry - cisco.aci.aci_filter_entry: - <<: *aci_query_entry - tenant: "{{ fakevar | default(omit) }}" - register: query_filter_entry - -- name: query tenant entry - cisco.aci.aci_filter_entry: - <<: *aci_query_entry - filter: "{{ fakevar | default(omit) }}" - register: query_tenant_entry - -- name: query tenant filter - cisco.aci.aci_filter_entry: - <<: *aci_query_entry - entry: "{{ fakevar | default(omit) }}" - register: query_tenant_filter - -- name: query entry - cisco.aci.aci_filter_entry: &aci_query_entry_2 - <<: *aci_query_entry - tenant: "{{ fakevar | default(omit) }}" - filter: "{{ fakevar | default(omit) }}" - register: query_entry - -- name: query filter - cisco.aci.aci_filter_entry: - <<: *aci_query_entry - tenant: "{{ fakevar | default(omit) }}" - entry: "{{ fakevar | default(omit) }}" - register: query_filter - -- name: query tenant - cisco.aci.aci_filter_entry: - <<: *aci_query_entry - filter: "{{ fakevar | default(omit) }}" - entry: "{{ fakevar | default(omit) }}" - register: query_tenant - -- name: query all - cisco.aci.aci_filter_entry: - <<: *aci_query_entry_2 - entry: "{{ fakevar | default(omit) }}" - register: query_all - -- name: query assertions for all - assert: - that: - - query_tenant_filter_entry is not changed - - query_tenant_filter_entry.current | length == 1 - - query_tenant_filter_entry.current.0.vzEntry.attributes.name == "anstest" - - '"tn-ansible_test/flt-anstest/e-anstest.json" in query_tenant_filter_entry.url' - - query_filter_entry is not changed - - query_filter_entry.current.0.vzFilter.attributes.name == "anstest" - - query_filter_entry.current.0.vzFilter.children | length == 1 - - '"query-target-filter=eq(vzFilter.name,\"anstest\")" in query_filter_entry.filter_string' - - '"rsp-subtree-filter=eq(vzEntry.name,\"anstest\")" in query_filter_entry.filter_string' - - '"class/vzFilter.json" in query_filter_entry.url' - - query_tenant_entry is not changed - - query_tenant_entry.current | length == 1 - - query_tenant_entry.current.0.fvTenant.attributes.name == "ansible_test" - - '"rsp-subtree-filter=eq(vzEntry.name,\"anstest\")" in query_tenant_entry.filter_string' - - '"rsp-subtree-class=vzEntry" in query_tenant_entry.filter_string' - - '"tn-ansible_test.json" in query_tenant_entry.url' - - query_tenant_filter is not changed - - query_tenant_filter.current | length == 1 - - query_tenant_filter.current.0.vzFilter.attributes.name == "anstest" - - '"rsp-subtree-class=vzEntry" in query_tenant_filter.filter_string' - - '"tn-ansible_test/flt-anstest.json" in query_tenant_filter.url' - - query_entry is not changed - - query_entry.current.0.vzEntry.attributes.name == "anstest" - - '"query-target-filter=eq(vzEntry.name,\"anstest\")" in query_entry.filter_string' - - '"class/vzEntry.json" in query_entry.url' - - query_filter is not changed - - query_filter.current.0.vzFilter.attributes.name == "anstest" - - '"query-target-filter=eq(vzFilter.name,\"anstest\")" in query_filter.filter_string' - - '"rsp-subtree-class=vzEntry" in query_filter.filter_string' - - '"class/vzFilter.json" in query_filter.url' - - query_tenant is not changed - - query_tenant.current | length == 1 - - query_tenant.current.0.fvTenant.attributes.name == "ansible_test" - - '"rsp-subtree-class=vzEntry,vzFilter" in query_tenant.filter_string' - - '"tn-ansible_test.json" in query_tenant.url' - - query_all is not changed - - query_all.current | length > 1 - - query_all.current.0.vzEntry is defined - - '"class/vzEntry.json" in query_all.url' - - -- name: query assertions for only Non-Cloud - assert: - that: - - query_tenant_filter.current.0.vzFilter.children | length == 4 - when: query_cloud.current == [] # This condition will skip execution for cloud sites - -- name: delete entry - check mode works - cisco.aci.aci_filter_entry: &aci_entry_absent - <<: *aci_entry_present - state: absent - check_mode: true - register: entry_absent_check_mode - -- name: delete entry - deletion works - cisco.aci.aci_filter_entry: - <<: *aci_entry_absent - register: entry_absent - -- name: delete entry - idempotency works - cisco.aci.aci_filter_entry: - <<: *aci_entry_absent - register: entry_absent_idempotent - -- name: missing param - failure message works - cisco.aci.aci_filter_entry: - <<: *aci_tenant_present - state: absent - ignore_errors: true - register: absent_missing_param - -- name: cleanup remaining entries - cisco.aci.aci_filter_entry: - <<: *aci_entry_absent - entry: "{{ item }}" - with_items: ["anstest2", "anstest3", "anstest4"] - -- name: absent assertions - assert: - that: - - entry_absent_check_mode is changed - - entry_absent_check_mode.previous != [] - - entry_absent is changed - - entry_absent.previous == entry_absent_check_mode.previous - - entry_absent.proposed == {} - - entry_absent_idempotent is not changed - - entry_absent_idempotent.previous == [] - - absent_missing_param is failed - - 'absent_missing_param.msg == "state is absent but all of the following are missing: entry, filter"' - -- name: cleanup filter - cisco.aci.aci_filter: - <<: *aci_filter_present - state: absent - when: filter_present is changed - -- name: cleanup tenant - cisco.aci.aci_tenant: - <<: *aci_tenant_present - state: absent - when: tenant_present is changed +# TODO current module will fail on cloud sites because range is not supported +# APIC Error 1: Invalid Configuration CLOUD_SOURCE_PORT_NOT_SUPPORTED: vz::EntryMo Dn = uni/tn-ansible_test/flt-anstest_fileter_2/e-source_port_start - Source port range is not allowed on CAPIC" +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + + - name: ensure tenant exists for tests to kick off + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_test + state: absent + + - name: ensure tenant exists for tests to kick off + cisco.aci.aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_test + state: present + register: tenant_present + + - name: ensure filter exists for tests to kick off + cisco.aci.aci_filter: &aci_filter_present + <<: *aci_tenant_present + filter: anstest + register: filter_present + + - name: ensure anstest_2 filter exists for tests to kick off + cisco.aci.aci_filter: &anstest_fileter_2_present + <<: *aci_tenant_present + filter: anstest_fileter_2 + + - name: Create a filter entry with the match_only_fragments - enabled and dst_port values - negative test + cisco.aci.aci_filter_entry: + <<: *anstest_fileter_2_present + entry: nt_match_only_fragments_with_dst_port + ether_type: ip + ip_protocol: tcp + dst_port_start: 80 + dst_port_end: 88 + match_only_fragments: true + register: nt_match_only_fragments_with_dst_port + ignore_errors: true + + - name: Create a filter entry with the match_only_fragments - enabled + cisco.aci.aci_filter_entry: &match_only_fragments_enabled + <<: *anstest_fileter_2_present + entry: match_only_fragments_enabled + ether_type: ip + ip_protocol: tcp + match_only_fragments: true + register: match_only_fragments_enabled + + - name: Disabled the match_only_fragments of an existing filter entry - "match_only_fragments_enabled" + cisco.aci.aci_filter_entry: + <<: *match_only_fragments_enabled + match_only_fragments: false + register: match_only_fragments_disabled + + - name: Create a filter entry with the source_port values - negative test + cisco.aci.aci_filter_entry: + <<: *anstest_fileter_2_present + entry: nt_source_port + ether_type: ip + ip_protocol: tcp + source_port: 20 + source_port_start: 22 + source_port_end: 22 + register: nt_source_port + ignore_errors: true + + - name: Create a filter entry with the only dst_port_end - negative test + cisco.aci.aci_filter_entry: + <<: *anstest_fileter_2_present + entry: nt_dst_port_end + ether_type: ip + ip_protocol: tcp + dst_port_end: 20 + register: nt_dst_port_end + ignore_errors: true + + - name: Create a filter entry with the only source_port_end - negative test + cisco.aci.aci_filter_entry: + <<: *anstest_fileter_2_present + entry: nt_source_port_end + ether_type: ip + ip_protocol: tcp + source_port_end: 20 + register: nt_source_port_end + ignore_errors: true + + - name: Create a filter entry with the only source_port_start + cisco.aci.aci_filter_entry: + <<: *anstest_fileter_2_present + entry: source_port_start + ether_type: ip + ip_protocol: tcp + source_port_start: 20 + register: source_port_start + + - name: Create a filter entry with only source_port_start, source_port_end and valid tcp_flags rules + cisco.aci.aci_filter_entry: + <<: *anstest_fileter_2_present + entry: source_port_values + ether_type: ip + ip_protocol: tcp + source_port_start: 20 + source_port_end: 23 + tcp_flags: + - acknowledgment + - finish + register: source_port_values + + - name: Updated source port and tcp_flags values of an existing filter entry - "source_port_values" + cisco.aci.aci_filter_entry: + <<: *anstest_fileter_2_present + entry: source_port_values + ether_type: ip + ip_protocol: tcp + source_port: 53 + tcp_flags: + - acknowledgment + register: update_source_port_values + + - name: Create a filter entry with the tcp_flags - established and other tcp rules - negative test + cisco.aci.aci_filter_entry: + <<: *anstest_fileter_2_present + entry: nt_tcp_flags + ether_type: ip + ip_protocol: tcp + tcp_flags: + - acknowledgment + - established + - finish + register: nt_tcp_flags + ignore_errors: true + + - name: Create a filter entry with the tcp_flags - established + cisco.aci.aci_filter_entry: + <<: *anstest_fileter_2_present + entry: tcp_flags_est + ether_type: ip + ip_protocol: tcp + tcp_flags: + - established + register: tcp_flags_est + + - name: Create a filter entry with icmp6_msg_type - established + cisco.aci.aci_filter_entry: + <<: *anstest_fileter_2_present + entry: icmp6_msg_type_est + icmp6_msg_type: neighbor_solicitation + register: icmp6_msg_type_est + + - name: Assertion check for the filter entry - match_only_fragments, source_port and tcp_flags attributes + assert: + that: + - nt_match_only_fragments_with_dst_port is not changed + - nt_match_only_fragments_with_dst_port.msg == "Parameter 'match_only_fragments' cannot be used with 'Layer 4 Port' value" + - match_only_fragments_enabled is changed + - match_only_fragments_enabled.current.0.vzEntry.attributes.name == "match_only_fragments_enabled" + - match_only_fragments_enabled.current.0.vzEntry.attributes.tcpRules == match_only_fragments_enabled.current.0.vzEntry.attributes.tcpRules == "" + - match_only_fragments_enabled.current.0.vzEntry.attributes.applyToFrag == match_only_fragments_enabled.sent.vzEntry.attributes.applyToFrag == "yes" + - match_only_fragments_enabled.current.0.vzEntry.attributes.sFromPort == match_only_fragments_enabled.current.0.vzEntry.attributes.sToPort == "unspecified" + - match_only_fragments_enabled.current.0.vzEntry.attributes.dFromPort == match_only_fragments_enabled.current.0.vzEntry.attributes.dToPort == "unspecified" + - match_only_fragments_disabled is changed + - match_only_fragments_disabled.current.0.vzEntry.attributes.applyToFrag == match_only_fragments_disabled.sent.vzEntry.attributes.applyToFrag == "no" + - match_only_fragments_disabled.current.0.vzEntry.attributes.name == "match_only_fragments_enabled" + - match_only_fragments_disabled.current.0.vzEntry.attributes.tcpRules == "" + - match_only_fragments_disabled.current.0.vzEntry.attributes.sFromPort == match_only_fragments_disabled.current.0.vzEntry.attributes.sToPort == "unspecified" + - match_only_fragments_disabled.current.0.vzEntry.attributes.dFromPort == match_only_fragments_disabled.current.0.vzEntry.attributes.dToPort == "unspecified" + - nt_source_port is not changed + - nt_source_port.msg == "Parameter 'source_port' cannot be used with 'source_port_end' and 'source_port_start'" + - nt_dst_port_end is not changed + - nt_dst_port_end.msg == "Parameter 'dst_port_end' cannot be configured when the 'dst_port_start' is not defined" + - nt_source_port_end is not changed + - nt_source_port_end.msg == "Parameter 'source_port_end' cannot be configured when the 'source_port_start' is not defined" + - source_port_start is changed + - source_port_start.current.0.vzEntry.attributes.name == source_port_start.sent.vzEntry.attributes.name == "source_port_start" + - source_port_start.current.0.vzEntry.attributes.sFromPort == source_port_start.sent.vzEntry.attributes.sFromPort == "ftpData" + - source_port_start.current.0.vzEntry.attributes.sToPort == "ftpData" + - source_port_start.current.0.vzEntry.attributes.tcpRules == source_port_start.sent.vzEntry.attributes.tcpRules == "" + - source_port_start.current.0.vzEntry.attributes.applyToFrag == "no" + - source_port_start.current.0.vzEntry.attributes.arpOpc == "unspecified" + - source_port_start.current.0.vzEntry.attributes.etherT == "ip" + - source_port_start.current.0.vzEntry.attributes.prot == "tcp" + - source_port_values is changed + - source_port_values.current.0.vzEntry.attributes.name == source_port_values.sent.vzEntry.attributes.name == "source_port_values" + - source_port_values.current.0.vzEntry.attributes.sFromPort == source_port_values.sent.vzEntry.attributes.sFromPort == "ftpData" + - source_port_values.current.0.vzEntry.attributes.sToPort == source_port_values.sent.vzEntry.attributes.sToPort == "23" + - source_port_values.current.0.vzEntry.attributes.tcpRules == source_port_values.sent.vzEntry.attributes.tcpRules == "ack,fin" + - source_port_values.current.0.vzEntry.attributes.applyToFrag == "no" + - source_port_values.current.0.vzEntry.attributes.arpOpc == "unspecified" + - source_port_values.current.0.vzEntry.attributes.etherT == "ip" + - source_port_values.current.0.vzEntry.attributes.prot == "tcp" + - update_source_port_values is changed + - update_source_port_values.current.0.vzEntry.attributes.name == "source_port_values" + - update_source_port_values.current.0.vzEntry.attributes.applyToFrag == "no" + - update_source_port_values.current.0.vzEntry.attributes.arpOpc == "unspecified" + - update_source_port_values.current.0.vzEntry.attributes.etherT == "ip" + - update_source_port_values.current.0.vzEntry.attributes.prot == "tcp" + - update_source_port_values.current.0.vzEntry.attributes.sFromPort == update_source_port_values.sent.vzEntry.attributes.sFromPort == "dns" + - update_source_port_values.current.0.vzEntry.attributes.sToPort == update_source_port_values.sent.vzEntry.attributes.sToPort == "dns" + - update_source_port_values.current.0.vzEntry.attributes.tcpRules == update_source_port_values.sent.vzEntry.attributes.tcpRules == "ack" + - nt_tcp_flags is not changed + - nt_tcp_flags.msg == "TCP established cannot be combined with other tcp rules" + - tcp_flags_est is changed + - tcp_flags_est.current.0.vzEntry.attributes.applyToFrag == "no" + - tcp_flags_est.current.0.vzEntry.attributes.tcpRules == tcp_flags_est.sent.vzEntry.attributes.tcpRules == "est" + - tcp_flags_est.current.0.vzEntry.attributes.name == tcp_flags_est.sent.vzEntry.attributes.name == "tcp_flags_est" + - tcp_flags_est.current.0.vzEntry.attributes.etherT == tcp_flags_est.sent.vzEntry.attributes.etherT == "ip" + - icmp6_msg_type_est.current.0.vzEntry.attributes.icmpv6T == "nbr-solicit" + + - name: create filter entry - check mode works + cisco.aci.aci_filter_entry: &aci_entry_present + <<: *aci_filter_present + entry: anstest + description: Ansible Test + ether_type: ip + ip_protocol: tcp + dst_port_start: 80 + dst_port_end: 88 + check_mode: true + register: entry_present_check_mode + + - name: create filter entry - creation works + cisco.aci.aci_filter_entry: + <<: *aci_entry_present + register: entry_present + + - name: create filter entry - idempotency works + cisco.aci.aci_filter_entry: + <<: *aci_entry_present + register: entry_present_idempotent + + - name: update filter entry - update works + cisco.aci.aci_filter_entry: + <<: *aci_entry_present + description: Ansible Test Update + dst_port: 80 + dst_port_start: "{{ fake_var | default(omit) }}" + dst_port_end: "{{ fake_var | default(omit) }}" + register: entry_present_update + + - name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + + - name: create filter entry - test different types + cisco.aci.aci_filter_entry: + <<: *aci_filter_present + entry: anstest2 + ether_type: arp + arp_flag: arp_reply + register: entry_present_2 + when: query_cloud.current == [] # This condition will skip execution for cloud sites + + - name: create filter entry - test different types + cisco.aci.aci_filter_entry: + <<: *aci_filter_present + entry: anstest3 + ether_type: ip + ip_protocol: icmp + icmp_msg_type: echo + register: entry_present_3 + + - name: create filter entry - test different types + cisco.aci.aci_filter_entry: + <<: *aci_filter_present + entry: anstest4 + ether_type: ip + ip_protocol: udp + dst_port: 1000 + register: entry_present_4 + + - name: missing param - failure message works + cisco.aci.aci_filter_entry: + <<: *aci_filter_present + ignore_errors: true + register: present_missing_param + + - name: incompatable params - failure message works + cisco.aci.aci_filter_entry: + <<: *aci_entry_present + dst_port: 99 + ignore_errors: true + register: present_incompatible_params + + - name: present assertions + assert: + that: + - entry_present_check_mode is changed + - entry_present_check_mode.previous == [] + - entry_present_check_mode.sent.vzEntry.attributes.dFromPort == 'http' + - entry_present_check_mode.sent.vzEntry.attributes.dToPort == '88' + - entry_present_check_mode.sent.vzEntry.attributes.descr == 'Ansible Test' + - entry_present_check_mode.sent.vzEntry.attributes.etherT == 'ip' + - entry_present_check_mode.sent.vzEntry.attributes.name == 'anstest' + - entry_present_check_mode.sent.vzEntry.attributes.prot == 'tcp' + - entry_present is changed + - entry_present.current.0.vzEntry.attributes.annotation == 'orchestrator:ansible' + - entry_present.previous == [] + - entry_present.sent == entry_present_check_mode.sent + - entry_present_idempotent is not changed + - entry_present_idempotent.previous != [] + - entry_present_idempotent.sent == {} + - entry_present_update is changed + - entry_present_update.previous != [] + - entry_present_update.sent != entry_present_update.proposed + - entry_present_3 is changed + - entry_present_3.sent.vzEntry.attributes.etherT == 'ip' + - entry_present_3.sent.vzEntry.attributes.icmpv4T == 'echo' + - entry_present_3.sent.vzEntry.attributes.name == 'anstest3' + - entry_present_3.sent.vzEntry.attributes.prot == 'icmp' + - entry_present_4 is changed + - entry_present_4.sent.vzEntry.attributes.dFromPort == '1000' + - entry_present_4.sent.vzEntry.attributes.dToPort == '1000' + - entry_present_4.sent.vzEntry.attributes.etherT == 'ip' + - entry_present_4.sent.vzEntry.attributes.name == 'anstest4' + - entry_present_4.sent.vzEntry.attributes.prot == 'udp' + - present_missing_param is failed + - 'present_missing_param.msg == "state is present but all of the following are missing: entry"' + - present_incompatible_params is failed + - present_incompatible_params.msg.startswith("Parameter") + + - name: present assertions for arp + assert: + that: + - entry_present_2 is changed + - entry_present_2.sent.vzEntry.attributes.arpOpc == 'reply' + - entry_present_2.sent.vzEntry.attributes.etherT == 'arp' + - entry_present_2.sent.vzEntry.attributes.name == 'anstest2' + when: query_cloud.current == [] # This condition will skip execution for cloud sites + + - name: query tenant filter entry + cisco.aci.aci_filter_entry: &aci_query_entry + <<: *aci_entry_present + state: query + register: query_tenant_filter_entry + + - name: query filter entry + cisco.aci.aci_filter_entry: + <<: *aci_query_entry + tenant: "{{ fakevar | default(omit) }}" + register: query_filter_entry + + - name: query tenant entry + cisco.aci.aci_filter_entry: + <<: *aci_query_entry + filter: "{{ fakevar | default(omit) }}" + register: query_tenant_entry + + - name: query tenant filter + cisco.aci.aci_filter_entry: + <<: *aci_query_entry + entry: "{{ fakevar | default(omit) }}" + register: query_tenant_filter + + - name: query entry + cisco.aci.aci_filter_entry: &aci_query_entry_2 + <<: *aci_query_entry + tenant: "{{ fakevar | default(omit) }}" + filter: "{{ fakevar | default(omit) }}" + register: query_entry + + - name: query filter + cisco.aci.aci_filter_entry: + <<: *aci_query_entry + tenant: "{{ fakevar | default(omit) }}" + entry: "{{ fakevar | default(omit) }}" + register: query_filter + + - name: query tenant + cisco.aci.aci_filter_entry: + <<: *aci_query_entry + filter: "{{ fakevar | default(omit) }}" + entry: "{{ fakevar | default(omit) }}" + register: query_tenant + + - name: query all + cisco.aci.aci_filter_entry: + <<: *aci_query_entry_2 + entry: "{{ fakevar | default(omit) }}" + register: query_all + + - name: query assertions for all + assert: + that: + - query_tenant_filter_entry is not changed + - query_tenant_filter_entry.current | length == 1 + - query_tenant_filter_entry.current.0.vzEntry.attributes.name == "anstest" + - '"tn-ansible_test/flt-anstest/e-anstest.json" in query_tenant_filter_entry.url' + - query_filter_entry is not changed + - query_filter_entry.current.0.vzFilter.attributes.name == "anstest" + - query_filter_entry.current.0.vzFilter.children | length == 1 + - '"query-target-filter=eq(vzFilter.name,\"anstest\")" in query_filter_entry.filter_string' + - '"rsp-subtree-filter=eq(vzEntry.name,\"anstest\")" in query_filter_entry.filter_string' + - '"class/vzFilter.json" in query_filter_entry.url' + - query_tenant_entry is not changed + - query_tenant_entry.current | length == 1 + - query_tenant_entry.current.0.fvTenant.attributes.name == "ansible_test" + - '"rsp-subtree-filter=eq(vzEntry.name,\"anstest\")" in query_tenant_entry.filter_string' + - '"rsp-subtree-class=vzEntry" in query_tenant_entry.filter_string' + - '"tn-ansible_test.json" in query_tenant_entry.url' + - query_tenant_filter is not changed + - query_tenant_filter.current | length == 1 + - query_tenant_filter.current.0.vzFilter.attributes.name == "anstest" + - '"rsp-subtree-class=vzEntry" in query_tenant_filter.filter_string' + - '"tn-ansible_test/flt-anstest.json" in query_tenant_filter.url' + - query_entry is not changed + - query_entry.current.0.vzEntry.attributes.name == "anstest" + - '"query-target-filter=eq(vzEntry.name,\"anstest\")" in query_entry.filter_string' + - '"class/vzEntry.json" in query_entry.url' + - query_filter is not changed + - query_filter.current.0.vzFilter.attributes.name == "anstest" + - '"query-target-filter=eq(vzFilter.name,\"anstest\")" in query_filter.filter_string' + - '"rsp-subtree-class=vzEntry" in query_filter.filter_string' + - '"class/vzFilter.json" in query_filter.url' + - query_tenant is not changed + - query_tenant.current | length == 1 + - query_tenant.current.0.fvTenant.attributes.name == "ansible_test" + - '"rsp-subtree-class=vzEntry,vzFilter" in query_tenant.filter_string' + - '"tn-ansible_test.json" in query_tenant.url' + - query_all is not changed + - query_all.current | length > 1 + - query_all.current.0.vzEntry is defined + - '"class/vzEntry.json" in query_all.url' + + + - name: query assertions for only Non-Cloud + assert: + that: + - query_tenant_filter.current.0.vzFilter.children | length == 4 + when: query_cloud.current == [] # This condition will skip execution for cloud sites + + - name: delete entry - check mode works + cisco.aci.aci_filter_entry: &aci_entry_absent + <<: *aci_entry_present + state: absent + check_mode: true + register: entry_absent_check_mode + + - name: delete entry - deletion works + cisco.aci.aci_filter_entry: + <<: *aci_entry_absent + register: entry_absent + + - name: delete entry - idempotency works + cisco.aci.aci_filter_entry: + <<: *aci_entry_absent + register: entry_absent_idempotent + + - name: missing param - failure message works + cisco.aci.aci_filter_entry: + <<: *aci_tenant_present + state: absent + ignore_errors: true + register: absent_missing_param + + - name: cleanup remaining entries + cisco.aci.aci_filter_entry: + <<: *aci_entry_absent + entry: "{{ item }}" + with_items: ["anstest2", "anstest3", "anstest4"] + + - name: absent assertions + assert: + that: + - entry_absent_check_mode is changed + - entry_absent_check_mode.previous != [] + - entry_absent is changed + - entry_absent.previous == entry_absent_check_mode.previous + - entry_absent.proposed == {} + - entry_absent_idempotent is not changed + - entry_absent_idempotent.previous == [] + - absent_missing_param is failed + - 'absent_missing_param.msg == "state is absent but all of the following are missing: entry, filter"' + + - name: cleanup filter + cisco.aci.aci_filter: + <<: *aci_filter_present + state: absent + when: filter_present is changed + + - name: cleanup tenant + cisco.aci.aci_tenant: + <<: *aci_tenant_present + state: absent + when: tenant_present is changed diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_group/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_group/tasks/main.yml new file mode 100644 index 000000000..5cf88997c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_group/tasks/main.yml @@ -0,0 +1,154 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Clean Environment + - name: Create firmware policy + aci_firmware_policy: &aci_firmware_policy_present + <<: *aci_info + name: anstest_policy + version: n9000-15.2(7) + state: present + + - name: Ensure first firmware group does not exist + aci_firmware_group: &aci_firmware_group_absent + <<: *aci_info + group: anstest_group + policy: anstest_policy + type_group: all + description: test firmware group + state: absent + + - name: Ensure second firmware group does not exist + aci_firmware_group: &aci_firmware_group_2_absent + <<: *aci_info + group: anstest_group_2 + policy: anstest_policy + state: absent + + - name: Create first firmware group (check_mode) + aci_firmware_group: &aci_firmware_group_present + <<: *aci_firmware_group_absent + state: present + check_mode: true + register: cm_add_firmware_group_1 + + - name: Create first firmware group (normal_mode) + aci_firmware_group: + <<: *aci_firmware_group_present + register: nm_add_firmware_group_1 + + - name: Create first firmware group again - testing idempotency + aci_firmware_group: + <<: *aci_firmware_group_present + register: idempotency_add_firmware_group_1 + + - name: Create second firmware group + aci_firmware_group: &aci_firmware_group_2_present + <<: *aci_firmware_group_2_absent + state: present + register: nm_add_firmware_group_2 + + - name: Asserts for creation tasks + assert: + that: + - cm_add_firmware_group_1 is changed + - cm_add_firmware_group_1.previous == [] + - cm_add_firmware_group_1.current == [] + - nm_add_firmware_group_1 is changed + - nm_add_firmware_group_1.current.0.firmwareFwGrp.attributes.name == "anstest_group" + - nm_add_firmware_group_1.current.0.firmwareFwGrp.attributes.type == "ALL" + - nm_add_firmware_group_1.current.0.firmwareFwGrp.children.0.firmwareRsFwgrpp.attributes.tnFirmwareFwPName == "anstest_policy" + - idempotency_add_firmware_group_1 is not changed + - nm_add_firmware_group_2 is changed + + - name: Query all firmware groups + aci_firmware_group: + <<: *aci_info + state: query + register: query_all_firmware_group + + - name: Query first firmware group + aci_firmware_group: + <<: *aci_firmware_group_present + state: query + register: query_first_firmware_group + + - name: Asserts for query tasks + assert: + that: + - query_all_firmware_group is not changed + - query_all_firmware_group.current | length >= 2 + - '"firmwareRsFwgrpp" in query_all_firmware_group.filter_string' + - '"class/firmwareFwGrp.json" in query_all_firmware_group.url' + - query_first_firmware_group is not changed + - query_first_firmware_group.current.0.firmwareFwGrp.attributes.name == "anstest_group" + - query_first_firmware_group.current.0.firmwareFwGrp.attributes.type == "ALL" + - query_first_firmware_group.current.0.firmwareFwGrp.children.0.firmwareRsFwgrpp.attributes.tnFirmwareFwPName == "anstest_policy" + + - name: Delete first firmware group (check_mode) + aci_firmware_group: + <<: *aci_firmware_group_present + state: absent + check_mode: true + register: cm_delete_firmware_group_1 + + - name: Delete first firmware group (normal_mode) + aci_firmware_group: + <<: *aci_firmware_group_present + state: absent + register: nm_delete_firmware_group_1 + + - name: Delete first firmware group again - testing idempotency + aci_firmware_group: + <<: *aci_firmware_group_present + state: absent + register: idempotency_delete_firmware_group_1 + + - name: Delete second firmware group (normal_mode) + aci_firmware_group: + <<: *aci_firmware_group_2_present + state: absent + register: nm_delete_firmware_group_2 + + - name: Asserts for deletion tasks + assert: + that: + - cm_delete_firmware_group_1 is changed + - cm_delete_firmware_group_1.proposed == {} + - nm_delete_firmware_group_1 is changed + - nm_delete_firmware_group_1.previous != [] + - nm_delete_firmware_group_1.current == [] + - idempotency_delete_firmware_group_1 is not changed + - idempotency_delete_firmware_group_1.previous == [] + - nm_delete_firmware_group_2 is changed + - nm_delete_firmware_group_2.previous != [] + - nm_delete_firmware_group_2.current == [] + + - name: Delete firmware policy - clean up the environment + aci_firmware_policy: + <<: *aci_firmware_policy_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_group_node/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_group_node/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_group_node/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_group_node/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_group_node/tasks/main.yml new file mode 100644 index 000000000..8da20a7ca --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_group_node/tasks/main.yml @@ -0,0 +1,164 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Clean Environment + - name: Create firmware policy exists + aci_firmware_policy: &aci_firmware_policy_present + <<: *aci_info + name: anstest_policy + version: n9000-15.2(7) + state: present + + - name: Create first firmware group + aci_firmware_group: &aci_firmware_group_present + <<: *aci_info + group: anstest_group + firmwarepol: anstest_policy + state: present + + - name: Ensure first firmware group node does not exist + aci_firmware_group_node: &aci_firmware_group_node_absent + <<: *aci_info + group: anstest_group + node: 1001 + state: absent + + - name: Ensure second firmware group node does not exist + aci_firmware_group_node: &aci_firmware_group_node_2_absent + <<: *aci_info + group: anstest_group + node: 1002 + state: absent + + - name: Create first firmware group node (check_mode) + aci_firmware_group_node: &aci_firmware_group_node_present + <<: *aci_firmware_group_node_absent + state: present + check_mode: true + register: cm_add_firmware_group_node_1 + + - name: Create first firmware group node (normal_mode) + aci_firmware_group_node: + <<: *aci_firmware_group_node_present + register: nm_add_firmware_group_node_1 + + - name: Create first firmware group node again - testing idempotency + aci_firmware_group_node: + <<: *aci_firmware_group_node_present + register: idempotency_add_firmware_group_node_1 + + - name: Create second firmware group node + aci_firmware_group_node: &aci_firmware_group_node_2_present + <<: *aci_firmware_group_node_2_absent + state: present + register: nm_add_firmware_group_node_2 + + - name: Asserts for creation tasks + assert: + that: + - cm_add_firmware_group_node_1 is changed + - cm_add_firmware_group_node_1.previous == [] + - cm_add_firmware_group_node_1.current == [] + - nm_add_firmware_group_node_1 is changed + - nm_add_firmware_group_node_1.current.0.fabricNodeBlk.attributes.from_ == "1001" + - nm_add_firmware_group_node_1.current.0.fabricNodeBlk.attributes.to_ == "1001" + - idempotency_add_firmware_group_node_1 is not changed + - nm_add_firmware_group_node_2 is changed + - nm_add_firmware_group_node_2.current.0.fabricNodeBlk.attributes.from_ == "1002" + - nm_add_firmware_group_node_2.current.0.fabricNodeBlk.attributes.to_ == "1002" + + + - name: Query all firmware group nodes + aci_firmware_group_node: + <<: *aci_info + state: query + register: query_all_firmware_group_node + + - name: Query first firmware group nnode + aci_firmware_group_node: + <<: *aci_firmware_group_node_present + state: query + register: query_first_firmware_group_node + + - name: Asserts for query tasks + assert: + that: + - query_all_firmware_group_node is not changed + - query_all_firmware_group_node.current | length >= 2 + - '"class/fabricNodeBlk.json" in query_all_firmware_group_node.url' + - query_first_firmware_group_node is not changed + - query_first_firmware_group_node.current.0.fabricNodeBlk.attributes.from_ == "1001" + - query_first_firmware_group_node.current.0.fabricNodeBlk.attributes.to_ == "1001" + + - name: Delete first firmware group (check_mode) + aci_firmware_group_node: + <<: *aci_firmware_group_node_present + state: absent + check_mode: true + register: cm_delete_firmware_group_node_1 + + - name: Delete first firmware group (normal_mode) + aci_firmware_group_node: + <<: *aci_firmware_group_node_present + state: absent + register: nm_delete_firmware_group_node_1 + + - name: Delete first firmware group again - testing idempotency + aci_firmware_group_node: + <<: *aci_firmware_group_node_present + state: absent + register: idempotency_delete_firmware_group_1 + + - name: Delete second firmware group (normal_mode) + aci_firmware_group_node: + <<: *aci_firmware_group_node_2_present + state: absent + register: nm_delete_firmware_group_node_2 + + - name: Asserts for deletion tasks + assert: + that: + - cm_delete_firmware_group_node_1 is changed + - cm_delete_firmware_group_node_1.proposed == {} + - nm_delete_firmware_group_node_1 is changed + - nm_delete_firmware_group_node_1.previous != [] + - nm_delete_firmware_group_node_1.current == [] + - idempotency_delete_firmware_group_1 is not changed + - idempotency_delete_firmware_group_1.previous == [] + - nm_delete_firmware_group_node_2 is changed + - nm_delete_firmware_group_node_2.previous != [] + - nm_delete_firmware_group_node_2.current == [] + + - name: Delete firmware group - clean up the environment + aci_firmware_group: + <<: *aci_firmware_group_present + state: absent + + - name: Delete firmware policy - clean up the environment + aci_firmware_policy: + <<: *aci_firmware_policy_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_policy/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_policy/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_policy/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_policy/tasks/main.yml new file mode 100644 index 000000000..ec0bb88ae --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_policy/tasks/main.yml @@ -0,0 +1,143 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Clean Environment + - name: Ensure first firmware policy does not exist + aci_firmware_policy: &aci_firmware_policy_absent + <<: *aci_info + name: anstest_policy + version: n9000-15.2(7) + ignore_compat: true + state: absent + + - name: Ensure second firmware policy does not exist + aci_firmware_policy: &aci_firmware_policy_2_absent + <<: *aci_info + name: anstest_policy_2 + version: n9000-16.0(1) + state: absent + + - name: Create first firmware policy (check_mode) + aci_firmware_policy: &aci_firmware_policy_present + <<: *aci_firmware_policy_absent + state: present + check_mode: true + register: cm_add_firmware_policy_1 + + - name: Create first firmware policy (normal_mode) + aci_firmware_policy: + <<: *aci_firmware_policy_present + register: nm_add_firmware_policy_1 + + - name: Create first firmware policy again - testing idempotency + aci_firmware_policy: + <<: *aci_firmware_policy_present + register: idempotency_add_firmware_policy_1 + + - name: Create second firmware policy + aci_firmware_policy: &aci_firmware_policy_2_present + <<: *aci_firmware_policy_2_absent + state: present + register: nm_add_firmware_policy_2 + + - name: Asserts for creation tasks + assert: + that: + - cm_add_firmware_policy_1 is changed + - cm_add_firmware_policy_1.previous == [] + - cm_add_firmware_policy_1.current == [] + - nm_add_firmware_policy_1 is changed + - nm_add_firmware_policy_1.current.0.firmwareFwP.attributes.name == "anstest_policy" + - nm_add_firmware_policy_1.current.0.firmwareFwP.attributes.ignoreCompat == "yes" + - nm_add_firmware_policy_1.current.0.firmwareFwP.attributes.version == "n9000-15.2(7)" + - idempotency_add_firmware_policy_1 is not changed + - nm_add_firmware_policy_2 is changed + - nm_add_firmware_policy_2.current.0.firmwareFwP.attributes.name == "anstest_policy_2" + - nm_add_firmware_policy_2.current.0.firmwareFwP.attributes.ignoreCompat == "no" + - nm_add_firmware_policy_2.current.0.firmwareFwP.attributes.version == "n9000-16.0(1)" + + - name: Query all firmware policies + aci_firmware_policy: + <<: *aci_info + state: query + register: query_all_firmware_policy + + - name: Query first firmware policy + aci_firmware_policy: + <<: *aci_firmware_policy_present + state: query + register: query_first_firmware_policy + + - name: Asserts for query tasks + assert: + that: + - query_all_firmware_policy is not changed + - query_all_firmware_policy.current | length >= 2 + - '"class/firmwareFwP.json" in query_all_firmware_policy.url' + - query_first_firmware_policy is not changed + - query_first_firmware_policy.current.0.firmwareFwP.attributes.name == "anstest_policy" + - query_first_firmware_policy.current.0.firmwareFwP.attributes.ignoreCompat == "yes" + - query_first_firmware_policy.current.0.firmwareFwP.attributes.version == "n9000-15.2(7)" + + - name: Delete first firmware policy (check_mode) + aci_firmware_policy: + <<: *aci_firmware_policy_present + state: absent + check_mode: true + register: cm_delete_firmware_policy_1 + + - name: Delete first firmware policy (normal_mode) + aci_firmware_policy: + <<: *aci_firmware_policy_present + state: absent + register: nm_delete_firmware_policy_1 + + - name: Delete first firmware policy again - testing idempotency + aci_firmware_policy: + <<: *aci_firmware_policy_present + state: absent + register: idempotency_delete_firmware_policy_1 + + - name: Delete second firmware policy (normal_mode) + aci_firmware_policy: + <<: *aci_firmware_policy_2_present + state: absent + register: nm_delete_firmware_policy_2 + + - name: Asserts for deletion tasks + assert: + that: + - cm_delete_firmware_policy_1 is changed + - cm_delete_firmware_policy_1.proposed == {} + - nm_delete_firmware_policy_1 is changed + - nm_delete_firmware_policy_1.previous != [] + - nm_delete_firmware_policy_1.current == [] + - idempotency_delete_firmware_policy_1 is not changed + - idempotency_delete_firmware_policy_1.previous == [] + - nm_delete_firmware_policy_2 is changed + - nm_delete_firmware_policy_2.previous != [] + - nm_delete_firmware_policy_2.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_blacklist/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_blacklist/tasks/main.yml index d7b125267..17e0bb67c 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_blacklist/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_blacklist/tasks/main.yml @@ -45,6 +45,40 @@ - name: Execute tasks only for non-cloud sites when: query_cloud.current == [] # This condition will execute only non-cloud sites block: # block specifies execution of tasks within, based on conditions + + - name: Query blacklisted interfaces + cisco.aci.aci_interface_blacklist: + <<: *aci_info + state: query + register: enable_and_clear + + - name: set regex + set_fact: + regexp: '(topology/pod-)(\d)(/paths-)(\d*)(/pathep-\[eth)(.*)(])' + + - name: Save Target DNs + set_fact: + tdn: "{{ item.fabricRsOosPath.attributes.tDn }}" + loop: "{{ enable_and_clear.current }}" + register: enabled_tdn + + - name: Enable interfaces that were blacklisted + cisco.aci.aci_interface_blacklist: + <<: *aci_info + pod_id: "{{ item.ansible_facts.tdn | regex_search(regexp, '\\2') | first }}" + node_id: "{{ item.ansible_facts.tdn | regex_search(regexp, '\\4') | first }}" + interface: "{{ item.ansible_facts.tdn | regex_search(regexp, '\\6') | first }}" + state: absent + loop: "{{ enabled_tdn.results }}" + + - name: Ensure Interfaces are absent - Clean up test environment + cisco.aci.aci_interface_config: + <<: *aci_info + node: "{{ item.ansible_facts.tdn | regex_search(regexp, '\\4') | first }}" + interface: "{{ item.ansible_facts.tdn | regex_search(regexp, '\\6') | first }}" + state: absent + loop: "{{ enabled_tdn.results }}" + - name: Spine - Clean test environment with enabled interface cisco.aci.aci_interface_blacklist: <<: *aci_info diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_config/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_config/tasks/main.yml index 75253bd40..3e8ebcb82 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_config/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_config/tasks/main.yml @@ -42,7 +42,7 @@ role: leaf port_type: access interface_type: switch_port - interface: "1/1/1" + interface: "1/1" state: absent register: invalid_interface_absent ignore_errors: true @@ -68,7 +68,7 @@ policy_group: ans_test_switch_port node: 501 breakout: "100g-4x" - interface: "1/1/1" + interface: "1/1" state: present register: invalid_policy_group_with_breakout ignore_errors: true @@ -86,7 +86,7 @@ cisco.aci.aci_interface_config: <<: *aci_info node: 5000 - interface: "1/1/1" + interface: "1/1" state: present register: invalid_node ignore_errors: true @@ -141,7 +141,7 @@ - invalid_sub_port is not changed - invalid_sub_port.msg is match("^Sub Port ID{{':'}} .+? is invalid; it must be in the range of 0 to 16.") - - name: Ensure Interface 501 with leaf access with policy_group - switch_port absent + - name: Ensure Interface 501 with leaf access with policy_group and without sub port - switch_port absent cisco.aci.aci_interface_config: &interface_501_absent <<: *aci_info role: leaf @@ -149,20 +149,20 @@ interface_type: switch_port policy_group: ans_test_switch_port node: 501 - interface: "1/1/1" + interface: "1/1" description: "Interface - 501 added by Ansible" admin_state: "down" state: absent register: interface_501_absent - - name: Ensure Interface 501 with leaf access with policy_group - switch_port present - check mode + - name: Ensure Interface 501 with leaf access with policy_group and without sub port - switch_port present - check mode cisco.aci.aci_interface_config: &cm_interface_501_present <<: *interface_501_absent state: present check_mode: true register: cm_interface_501_present - - name: Ensure Interface 501 with leaf access with policy_group - switch_port present - normal mode + - name: Ensure Interface 501 with leaf access with policy_group and without sub port - switch_port present - normal mode cisco.aci.aci_interface_config: &nm_interface_501_present <<: *interface_501_absent state: present @@ -178,13 +178,13 @@ - nm_interface_501_present.current != [] - nm_interface_501_present.current.0.infraPortConfig.attributes.assocGrp == "uni/infra/funcprof/accportgrp-ans_test_switch_port" - nm_interface_501_present.current.0.infraPortConfig.attributes.brkoutMap == "none" - - nm_interface_501_present.current.0.infraPortConfig.attributes.dn == "uni/infra/portconfnode-501-card-1-port-1-sub-1" + - nm_interface_501_present.current.0.infraPortConfig.attributes.dn == "uni/infra/portconfnode-501-card-1-port-1-sub-0" - nm_interface_501_present.current.0.infraPortConfig.attributes.node == "501" - nm_interface_501_present.current.0.infraPortConfig.attributes.role == "leaf" - nm_interface_501_present.current.0.infraPortConfig.attributes.shutdown == "yes" - nm_interface_501_present.current.0.infraPortConfig.attributes.card == "1" - nm_interface_501_present.current.0.infraPortConfig.attributes.port == "1" - - nm_interface_501_present.current.0.infraPortConfig.attributes.subPort == "1" + - nm_interface_501_present.current.0.infraPortConfig.attributes.subPort == "0" - name: Ensure Interface 502 with leaf access with policy_group - pc_or_vpc absent cisco.aci.aci_interface_config: &interface_502_absent @@ -461,7 +461,7 @@ policy_group: ans_test_switch_port breakout: "100g-4x" node: 501 - interface: "1/1/1" + interface: "1/1" description: "Interface - 501 added by Ansible" state: present register: invalid_breakout_501_present @@ -475,7 +475,7 @@ interface_type: switch_port breakout: "100g-4x" node: 501 - interface: "1/1/1" + interface: "1/1" description: "Interface - 501 added by Ansible" admin_state: "down" state: present @@ -504,14 +504,14 @@ - nm_valid_breakout_501_present.current != [] - nm_valid_breakout_501_present.current.0.infraPortConfig.attributes.brkoutMap == "100g-4x" - nm_valid_breakout_501_present.current.0.infraPortConfig.attributes.description == "Interface - 501 added by Ansible" - - nm_valid_breakout_501_present.current.0.infraPortConfig.attributes.dn == "uni/infra/portconfnode-501-card-1-port-1-sub-1" + - nm_valid_breakout_501_present.current.0.infraPortConfig.attributes.dn == "uni/infra/portconfnode-501-card-1-port-1-sub-0" - nm_valid_breakout_501_present.current.0.infraPortConfig.attributes.role == "leaf" - nm_valid_breakout_501_present.current.0.infraPortConfig.attributes.shutdown == "yes" - idm_breakout_501_present is not changed - idm_breakout_501_present.current != [] - idm_breakout_501_present.current.0.infraPortConfig.attributes.brkoutMap == "100g-4x" - idm_breakout_501_present.current.0.infraPortConfig.attributes.description == "Interface - 501 added by Ansible" - - idm_breakout_501_present.current.0.infraPortConfig.attributes.dn == "uni/infra/portconfnode-501-card-1-port-1-sub-1" + - idm_breakout_501_present.current.0.infraPortConfig.attributes.dn == "uni/infra/portconfnode-501-card-1-port-1-sub-0" - idm_breakout_501_present.current.0.infraPortConfig.attributes.role == "leaf" - idm_breakout_501_present.current.0.infraPortConfig.attributes.shutdown == "yes" # Breakup part ends @@ -527,7 +527,7 @@ assert: that: - query_all_access_interfaces is not changed - - query_all_access_interfaces.current|length >= 6 + - query_all_access_interfaces.current|length >= 5 - name: Query all fabric interfaces cisco.aci.aci_interface_config: @@ -678,3 +678,19 @@ that: - query_interface_509 is not changed - query_interface_509.current == [] + + - name: Ensure Interfaces 50* are absent - Clean up test environment + cisco.aci.aci_interface_config: + <<: *aci_info + node: "{{ item.node }}" + interface: "{{ item.interface }}" + state: absent + with_items: + - { node: "501", interface: "1/1/1" } + - { node: "502", interface: "2/2/2" } + - { node: "503", interface: "1/1/1" } + - { node: "505", interface: "5/5/5" } + - { node: "506", interface: "6/6/6" } + - { node: "507", interface: "7/7/7" } + - { node: "508", interface: "8/8/8" } + - { node: "509", interface: "9/9/9" } diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_fc/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_fc/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_fc/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_fc/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_fc/tasks/main.yml new file mode 100644 index 000000000..5e039380e --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_fc/tasks/main.yml @@ -0,0 +1,160 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Clean Environment + - name: Ensure first fc interface policy does not exist + aci_interface_policy_fc: &aci_interface_policy_fc_absent + <<: *aci_info + name: anstest_policy + description: test for fc interface policy + port_mode: np + auto_max_speed: 16G + fill_pattern: arbff + buffer_credits: 32 + speed: 8G + trunk_mode: trunk-on + state: absent + + - name: Ensure second fc interface policy does not exist + aci_interface_policy_fc: &aci_interface_policy_fc_2_absent + <<: *aci_info + name: anstest_policy_2 + state: absent + + - name: Create first fc interface policy (check_mode) + aci_interface_policy_fc: &aci_interface_policy_fc_present + <<: *aci_interface_policy_fc_absent + state: present + check_mode: true + register: cm_add_interface_policy_fc_1 + + - name: Create first fc interface policy (normal_mode) + aci_interface_policy_fc: + <<: *aci_interface_policy_fc_present + register: nm_add_interface_policy_fc_1 + + - name: Create first fc interface policy again - testing idempotency + aci_interface_policy_fc: + <<: *aci_interface_policy_fc_present + register: idempotency_add_interface_policy_fc_1 + + - name: Create second fc interface policy + aci_interface_policy_fc: &aci_interface_policy_fc_2_present + <<: *aci_interface_policy_fc_2_absent + state: present + register: nm_add_interface_policy_fc_2 + + - name: Asserts for creation tasks + assert: + that: + - cm_add_interface_policy_fc_1 is changed + - cm_add_interface_policy_fc_1.previous == [] + - cm_add_interface_policy_fc_1.current == [] + - nm_add_interface_policy_fc_1 is changed + - nm_add_interface_policy_fc_1.current.0.fcIfPol.attributes.name == "anstest_policy" + - nm_add_interface_policy_fc_1.current.0.fcIfPol.attributes.portMode == "np" + - nm_add_interface_policy_fc_1.current.0.fcIfPol.attributes.automaxspeed == "16G" + - nm_add_interface_policy_fc_1.current.0.fcIfPol.attributes.fillPattern == "ARBFF" + - nm_add_interface_policy_fc_1.current.0.fcIfPol.attributes.rxBBCredit == "32" + - nm_add_interface_policy_fc_1.current.0.fcIfPol.attributes.speed == "8G" + - nm_add_interface_policy_fc_1.current.0.fcIfPol.attributes.trunkMode == "trunk-on" + - idempotency_add_interface_policy_fc_1 is not changed + - nm_add_interface_policy_fc_2 is changed + - nm_add_interface_policy_fc_2.current.0.fcIfPol.attributes.name == "anstest_policy_2" + - nm_add_interface_policy_fc_2.current.0.fcIfPol.attributes.portMode == "f" + - nm_add_interface_policy_fc_2.current.0.fcIfPol.attributes.automaxspeed == "32G" + - nm_add_interface_policy_fc_2.current.0.fcIfPol.attributes.fillPattern == "IDLE" + - nm_add_interface_policy_fc_2.current.0.fcIfPol.attributes.rxBBCredit == "64" + - nm_add_interface_policy_fc_2.current.0.fcIfPol.attributes.speed == "auto" + - nm_add_interface_policy_fc_2.current.0.fcIfPol.attributes.trunkMode == "trunk-off" + - idempotency_add_interface_policy_fc_1 is not changed + + - name: Query all fc interface policies + aci_interface_policy_fc: + <<: *aci_info + state: query + register: query_all_interface_policy_fc + + - name: Query first fc interface policy + aci_interface_policy_fc: + <<: *aci_interface_policy_fc_present + state: query + register: query_first_interface_policy_fc + + - name: Asserts for query tasks + assert: + that: + - query_all_interface_policy_fc is not changed + - query_all_interface_policy_fc.current | length >= 2 + - '"class/fcIfPol.json" in query_all_interface_policy_fc.url' + - query_first_interface_policy_fc is not changed + - query_first_interface_policy_fc.current.0.fcIfPol.attributes.name == "anstest_policy" + - query_first_interface_policy_fc.current.0.fcIfPol.attributes.portMode == "np" + - query_first_interface_policy_fc.current.0.fcIfPol.attributes.automaxspeed == "16G" + - query_first_interface_policy_fc.current.0.fcIfPol.attributes.fillPattern == "ARBFF" + - query_first_interface_policy_fc.current.0.fcIfPol.attributes.rxBBCredit == "32" + - query_first_interface_policy_fc.current.0.fcIfPol.attributes.speed == "8G" + - query_first_interface_policy_fc.current.0.fcIfPol.attributes.trunkMode == "trunk-on" + + - name: Delete first fc interface policy (check_mode) + aci_interface_policy_fc: + <<: *aci_interface_policy_fc_present + state: absent + check_mode: true + register: cm_delete_interface_policy_fc_1 + + - name: Delete first fc interface policy (normal_mode) + aci_interface_policy_fc: + <<: *aci_interface_policy_fc_present + state: absent + register: nm_delete_interface_policy_fc_1 + + - name: Delete first fc interface policy again - testing idempotency + aci_interface_policy_fc: + <<: *aci_interface_policy_fc_present + state: absent + register: idempotency_delete_interface_policy_fc_1 + + - name: Delete second fc interface policy (normal_mode) + aci_interface_policy_fc: + <<: *aci_interface_policy_fc_2_present + state: absent + register: nm_delete_interface_policy_fc_2 + + - name: Asserts for deletion tasks + assert: + that: + - cm_delete_interface_policy_fc_1 is changed + - cm_delete_interface_policy_fc_1.proposed == {} + - nm_delete_interface_policy_fc_1 is changed + - nm_delete_interface_policy_fc_1.previous != [] + - nm_delete_interface_policy_fc_1.current == [] + - idempotency_delete_interface_policy_fc_1 is not changed + - idempotency_delete_interface_policy_fc_1.previous == [] + - nm_delete_interface_policy_fc_2 is changed + - nm_delete_interface_policy_fc_2.previous != [] + - nm_delete_interface_policy_fc_2.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_l2/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_l2/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_l2/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_l2/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_l2/tasks/main.yml new file mode 100644 index 000000000..f52b74fdb --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_l2/tasks/main.yml @@ -0,0 +1,147 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Clean Environment + - name: Ensure first l2 interface policy does not exist + aci_interface_policy_l2: &aci_interface_policy_l2_absent + <<: *aci_info + name: anstest_policy + description: test for l2 interface policy + vlan_scope: portlocal + qinq: core + vepa: true + state: absent + + - name: Ensure second l2 interface policy does not exist + aci_interface_policy_l2: &aci_interface_policy_l2_2_absent + <<: *aci_info + name: anstest_policy_2 + state: absent + + - name: Create first l2 interface policy (check_mode) + aci_interface_policy_l2: &aci_interface_policy_l2_present + <<: *aci_interface_policy_l2_absent + state: present + check_mode: true + register: cm_add_interface_policy_l2_1 + + - name: Create first l2 interface policy (normal_mode) + aci_interface_policy_l2: + <<: *aci_interface_policy_l2_present + register: nm_add_interface_policy_l2_1 + + - name: Create first l2 interface policy again - testing idempotency + aci_interface_policy_l2: + <<: *aci_interface_policy_l2_present + register: idempotency_add_interface_policy_l2_1 + + - name: Create second l2 interface policy + aci_interface_policy_l2: &aci_interface_policy_l2_2_present + <<: *aci_interface_policy_l2_2_absent + state: present + register: nm_add_interface_policy_l2_2 + + - name: Asserts for creation tasks + assert: + that: + - cm_add_interface_policy_l2_1 is changed + - cm_add_interface_policy_l2_1.previous == [] + - cm_add_interface_policy_l2_1.current == [] + - nm_add_interface_policy_l2_1 is changed + - nm_add_interface_policy_l2_1.current.0.l2IfPol.attributes.name == "anstest_policy" + - nm_add_interface_policy_l2_1.current.0.l2IfPol.attributes.vlanScope == "portlocal" + - nm_add_interface_policy_l2_1.current.0.l2IfPol.attributes.qinq == "corePort" + - nm_add_interface_policy_l2_1.current.0.l2IfPol.attributes.vepa == "enabled" + - idempotency_add_interface_policy_l2_1 is not changed + - nm_add_interface_policy_l2_2 is changed + - nm_add_interface_policy_l2_2.current.0.l2IfPol.attributes.name == "anstest_policy_2" + - nm_add_interface_policy_l2_2.current.0.l2IfPol.attributes.vlanScope == "global" + - nm_add_interface_policy_l2_2.current.0.l2IfPol.attributes.qinq == "disabled" + - nm_add_interface_policy_l2_2.current.0.l2IfPol.attributes.vepa == "disabled" + + - name: Query all l2 interface policies + aci_interface_policy_l2: + <<: *aci_info + state: query + register: query_all_interface_policy_l2 + + - name: Query first l2 interface policy + aci_interface_policy_l2: + <<: *aci_interface_policy_l2_present + state: query + register: query_first_interface_policy_l2 + + - name: Asserts for query tasks + assert: + that: + - query_all_interface_policy_l2 is not changed + - query_all_interface_policy_l2.current | length >= 2 + - '"class/l2IfPol.json" in query_all_interface_policy_l2.url' + - query_first_interface_policy_l2 is not changed + - query_first_interface_policy_l2.current.0.l2IfPol.attributes.name == "anstest_policy" + - query_first_interface_policy_l2.current.0.l2IfPol.attributes.vlanScope == "portlocal" + - query_first_interface_policy_l2.current.0.l2IfPol.attributes.qinq == "corePort" + - query_first_interface_policy_l2.current.0.l2IfPol.attributes.vepa == "enabled" + + - name: Delete first l2 interface policy (check_mode) + aci_interface_policy_l2: + <<: *aci_interface_policy_l2_present + state: absent + check_mode: true + register: cm_delete_interface_policy_l2_1 + + - name: Delete first l2 interface policy (normal_mode) + aci_interface_policy_l2: + <<: *aci_interface_policy_l2_present + state: absent + register: nm_delete_interface_policy_l2_1 + + - name: Delete first l2 interface policy again - testing idempotency + aci_interface_policy_l2: + <<: *aci_interface_policy_l2_present + state: absent + register: idempotency_delete_interface_policy_l2_1 + + - name: Delete second l2 interface policy (normal_mode) + aci_interface_policy_l2: + <<: *aci_interface_policy_l2_2_present + state: absent + register: nm_delete_interface_policy_l2_2 + + - name: Asserts for deletion tasks + assert: + that: + - cm_delete_interface_policy_l2_1 is changed + - cm_delete_interface_policy_l2_1.proposed == {} + - nm_delete_interface_policy_l2_1 is changed + - nm_delete_interface_policy_l2_1.previous != [] + - nm_delete_interface_policy_l2_1.current == [] + - idempotency_delete_interface_policy_l2_1 is not changed + - idempotency_delete_interface_policy_l2_1.previous == [] + - nm_delete_interface_policy_l2_2 is changed + - nm_delete_interface_policy_l2_2.previous != [] + - nm_delete_interface_policy_l2_2.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_fc_policy_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_fc_policy_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_fc_policy_group/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_fc_policy_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_fc_policy_group/tasks/main.yml new file mode 100644 index 000000000..5a758bb3d --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_fc_policy_group/tasks/main.yml @@ -0,0 +1,231 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Anvitha Jain <anvjain@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + + # CLEAN ENVIRONMENT + - name: Making sure FC port policy group doesn't exist at beginning of test + cisco.aci.aci_interface_policy_leaf_fc_policy_group: &fc_absent + <<: *aci_info + lag_type: port + policy_group: fc_port_test + state: absent + + - name: Making sure FC PC policy group doesn't exist at beginning of test + cisco.aci.aci_interface_policy_leaf_fc_policy_group: &fc_pc_absent + <<: *aci_info + lag_type: port_channel + policy_group: fc_pc_test + state: absent + + # ADD Leaf Access FC Port Policy Group + - name: Adding a interface policy Leaf Access FC Port policy group - check mode works + cisco.aci.aci_interface_policy_leaf_fc_policy_group: &fc_present + <<: *aci_info + policy_group: fc_port_test + lag_type: port + fibre_channel_interface_policy: fibre_channel_interface_policy_test + attached_entity_profile: test_aep + state: present + check_mode: yes + register: intf_policy_leaf_access_fc_port_polgrp_check_mode_present + + - name: Adding a interface policy Leaf Access FC Port policy group - creation works + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *fc_present + register: intf_policy_leaf_access_fc_port_polgrp_present + + - name: Adding a interface policy Leaf Access FC Port policy group - idempotency works + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *fc_present + register: intf_policy_leaf_access_fc_port_polgrp_idempotent + + # UPDATE Leaf Access FC Port Policy Group + - name: Adding a interface policy Leaf Access FC Port policy group description - update works + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *fc_present + description: policygroup description + register: intf_policy_leaf_access_fc_port_polgrp_update + + - name: Verify present assertions for FC Port Policy Group + assert: + that: + - intf_policy_leaf_access_fc_port_polgrp_check_mode_present is changed + - intf_policy_leaf_access_fc_port_polgrp_present is changed + - intf_policy_leaf_access_fc_port_polgrp_present.previous == [] + - intf_policy_leaf_access_fc_port_polgrp_present.current[0].infraFcAccPortGrp.attributes.name == 'fc_port_test' + - intf_policy_leaf_access_fc_port_polgrp_present.current[0].infraFcAccPortGrp.children.0.infraRsFcAttEntP.attributes.tDn == 'uni/infra/attentp-test_aep' + - intf_policy_leaf_access_fc_port_polgrp_present.current[0].infraFcAccPortGrp.children.1.infraRsFcL2IfPol.attributes.tnFcIfPolName == 'fibre_channel_interface_policy_test' + - intf_policy_leaf_access_fc_port_polgrp_present.current[0].infraFcAccPortGrp.attributes.annotation == 'orchestrator:ansible' + - intf_policy_leaf_access_fc_port_polgrp_idempotent is not changed + - intf_policy_leaf_access_fc_port_polgrp_idempotent.sent == {} + - intf_policy_leaf_access_fc_port_polgrp_update is changed + - intf_policy_leaf_access_fc_port_polgrp_update.current[0].infraFcAccPortGrp.attributes.descr == 'policygroup description' + + # ADD Leaf Access FC PC Policy Group + - name: Adding a interface policy Leaf Access FC PC policy group - check mode works + cisco.aci.aci_interface_policy_leaf_fc_policy_group: &fc_pc_present + <<: *aci_info + policy_group: fc_pc_test + lag_type: port_channel + fibre_channel_interface_policy: fibre_channel_interface_policy_test + port_channel_policy: port_channel_policy_test + attached_entity_profile: policy_group_aep + state: present + check_mode: yes + register: intf_policy_leaf_access_fc_pc_polgrp_check_mode_present + + - name: Adding a interface policy Leaf Access FC PC policy group - creation works + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *fc_pc_present + register: intf_policy_leaf_access_fc_pc_polgrp_present + + - name: Adding a interface policy Leaf Access FC PC policy group - idempotency works + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *fc_pc_present + register: intf_policy_leaf_access_fc_pc_polgrp_idempotent + + # UPDATE Leaf Access FC PC Policy Group + - name: Adding a interface policy Leaf Access FC PC policy group description - update works + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *fc_pc_present + description: policygroup description + register: intf_policy_leaf_access_fc_pc_polgrp_update + + - name: Verify present assertions for FC PC Policy Group + assert: + that: + - intf_policy_leaf_access_fc_pc_polgrp_check_mode_present is changed + - intf_policy_leaf_access_fc_pc_polgrp_present is changed + - intf_policy_leaf_access_fc_pc_polgrp_present.previous == [] + - intf_policy_leaf_access_fc_pc_polgrp_present.current[0].infraFcAccBndlGrp.attributes.name == 'fc_pc_test' + - intf_policy_leaf_access_fc_pc_polgrp_present.current[0].infraFcAccBndlGrp.children.0.infraRsFcLagPol.attributes.tnLacpLagPolName == 'port_channel_policy_test' + - intf_policy_leaf_access_fc_pc_polgrp_present.current[0].infraFcAccBndlGrp.children.1.infraRsFcAttEntP.attributes.tDn == 'uni/infra/attentp-policy_group_aep' + - intf_policy_leaf_access_fc_pc_polgrp_present.current[0].infraFcAccBndlGrp.children.2.infraRsFcL2IfPol.attributes.tnFcIfPolName == 'fibre_channel_interface_policy_test' + - intf_policy_leaf_access_fc_pc_polgrp_present.current[0].infraFcAccBndlGrp.attributes.annotation == 'orchestrator:ansible' + - intf_policy_leaf_access_fc_pc_polgrp_idempotent is not changed + - intf_policy_leaf_access_fc_pc_polgrp_idempotent.sent == {} + - intf_policy_leaf_access_fc_pc_polgrp_update is changed + - intf_policy_leaf_access_fc_pc_polgrp_update.current[0].infraFcAccBndlGrp.attributes.descr == 'policygroup description' + + + # QUERY Leaf Access FC Port Policy Group + - name: Query all interface policy Leaf Access FC Port policy groups + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *aci_info + lag_type: port + state: query + register: query_all_leaf_access_fc_port_policy_groups + + - name: Query interface policy Leaf Access FC Port policy group + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *aci_info + policy_group: fc_port_test + lag_type: port + state: query + register: query_leaf_access_fc_port_policy_group + + - name: Verify query assertions for Leaf Access FC Port Policy Group + assert: + that: + - query_leaf_access_fc_port_policy_group is not changed + - query_leaf_access_fc_port_policy_group.current[0] | length >= 1 + - query_all_leaf_access_fc_port_policy_groups is not changed + + # QUERY Leaf Access FC PC Policy Group + - name: Query all interface policy Leaf Access FC PC policy groups + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *aci_info + lag_type: port_channel + state: query + register: query_all_leaf_access_fc_pc_policy_groups + + - name: Query interface policy Leaf Access FC PC policy group + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *aci_info + policy_group: fc_pc_test + lag_type: port_channel + state: query + register: query_leaf_access_fc_pc_policy_group + + - name: Verify query assertions for Leaf Access FC PC Policy Group + assert: + that: + - query_leaf_access_fc_pc_policy_group is not changed + - query_leaf_access_fc_pc_policy_group.current[0] | length >= 1 + - query_all_leaf_access_fc_pc_policy_groups is not changed + + # DELETE Leaf Access FC Port Policy Group + - name: Remove interface policy Leaf Access FC Port policy group - check mode + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *fc_absent + check_mode: yes + register: intf_policy_leaf_access_fc_port_polgrp_check_mode_absent + + - name: Remove interface policy Leaf Access FC Port policy group - delete works + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *fc_absent + register: intf_policy_leaf_access_fc_port_polgrp_absent + + - name: Remove interface policy Leaf Access FC Port policy group - idempotency works + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *fc_absent + register: intf_policy_leaf_access_fc_port_polgrp_absent_idempotent + + - name: Verify absent assertions for FC Port Policy Group + assert: + that: + - intf_policy_leaf_access_fc_port_polgrp_check_mode_absent is changed + - intf_policy_leaf_access_fc_port_polgrp_check_mode_absent.previous != [] + - intf_policy_leaf_access_fc_port_polgrp_absent is changed + - intf_policy_leaf_access_fc_port_polgrp_absent_idempotent is not changed + - intf_policy_leaf_access_fc_port_polgrp_absent_idempotent.previous == [] + + # DELETE Leaf Access FC PC Policy Group + - name: Remove interface policy Leaf Access FC PC policy group - check mode + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *fc_pc_absent + check_mode: yes + register: intf_policy_leaf_access_fc_pc_polgrp_check_mode_absent + + - name: Remove interface policy Leaf Access FC PC policy group - delete works + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *fc_pc_absent + register: intf_policy_leaf_access_fc_pc_polgrp_absent + + - name: Remove interface policy Leaf Access FC PC policy group - idempotency works + cisco.aci.aci_interface_policy_leaf_fc_policy_group: + <<: *fc_pc_absent + register: intf_policy_leaf_access_fc_pc_polgrp_absent_idempotent + + - name: Verify absent assertions for FC PC policy group + assert: + that: + - intf_policy_leaf_access_fc_pc_polgrp_check_mode_absent is changed + - intf_policy_leaf_access_fc_pc_polgrp_check_mode_absent.previous != [] + - intf_policy_leaf_access_fc_pc_polgrp_absent is changed + - intf_policy_leaf_access_fc_pc_polgrp_absent_idempotent is not changed + - intf_policy_leaf_access_fc_pc_polgrp_absent_idempotent.previous == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_policy_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_policy_group/tasks/main.yml index f94ba4e48..3f6e25505 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_policy_group/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_policy_group/tasks/main.yml @@ -1,4 +1,5 @@ # Test code for the ACI modules +# Copyright: (c) 2023, Anvitha Jain <anvjain@cisco.com> # Copyright: (c) 2017, Bruno Calogero <brunocalogero@hotmail.com> # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -8,6 +9,25 @@ msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined +# GET Credentials from the inventory +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: "{{ aci_validate_certs | default(false) }}" + use_ssl: "{{ aci_use_ssl | default(true) }}" + use_proxy: "{{ aci_use_proxy | default(true) }}" + output_level: debug + +- name: Query system information + cisco.aci.aci_system: + <<: *aci_info + id: 1 + state: query + register: version + - name: Verify Cloud and Non-Cloud Sites in use. include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml @@ -16,55 +36,30 @@ block: # block specifies execution of tasks within, based on conditions - name: Making sure interface_policy_leaf_policy_group doesn't exist at beginning of test (PC) cisco.aci.aci_interface_policy_leaf_policy_group: &aci_interface_policy_leaf_policy_group_link_absent - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + <<: *aci_info policy_group: policygroupname_link lag_type: link state: absent - name: Making sure interface_policy_leaf_policy_group doesn't exist at beginning of test (VPC) cisco.aci.aci_interface_policy_leaf_policy_group: &aci_interface_policy_leaf_policy_group_node_absent - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + <<: *aci_info policy_group: policygroupname_node lag_type: node state: absent - name: Making sure interface_policy_leaf_policy_group doesn't exist at beginning of test (Leaf Access Port) cisco.aci.aci_interface_policy_leaf_policy_group: &aci_interface_policy_leaf_policy_group_leaf_absent - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + <<: *aci_info policy_group: policygroupname_leaf lag_type: leaf state: absent - # ==== TESTING Port Channel (PC), lag_type: link ==== - name: Adding a interface policy leaf policy group (PC) - check mode works cisco.aci.aci_interface_policy_leaf_policy_group: &aci_interface_policy_leaf_policy_group_link_present - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + <<: *aci_info policy_group: policygroupname_link lag_type: link link_level_policy: linklevelpolicy @@ -90,7 +85,7 @@ register: intf_policy_leaf_polgrp_update # TODO: also test for errors - - name: present assertions + - name: present assertions for interface policy leaf policy group (PC) assert: that: - intf_policy_leaf_polgrp_check_mode_present is changed @@ -108,19 +103,13 @@ - name: Query interface policy leaf policy group (PC) cisco.aci.aci_interface_policy_leaf_policy_group: - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + <<: *aci_info policy_group: policygroupname_link lag_type: link state: query register: binding_query - - name: present assertions + - name: Query assertions for interface policy leaf policy group (PC) assert: that: - binding_query is not changed @@ -145,20 +134,14 @@ - name: Remove interface policy leaf policy group (PC) - check mode cisco.aci.aci_interface_policy_leaf_policy_group: - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + <<: *aci_info policy_group: policygroupname_link #lag_type: link state: absent ignore_errors: true register: intf_policy_leaf_polgrp_absent_missing_param - - name: absent assertions + - name: absent assertions for interface policy leaf policy group (PC) assert: that: - intf_policy_leaf_polgrp_check_mode_absent is changed @@ -181,13 +164,7 @@ - name: Adding a interface policy leaf policy group (VPC) - check mode works cisco.aci.aci_interface_policy_leaf_policy_group: &aci_interface_policy_leaf_policy_group_node_present - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + <<: *aci_info policy_group: policygroupname_node lag_type: node link_level_policy: linklevelpolicy @@ -213,7 +190,7 @@ register: intf_policy_leaf_polgrp_update # TODO: also test for errors - - name: present assertions + - name: present assertions for interface policy leaf policy group (VPC) assert: that: - intf_policy_leaf_polgrp_check_mode_present is changed @@ -231,19 +208,13 @@ - name: Query interface policy leaf policy group (VPC) cisco.aci.aci_interface_policy_leaf_policy_group: - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + <<: *aci_info policy_group: policygroupname_node lag_type: node state: query register: binding_query - - name: present assertions + - name: Query assertions for interface policy leaf policy group (VPC) assert: that: - binding_query is not changed @@ -258,18 +229,12 @@ - name: Query interface policy leaf policy group (VPC) cisco.aci.aci_interface_policy_leaf_policy_group: - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + <<: *aci_info lag_type: node state: query register: binding_query_node_all - - name: present assertions + - name: Query assertions for interface policy leaf policy group (VPC) assert: that: - binding_query_node_all is not changed @@ -293,22 +258,15 @@ <<: *aci_interface_policy_leaf_policy_group_node_absent register: intf_policy_leaf_polgrp_absent_idempotent - - name: Remove interface policy leaf policy group (VPC) - check mode + - name: Remove interface policy leaf policy group (VPC) - without lag_type cisco.aci.aci_interface_policy_leaf_policy_group: - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + <<: *aci_info policy_group: policygroupname_node - #lag_type: node state: absent ignore_errors: true register: intf_policy_leaf_polgrp_absent_missing_param - - name: absent assertions + - name: absent assertions for interface policy leaf policy group (VPC) assert: that: - intf_policy_leaf_polgrp_check_mode_absent is changed @@ -320,6 +278,18 @@ - intf_policy_leaf_polgrp_absent_missing_param is failed - 'intf_policy_leaf_polgrp_absent_missing_param.msg == "missing required arguments: lag_type"' + - name: Adding a interface policy leaf policy group (VPC) - port_channel_policy not supported error + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_link_present + port_authentication: "default" + ignore_errors: true + register: intf_policy_leaf_polgrp_pa_policy_error + + - name: VPC error assertions (adding invalid parameters) + assert: + that: + - intf_policy_leaf_polgrp_pa_policy_error.msg == 'port_authentication is not a valid parameter for link/node (Port Channel, Virtual Port Channel), if used assign null to it (port_authentication{{":"}} null).' + # ==== END TESTING Virtual Port Channel (VPC), lag_type: node ==== @@ -331,17 +301,12 @@ - name: Adding a interface policy leaf policy group (Leaf Access Port) - check mode works cisco.aci.aci_interface_policy_leaf_policy_group: &aci_interface_policy_leaf_policy_group_leaf_present - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + <<: *aci_info policy_group: policygroupname_leaf lag_type: leaf link_level_policy: linklevelpolicy fibre_channel_interface_policy: fiberchannelpolicy + aep: test_aep state: present check_mode: true register: intf_policy_leaf_polgrp_check_mode_present @@ -377,7 +342,7 @@ register: intf_policy_leaf_polgrp_pc_policy_error # TODO: also test for errors - - name: present assertions + - name: present assertions for interface policy leaf policy group (Leaf Access Port) assert: that: - intf_policy_leaf_polgrp_check_mode_present is changed @@ -386,6 +351,7 @@ - intf_policy_leaf_polgrp_present.sent.infraAccPortGrp.attributes.name == 'policygroupname_leaf' - intf_policy_leaf_polgrp_present.sent.infraAccPortGrp.children.0.infraRsFcIfPol.attributes.tnFcIfPolName == 'fiberchannelpolicy' - intf_policy_leaf_polgrp_present.sent.infraAccPortGrp.children.1.infraRsHIfPol.attributes.tnFabricHIfPolName == 'linklevelpolicy' + - intf_policy_leaf_polgrp_present.sent.infraAccPortGrp.children.2.infraRsAttEntP.attributes.tDn == "uni/infra/attentp-test_aep" - intf_policy_leaf_polgrp_idempotent is not changed - intf_policy_leaf_polgrp_idempotent.sent == {} - intf_policy_leaf_polgrp_update is changed @@ -395,24 +361,19 @@ - name: Query interface policy leaf policy group (Leaf Access Port) cisco.aci.aci_interface_policy_leaf_policy_group: - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + <<: *aci_info policy_group: policygroupname_leaf lag_type: leaf state: query register: binding_query - - name: present assertions + - name: Query assertions interface policy leaf policy group (Leaf Access Port) assert: that: - binding_query is not changed - binding_query.current | length >= 1 - '"/api/mo/uni/infra/funcprof/accportgrp-policygroupname_leaf.json" in binding_query.url' + - binding_query.current.0.infraAccPortGrp.children.14.infraRsAttEntP.attributes.tDn == "uni/infra/attentp-test_aep" - name: Remove interface policy leaf policy group (Leaf Access Port) - check mode cisco.aci.aci_interface_policy_leaf_policy_group: @@ -430,22 +391,15 @@ <<: *aci_interface_policy_leaf_policy_group_leaf_absent register: intf_policy_leaf_polgrp_absent_idempotent - - name: Remove interface policy leaf policy group (Leaf Access Port) - check mode + - name: Remove interface policy leaf policy group (Leaf Access Port) - without lag_type cisco.aci.aci_interface_policy_leaf_policy_group: - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + <<: *aci_info policy_group: policygroupname_leaf - #lag_type: leaf state: absent ignore_errors: true register: intf_policy_leaf_polgrp_absent_missing_param - - name: absent assertions + - name: absent assertions for interface policy leaf policy group (Leaf Access Port) assert: that: - intf_policy_leaf_polgrp_check_mode_absent is changed @@ -458,3 +412,129 @@ - 'intf_policy_leaf_polgrp_absent_missing_param.msg == "missing required arguments: lag_type"' # ==== END TESTING Virtual Port Channel (VPC), lag_type: leaf ==== + + + # ==== START TESTING PortCHannel (PC - lag_type: link), Virtual Port Channel (VPC - node: leaf) and Leaf Interface (lag_type: leaf) ==== + # ==== For parameters avaiable only for APIC versions > 5 ==== + + - name: Execute tasks only for the APIC version version > 5 + when: version.current.0.topSystem.attributes.version is version('5', '>') + block: + + # ==== TESTING Port Channel (PC) ==== + - name: Adding a interface policy leaf policy group (PC) - APIC version > 5 + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_link_present + sync_e_interface_policy: synceinterfacepolicy + state: present + register: intf_policy_leaf_policy_group_link_present_2 + + - name: present assertions (PC) for APIC version > 5 + assert: + that: + - intf_policy_leaf_policy_group_link_present_2 is changed + - intf_policy_leaf_policy_group_link_present_2.previous != [] + - intf_policy_leaf_policy_group_link_present_2.current[0].infraAccBndlGrp.attributes.name == 'policygroupname_link' + - intf_policy_leaf_policy_group_link_present_2.sent.infraAccBndlGrp.children.0.infraRsSynceEthIfPolBndlGrp.attributes.tnSynceEthIfPolName == 'synceinterfacepolicy' + + # ==== TESTING Leaf Interface ==== + - name: Adding a interface policy leaf policy group (Leaf Access Port) - APIC version > 5 + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_leaf_present + sync_e_interface_policy: synceinterfacepolicy + state: present + register: intf_policy_leaf_polgrp_present_2 + + - name: present assertions (Leaf Access Port) for APIC version > 5 + assert: + that: + - intf_policy_leaf_polgrp_present_2 is changed + - intf_policy_leaf_polgrp_present_2.previous == [] + - intf_policy_leaf_polgrp_present_2.sent.infraAccPortGrp.attributes.name == 'policygroupname_leaf' + - intf_policy_leaf_polgrp_present_2.sent.infraAccPortGrp.children.0.infraRsFcIfPol.attributes.tnFcIfPolName == 'fiberchannelpolicy' + - intf_policy_leaf_polgrp_present_2.sent.infraAccPortGrp.children.1.infraRsHIfPol.attributes.tnFabricHIfPolName == 'linklevelpolicy' + - intf_policy_leaf_polgrp_present_2.sent.infraAccPortGrp.children.2.infraRsAttEntP.attributes.tDn == 'uni/infra/attentp-test_aep' + - intf_policy_leaf_polgrp_present_2.sent.infraAccPortGrp.children.3.infraRsSynceEthIfPol.attributes.tnSynceEthIfPolName == 'synceinterfacepolicy' + + # ==== END TESTING for parameters avaiable only for APIC versions > 5 ==== + + + # ==== START TESTING PortCHannel (PC - lag_type: link), Virtual Port Channel (VPC - node: leaf) and Leaf Interface (lag_type: leaf) ==== + # ==== For parameters avaiable only for APIC versions >= 6 ==== + + - name: Execute tasks only for the APIC version version >= 6 + when: version.current.0.topSystem.attributes.version is version('6', '>=') + block: + # ==== TESTING Virtual Port Channel (VPC) ==== + - name: Adding a interface policy leaf policy group (VPC) - APIC version > 6 + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_node_present + sync_e_interface_policy: synceinterfacepolicy + state: present + register: intf_policy_leaf_policy_group_node_present_2 + + - name: present assertions (VPC) for APIC version > 6 + assert: + that: + - intf_policy_leaf_policy_group_node_present_2 is changed + - intf_policy_leaf_policy_group_node_present_2.previous == [] + - intf_policy_leaf_policy_group_node_present_2.current[0].infraAccBndlGrp.attributes.name == 'policygroupname_node' + - intf_policy_leaf_policy_group_node_present_2.sent.infraAccBndlGrp.children.0.infraRsFcIfPol.attributes.tnFcIfPolName == 'fiberchannelpolicy' + - intf_policy_leaf_policy_group_node_present_2.sent.infraAccBndlGrp.children.1.infraRsHIfPol.attributes.tnFabricHIfPolName == 'linklevelpolicy' + - intf_policy_leaf_policy_group_node_present_2.sent.infraAccBndlGrp.children.2.infraRsSynceEthIfPolBndlGrp.attributes.tnSynceEthIfPolName == 'synceinterfacepolicy' + + - name: Execute tasks only for the APIC version version >= 6.0.2 + when: version.current.0.topSystem.attributes.version is version('6.0(2h)', '>=') + block: + # ==== TESTING Leaf Interface ==== + - name: Adding a interface policy leaf policy group (Leaf Access Port) - APIC version >= 6.0.2 + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_leaf_present + transceiver_policy: + name: transceiverpolicy + type: zr + state: present + register: intf_policy_leaf_polgrp_present_3 + + - name: present assertions (Leaf Access Port) for APIC version >= 6.0.2 + assert: + that: + - intf_policy_leaf_polgrp_present_3 is changed + - intf_policy_leaf_polgrp_present_3.previous != [] + - intf_policy_leaf_polgrp_present_3.current[0].infraAccPortGrp.attributes.name == 'policygroupname_leaf' + - intf_policy_leaf_polgrp_present_3.sent.infraAccPortGrp.children.0.infraRsOpticsIfPol.attributes.tDn == 'uni/infra/zr-transceiverpolicy' + + - name: Adding all the policies for leaf policy group (Leaf Access Port) + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_leaf_present + cdp_policy: cdppolicy + mcp_policy: mcppolicy + lldp_policy: lldppolicy + stp_interface_policy: stppolicy + egress_data_plane_policing_policy: egressdataplanepolicingpolicy + ingress_data_plane_policing_policy: ingressdataplanepolicingpolicy + priority_flow_control_policy: priorityflowcontrolpolicy + slow_drain_policy: slowdrainpolicy + monitoring_policy: monitoringpolicy + storm_control_interface_policy: stormcontrolinterfacepolicy + l2_interface_policy: l2interfacepolicy + port_security_policy: portsecuritypolicy + link_flap_policy: linkflappolicy + link_level_flow_control: linklevelflowcontrol + mac_sec_interface_policy: macsecinterfacepolicy + copp_policy: copppolicy + dwdm: dwdmpolicy + port_authentication: portauthenticationpolicy + poe_interface_policy: poeinterfacepolicy + state: present + register: intf_policy_leaf_polgrp_all_policy_present + + - name: present assertions (Leaf Access Port) for all the policies. + assert: + that: + - intf_policy_leaf_polgrp_all_policy_present is changed + - intf_policy_leaf_polgrp_all_policy_present.previous != [] + - intf_policy_leaf_polgrp_all_policy_present.current[0].infraAccPortGrp.attributes.name == 'policygroupname_leaf' + - intf_policy_leaf_polgrp_all_policy_present.sent.infraAccPortGrp.children.0.infraRsCdpIfPol.attributes.tnCdpIfPolName == 'cdppolicy' + - intf_policy_leaf_polgrp_all_policy_present.sent.infraAccPortGrp.children.1.infraRsL2IfPol.attributes.tnL2IfPolName == 'l2interfacepolicy' + - intf_policy_leaf_polgrp_all_policy_present.sent.infraAccPortGrp.children.2.infraRsL2PortSecurityPol.attributes.tnL2PortSecurityPolName == 'portsecuritypolicy' diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_lldp/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_lldp/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_lldp/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_lldp/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_lldp/tasks/main.yml new file mode 100644 index 000000000..225e142ba --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_lldp/tasks/main.yml @@ -0,0 +1,143 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Clean Environment + - name: Ensure first lldp interface policy does not exist + aci_interface_policy_lldp: &aci_interface_policy_lldp_absent + <<: *aci_info + name: anstest_policy + description: test for lldp interface policy + receive_state: false + transmit_state: false + state: absent + + - name: Ensure second lldp interface policy does not exist + aci_interface_policy_lldp: &aci_interface_policy_lldp_2_absent + <<: *aci_info + name: anstest_policy_2 + state: absent + + - name: Create first lldp interface policy (check_mode) + aci_interface_policy_lldp: &aci_interface_policy_lldp_present + <<: *aci_interface_policy_lldp_absent + state: present + check_mode: true + register: cm_add_interface_policy_lldp_1 + + - name: Create first lldp interface policy (normal_mode) + aci_interface_policy_lldp: + <<: *aci_interface_policy_lldp_present + register: nm_add_interface_policy_lldp_1 + + - name: Create first lldp interface policy again - testing idempotency + aci_interface_policy_lldp: + <<: *aci_interface_policy_lldp_present + register: idempotency_add_interface_policy_lldp_1 + + - name: Create second lldp interface policy + aci_interface_policy_lldp: &aci_interface_policy_lldp_2_present + <<: *aci_interface_policy_lldp_2_absent + state: present + register: nm_add_interface_policy_lldp_2 + + - name: Asserts for creation tasks + assert: + that: + - cm_add_interface_policy_lldp_1 is changed + - cm_add_interface_policy_lldp_1.previous == [] + - cm_add_interface_policy_lldp_1.current == [] + - nm_add_interface_policy_lldp_1 is changed + - nm_add_interface_policy_lldp_1.current.0.lldpIfPol.attributes.name == "anstest_policy" + - nm_add_interface_policy_lldp_1.current.0.lldpIfPol.attributes.adminRxSt == "disabled" + - nm_add_interface_policy_lldp_1.current.0.lldpIfPol.attributes.adminTxSt == "disabled" + - idempotency_add_interface_policy_lldp_1 is not changed + - nm_add_interface_policy_lldp_2 is changed + - nm_add_interface_policy_lldp_2.current.0.lldpIfPol.attributes.name == "anstest_policy_2" + - nm_add_interface_policy_lldp_2.current.0.lldpIfPol.attributes.adminRxSt == "enabled" + - nm_add_interface_policy_lldp_2.current.0.lldpIfPol.attributes.adminTxSt == "enabled" + + - name: Query all lldp interface policies + aci_interface_policy_lldp: + <<: *aci_info + state: query + register: query_all_interface_policy_lldp + + - name: Query first lldp interface policy + aci_interface_policy_lldp: + <<: *aci_interface_policy_lldp_present + state: query + register: query_first_interface_policy_lldp + + - name: Asserts for query tasks + assert: + that: + - query_all_interface_policy_lldp is not changed + - query_all_interface_policy_lldp.current | length >= 2 + - '"class/lldpIfPol.json" in query_all_interface_policy_lldp.url' + - query_first_interface_policy_lldp is not changed + - query_first_interface_policy_lldp.current.0.lldpIfPol.attributes.name == "anstest_policy" + - query_first_interface_policy_lldp.current.0.lldpIfPol.attributes.adminRxSt == "disabled" + - query_first_interface_policy_lldp.current.0.lldpIfPol.attributes.adminTxSt == "disabled" + + - name: Delete first lldp interface policy (check_mode) + aci_interface_policy_lldp: + <<: *aci_interface_policy_lldp_present + state: absent + check_mode: true + register: cm_delete_interface_policy_lldp_1 + + - name: Delete first lldp interface policy (normal_mode) + aci_interface_policy_lldp: + <<: *aci_interface_policy_lldp_present + state: absent + register: nm_delete_interface_policy_lldp_1 + + - name: Delete first lldp interface policy again - testing idempotency + aci_interface_policy_lldp: + <<: *aci_interface_policy_lldp_present + state: absent + register: idempotency_delete_interface_policy_lldp_1 + + - name: Delete second lldp interface policy (normal_mode) + aci_interface_policy_lldp: + <<: *aci_interface_policy_lldp_2_present + state: absent + register: nm_delete_interface_policy_lldp_2 + + - name: Asserts for deletion tasks + assert: + that: + - cm_delete_interface_policy_lldp_1 is changed + - cm_delete_interface_policy_lldp_1.proposed == {} + - nm_delete_interface_policy_lldp_1 is changed + - nm_delete_interface_policy_lldp_1.previous != [] + - nm_delete_interface_policy_lldp_1.current == [] + - idempotency_delete_interface_policy_lldp_1 is not changed + - idempotency_delete_interface_policy_lldp_1.previous == [] + - nm_delete_interface_policy_lldp_2 is changed + - nm_delete_interface_policy_lldp_2.previous != [] + - nm_delete_interface_policy_lldp_2.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_mcp/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_mcp/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_mcp/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_mcp/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_mcp/tasks/main.yml new file mode 100644 index 000000000..7255c14ad --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_mcp/tasks/main.yml @@ -0,0 +1,255 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Clean Environment + - name: Ensure first mcp interface policy does not exist - APIC version >= 5.0 + aci_interface_policy_mcp: &aci_interface_policy_mcp_absent_5 + <<: *aci_info + name: anstest_policy + description: test for mcp interface policy + mcp_mode: strict + grace_period: 4 + grace_period_millisec: 500 + init_delay_time: 5 + tx_frequence: 2 + tx_frequence_millisec: 500 + admin_state: false + state: absent + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + - name: Ensure first mcp interface policy does not exist + aci_interface_policy_mcp: &aci_interface_policy_mcp_absent + <<: *aci_info + name: anstest_policy + description: test for mcp interface policy + admin_state: false + state: absent + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: Ensure second mcp interface policy does not exist + aci_interface_policy_mcp: &aci_interface_policy_mcp_2_absent + <<: *aci_info + name: anstest_policy_2 + state: absent + + - name: Create first mcp interface policy (check_mode) - APIC version >= 5.0 + aci_interface_policy_mcp: &aci_interface_policy_mcp_present_5 + <<: *aci_interface_policy_mcp_absent_5 + state: present + check_mode: true + register: cm_add_interface_policy_mcp_1_5 + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + - name: Create first mcp interface policy (normal_mode) - APIC version >= 5.0 + aci_interface_policy_mcp: + <<: *aci_interface_policy_mcp_present_5 + register: nm_add_interface_policy_mcp_1_5 + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + - name: Create first mcp interface policy again - testing idempotency - APIC version >= 5.0 + aci_interface_policy_mcp: + <<: *aci_interface_policy_mcp_present_5 + register: idempotency_add_interface_policy_mcp_1_5 + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + - name: Create first mcp interface policy (check_mode) - APIC version < 5.0 + aci_interface_policy_mcp: &aci_interface_policy_mcp_present + <<: *aci_interface_policy_mcp_absent + state: present + check_mode: true + register: cm_add_interface_policy_mcp_1 + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: Create first mcp interface policy (normal_mode) - APIC version < 5.0 + aci_interface_policy_mcp: + <<: *aci_interface_policy_mcp_present + register: nm_add_interface_policy_mcp_1 + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: Create first mcp interface policy again - testing idempotency - APIC version < 5.0 + aci_interface_policy_mcp: + <<: *aci_interface_policy_mcp_present + register: idempotency_add_interface_policy_mcp_1 + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: Create second mcp interface policy + aci_interface_policy_mcp: &aci_interface_policy_mcp_2_present + <<: *aci_interface_policy_mcp_2_absent + state: present + register: nm_add_interface_policy_mcp_2 + + - name: Asserts for creation tasks for first mcp interface policy - APIC version >= 5.0 + assert: + that: + - cm_add_interface_policy_mcp_1_5 is changed + - cm_add_interface_policy_mcp_1_5.previous == [] + - cm_add_interface_policy_mcp_1_5.current == [] + - nm_add_interface_policy_mcp_1_5 is changed + - nm_add_interface_policy_mcp_1_5.current.0.mcpIfPol.attributes.name == "anstest_policy" + - nm_add_interface_policy_mcp_1_5.current.0.mcpIfPol.attributes.adminSt == "disabled" + - idempotency_add_interface_policy_mcp_1_5 is not changed + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + - name: Asserts for creation tasks for first mcp interface policy - APIC version < 5.0 + assert: + that: + - cm_add_interface_policy_mcp_1 is changed + - cm_add_interface_policy_mcp_1.previous == [] + - cm_add_interface_policy_mcp_1.current == [] + - nm_add_interface_policy_mcp_1 is changed + - nm_add_interface_policy_mcp_1.current.0.mcpIfPol.attributes.name == "anstest_policy" + - nm_add_interface_policy_mcp_1.current.0.mcpIfPol.attributes.adminSt == "disabled" + - idempotency_add_interface_policy_mcp_1 is not changed + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: Asserts for creation tasks for second mcp interface policy + assert: + that: + - nm_add_interface_policy_mcp_2 is changed + - nm_add_interface_policy_mcp_2.current.0.mcpIfPol.attributes.name == "anstest_policy_2" + - nm_add_interface_policy_mcp_2.current.0.mcpIfPol.attributes.adminSt == "enabled" + + - name: Query all mcp interface policies + aci_interface_policy_mcp: + <<: *aci_info + state: query + register: query_all_interface_policy_mcp + + - name: Query first mcp interface policy + aci_interface_policy_mcp: + <<: *aci_interface_policy_mcp_present_5 + state: query + register: query_first_interface_policy_mcp_5 + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + - name: Query first mcp interface policy + aci_interface_policy_mcp: + <<: *aci_interface_policy_mcp_present + state: query + register: query_first_interface_policy_mcp + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: Asserts for query tasks + assert: + that: + - query_all_interface_policy_mcp is not changed + - query_all_interface_policy_mcp.current | length >= 2 + - '"class/mcpIfPol.json" in query_all_interface_policy_mcp.url' + + - name: Asserts for individual query tasks - APIC version >= 5.0 + assert: + that: + - query_first_interface_policy_mcp_5.current.0.mcpIfPol.attributes.name == "anstest_policy" + - query_first_interface_policy_mcp_5.current.0.mcpIfPol.attributes.adminSt == "disabled" + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + - name: Asserts for individual query tasks - APIC version < 5.0 + assert: + that: + - query_first_interface_policy_mcp.current.0.mcpIfPol.attributes.name == "anstest_policy" + - query_first_interface_policy_mcp.current.0.mcpIfPol.attributes.adminSt == "disabled" + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: Delete first mcp interface policy (check_mode) - APIC version >= 5.0 + aci_interface_policy_mcp: + <<: *aci_interface_policy_mcp_present_5 + state: absent + check_mode: true + register: cm_delete_interface_policy_mcp_1_5 + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + - name: Delete first mcp interface policy (normal_mode) - APIC version >= 5.0 + aci_interface_policy_mcp: + <<: *aci_interface_policy_mcp_present_5 + state: absent + register: nm_delete_interface_policy_mcp_1_5 + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + - name: Delete first mcp interface policy again - testing idempotency - APIC version >= 5.0 + aci_interface_policy_mcp: + <<: *aci_interface_policy_mcp_present_5 + state: absent + register: idempotency_delete_interface_policy_mcp_1_5 + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + - name: Delete first mcp interface policy (check_mode) - APIC version < 5.0 + aci_interface_policy_mcp: + <<: *aci_interface_policy_mcp_present + state: absent + check_mode: true + register: cm_delete_interface_policy_mcp_1 + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: Delete first mcp interface policy (normal_mode) - APIC version < 5.0 + aci_interface_policy_mcp: + <<: *aci_interface_policy_mcp_present + state: absent + register: nm_delete_interface_policy_mcp_1 + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: Delete first mcp interface policy again - testing idempotency - APIC version < 5.0 + aci_interface_policy_mcp: + <<: *aci_interface_policy_mcp_present + state: absent + register: idempotency_delete_interface_policy_mcp_1 + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: Delete second mcp interface policy (normal_mode) + aci_interface_policy_mcp: + <<: *aci_interface_policy_mcp_2_present + state: absent + register: nm_delete_interface_policy_mcp_2 + + - name: Asserts for first mcp interface policy deletion tasks - APIC version >= 5.0 + assert: + that: + - cm_delete_interface_policy_mcp_1_5 is changed + - cm_delete_interface_policy_mcp_1_5.proposed == {} + - nm_delete_interface_policy_mcp_1_5 is changed + - nm_delete_interface_policy_mcp_1_5.previous != [] + - nm_delete_interface_policy_mcp_1_5.current == [] + - idempotency_delete_interface_policy_mcp_1_5 is not changed + - idempotency_delete_interface_policy_mcp_1_5.previous == [] + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + - name: Asserts for first mcp interface policy deletion tasks - APIC version < 5.0 + assert: + that: + - cm_delete_interface_policy_mcp_1 is changed + - cm_delete_interface_policy_mcp_1.proposed == {} + - nm_delete_interface_policy_mcp_1 is changed + - nm_delete_interface_policy_mcp_1.previous != [] + - nm_delete_interface_policy_mcp_1.current == [] + - idempotency_delete_interface_policy_mcp_1 is not changed + - idempotency_delete_interface_policy_mcp_1.previous == [] + when: version.current.0.topSystem.attributes.version is version('5', '<') + + - name: Asserts for second mcp interface policy deletion tasks + assert: + that: + - nm_delete_interface_policy_mcp_2.previous != [] + - nm_delete_interface_policy_mcp_2.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_ospf/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_ospf/tasks/main.yml index 96a5472f0..71e096435 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_ospf/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_ospf/tasks/main.yml @@ -8,47 +8,33 @@ msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined +- name: Set vars + set_fact: + aci_info: &aci_info + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug # CLEAN ENVIRONMENT - name: Ensure tenant exists for tests to kick off cisco.aci.aci_tenant: &aci_tenant_present - host: "{{ aci_hostname }}" - username: "{{ aci_username }}" - password: "{{ aci_password }}" - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + <<: *aci_info tenant: ansible_test - state: present - register: tenant_present - name: Remove OSPF interface policy cisco.aci.aci_interface_policy_ospf: &interface_policy_ospf_absent - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' - tenant: ansible_test + <<: *aci_tenant_present ospf: ansible_ospf state: absent - # ADD OSPF INTERFACE POLICY - name: Add ospf interface policy (check_mode) cisco.aci.aci_interface_policy_ospf: &interface_policy_ospf_present - host: '{{ aci_hostname }}' - username: '{{ aci_username }}' - password: '{{ aci_password }}' - validate_certs: '{{ aci_validate_certs | default(false) }}' - use_ssl: '{{ aci_use_ssl | default(true) }}' - use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' - tenant: ansible_test - ospf: ansible_ospf + <<: *interface_policy_ospf_absent state: present check_mode: true register: cm_add_ospf_interface_policy @@ -70,47 +56,220 @@ assert: that: - cm_add_ospf_interface_policy is changed + - cm_add_ospf_interface_policy.current == [] + - cm_add_ospf_interface_policy.proposed.ospfIfPol.attributes.annotation == "orchestrator:ansible" + - cm_add_ospf_interface_policy.proposed.ospfIfPol.attributes.name == "ansible_ospf" - nm_add_ospf_interface_policy is changed - - nm_add_ospf_interface_policy.current.0.ospfIfPol.attributes.annotation == 'orchestrator:ansible' + - cm_add_ospf_interface_policy.previous == [] + - nm_add_ospf_interface_policy.current.0.ospfIfPol.attributes.annotation == "orchestrator:ansible" + - nm_add_ospf_interface_policy.current.0.ospfIfPol.attributes.descr == "" + - nm_add_ospf_interface_policy.current.0.ospfIfPol.attributes.name == "ansible_ospf" + - nm_add_ospf_interface_policy.current.0.ospfIfPol.attributes.cost == "unspecified" + - nm_add_ospf_interface_policy.current.0.ospfIfPol.attributes.ctrl == "" + - nm_add_ospf_interface_policy.current.0.ospfIfPol.attributes.deadIntvl == "40" + - nm_add_ospf_interface_policy.current.0.ospfIfPol.attributes.helloIntvl == "10" + - nm_add_ospf_interface_policy.current.0.ospfIfPol.attributes.nwT == "unspecified" + - nm_add_ospf_interface_policy.current.0.ospfIfPol.attributes.pfxSuppress == "inherit" + - nm_add_ospf_interface_policy.current.0.ospfIfPol.attributes.prio == "1" + - nm_add_ospf_interface_policy.current.0.ospfIfPol.attributes.rexmitIntvl == "5" + - nm_add_ospf_interface_policy.current.0.ospfIfPol.attributes.xmitDelay == "1" - cm_add_ospf_interface_policy_again is not changed - nm_add_ospf_interface_policy_again is not changed - + - nm_add_ospf_interface_policy_again.previous.0.ospfIfPol.attributes.annotation == "orchestrator:ansible" + - nm_add_ospf_interface_policy_again.previous.0.ospfIfPol.attributes.descr == "" + - nm_add_ospf_interface_policy_again.previous.0.ospfIfPol.attributes.name == "ansible_ospf" + - nm_add_ospf_interface_policy_again.previous.0.ospfIfPol.attributes.cost == "unspecified" + - nm_add_ospf_interface_policy_again.previous.0.ospfIfPol.attributes.ctrl == "" + - nm_add_ospf_interface_policy_again.previous.0.ospfIfPol.attributes.deadIntvl == "40" + - nm_add_ospf_interface_policy_again.previous.0.ospfIfPol.attributes.helloIntvl == "10" + - nm_add_ospf_interface_policy_again.previous.0.ospfIfPol.attributes.nwT == "unspecified" + - nm_add_ospf_interface_policy_again.previous.0.ospfIfPol.attributes.pfxSuppress == "inherit" + - nm_add_ospf_interface_policy_again.previous.0.ospfIfPol.attributes.prio == "1" + - nm_add_ospf_interface_policy_again.previous.0.ospfIfPol.attributes.rexmitIntvl == "5" + - nm_add_ospf_interface_policy_again.previous.0.ospfIfPol.attributes.xmitDelay == "1" + - nm_add_ospf_interface_policy_again.current.0.ospfIfPol.attributes.annotation == "orchestrator:ansible" + - nm_add_ospf_interface_policy_again.current.0.ospfIfPol.attributes.descr == "" + - nm_add_ospf_interface_policy_again.current.0.ospfIfPol.attributes.name == "ansible_ospf" + - nm_add_ospf_interface_policy_again.current.0.ospfIfPol.attributes.cost == "unspecified" + - nm_add_ospf_interface_policy_again.current.0.ospfIfPol.attributes.ctrl == "" + - nm_add_ospf_interface_policy_again.current.0.ospfIfPol.attributes.deadIntvl == "40" + - nm_add_ospf_interface_policy_again.current.0.ospfIfPol.attributes.helloIntvl == "10" + - nm_add_ospf_interface_policy_again.current.0.ospfIfPol.attributes.nwT == "unspecified" + - nm_add_ospf_interface_policy_again.current.0.ospfIfPol.attributes.pfxSuppress == "inherit" + - nm_add_ospf_interface_policy_again.current.0.ospfIfPol.attributes.prio == "1" + - nm_add_ospf_interface_policy_again.current.0.ospfIfPol.attributes.rexmitIntvl == "5" + - nm_add_ospf_interface_policy_again.current.0.ospfIfPol.attributes.xmitDelay == "1" # CHANGE OSPF INTERFACE POLICY - name: Change description of ospf interface policy (check_mode) - cisco.aci.aci_interface_policy_ospf: + cisco.aci.aci_interface_policy_ospf: &change_osp_interface_policy <<: *interface_policy_ospf_present - description: Ansible test ospf interface policy + description: Ansible test ospf interface policy changed + network_type: bcast + cost: 11 + controls: mtu-ignore + dead_interval: 12 + hello_interval: 13 + prefix_suppression: disable + priority: 14 + retransmit_interval: 15 + transmit_delay: 16 check_mode: true register: cm_add_ospf_descr - name: Change description of ospf interface policy (normal mode) cisco.aci.aci_interface_policy_ospf: - <<: *interface_policy_ospf_present - description: Ansible test ospf interface policy + <<: *change_osp_interface_policy register: nm_add_ospf_descr - name: Change description of ospf interface policy again (check_mode) cisco.aci.aci_interface_policy_ospf: - <<: *interface_policy_ospf_present - description: Ansible test ospf interface policy + <<: *change_osp_interface_policy check_mode: true register: cm_add_ospf_descr_again - name: Change description of ospf interface policy again (normal mode) cisco.aci.aci_interface_policy_ospf: - <<: *interface_policy_ospf_present - description: Ansible test ospf interface policy + <<: *change_osp_interface_policy register: nm_add_ospf_descr_again - name: Verify add_ospf_descr assert: that: - cm_add_ospf_descr is changed + - cm_add_ospf_descr.previous.0.ospfIfPol.attributes.annotation == "orchestrator:ansible" + - cm_add_ospf_descr.previous.0.ospfIfPol.attributes.descr == "" + - cm_add_ospf_descr.previous.0.ospfIfPol.attributes.name == "ansible_ospf" + - cm_add_ospf_descr.previous.0.ospfIfPol.attributes.cost == "unspecified" + - cm_add_ospf_descr.previous.0.ospfIfPol.attributes.ctrl == "" + - cm_add_ospf_descr.previous.0.ospfIfPol.attributes.deadIntvl == "40" + - cm_add_ospf_descr.previous.0.ospfIfPol.attributes.helloIntvl == "10" + - cm_add_ospf_descr.previous.0.ospfIfPol.attributes.nwT == "unspecified" + - cm_add_ospf_descr.previous.0.ospfIfPol.attributes.pfxSuppress == "inherit" + - cm_add_ospf_descr.previous.0.ospfIfPol.attributes.prio == "1" + - cm_add_ospf_descr.previous.0.ospfIfPol.attributes.rexmitIntvl == "5" + - cm_add_ospf_descr.previous.0.ospfIfPol.attributes.xmitDelay == "1" + - cm_add_ospf_descr.proposed.ospfIfPol.attributes.annotation == "orchestrator:ansible" + - cm_add_ospf_descr.proposed.ospfIfPol.attributes.descr == "Ansible test ospf interface policy changed" + - cm_add_ospf_descr.proposed.ospfIfPol.attributes.name == "ansible_ospf" + - cm_add_ospf_descr.proposed.ospfIfPol.attributes.cost == "11" + - cm_add_ospf_descr.proposed.ospfIfPol.attributes.ctrl == "mtu-ignore" + - cm_add_ospf_descr.proposed.ospfIfPol.attributes.deadIntvl == "12" + - cm_add_ospf_descr.proposed.ospfIfPol.attributes.helloIntvl == "13" + - cm_add_ospf_descr.proposed.ospfIfPol.attributes.nwT == "bcast" + - cm_add_ospf_descr.proposed.ospfIfPol.attributes.pfxSuppress == "disable" + - cm_add_ospf_descr.proposed.ospfIfPol.attributes.prio == "14" + - cm_add_ospf_descr.proposed.ospfIfPol.attributes.rexmitIntvl == "15" + - cm_add_ospf_descr.proposed.ospfIfPol.attributes.xmitDelay == "16" - nm_add_ospf_descr is changed + - nm_add_ospf_descr.previous.0.ospfIfPol.attributes.annotation == "orchestrator:ansible" + - nm_add_ospf_descr.previous.0.ospfIfPol.attributes.descr == "" + - nm_add_ospf_descr.previous.0.ospfIfPol.attributes.name == "ansible_ospf" + - nm_add_ospf_descr.previous.0.ospfIfPol.attributes.cost == "unspecified" + - nm_add_ospf_descr.previous.0.ospfIfPol.attributes.ctrl == "" + - nm_add_ospf_descr.previous.0.ospfIfPol.attributes.deadIntvl == "40" + - nm_add_ospf_descr.previous.0.ospfIfPol.attributes.helloIntvl == "10" + - nm_add_ospf_descr.previous.0.ospfIfPol.attributes.nwT == "unspecified" + - nm_add_ospf_descr.previous.0.ospfIfPol.attributes.pfxSuppress == "inherit" + - nm_add_ospf_descr.previous.0.ospfIfPol.attributes.prio == "1" + - nm_add_ospf_descr.previous.0.ospfIfPol.attributes.rexmitIntvl == "5" + - nm_add_ospf_descr.previous.0.ospfIfPol.attributes.xmitDelay == "1" + - nm_add_ospf_descr.current.0.ospfIfPol.attributes.annotation == "orchestrator:ansible" + - nm_add_ospf_descr.current.0.ospfIfPol.attributes.descr == "Ansible test ospf interface policy changed" + - nm_add_ospf_descr.current.0.ospfIfPol.attributes.name == "ansible_ospf" + - nm_add_ospf_descr.current.0.ospfIfPol.attributes.cost == "11" + - nm_add_ospf_descr.current.0.ospfIfPol.attributes.ctrl == "mtu-ignore" + - nm_add_ospf_descr.current.0.ospfIfPol.attributes.deadIntvl == "12" + - nm_add_ospf_descr.current.0.ospfIfPol.attributes.helloIntvl == "13" + - nm_add_ospf_descr.current.0.ospfIfPol.attributes.nwT == "bcast" + - nm_add_ospf_descr.current.0.ospfIfPol.attributes.pfxSuppress == "disable" + - nm_add_ospf_descr.current.0.ospfIfPol.attributes.prio == "14" + - nm_add_ospf_descr.current.0.ospfIfPol.attributes.rexmitIntvl == "15" + - nm_add_ospf_descr.current.0.ospfIfPol.attributes.xmitDelay == "16" - cm_add_ospf_descr_again is not changed - nm_add_ospf_descr_again is not changed + - nm_add_ospf_descr_again.previous.0.ospfIfPol.attributes.annotation == "orchestrator:ansible" + - nm_add_ospf_descr_again.previous.0.ospfIfPol.attributes.descr == "Ansible test ospf interface policy changed" + - nm_add_ospf_descr_again.previous.0.ospfIfPol.attributes.name == "ansible_ospf" + - nm_add_ospf_descr_again.previous.0.ospfIfPol.attributes.cost == "11" + - nm_add_ospf_descr_again.previous.0.ospfIfPol.attributes.ctrl == "mtu-ignore" + - nm_add_ospf_descr_again.previous.0.ospfIfPol.attributes.deadIntvl == "12" + - nm_add_ospf_descr_again.previous.0.ospfIfPol.attributes.helloIntvl == "13" + - nm_add_ospf_descr_again.previous.0.ospfIfPol.attributes.nwT == "bcast" + - nm_add_ospf_descr_again.previous.0.ospfIfPol.attributes.pfxSuppress == "disable" + - nm_add_ospf_descr_again.previous.0.ospfIfPol.attributes.prio == "14" + - nm_add_ospf_descr_again.previous.0.ospfIfPol.attributes.rexmitIntvl == "15" + - nm_add_ospf_descr_again.previous.0.ospfIfPol.attributes.xmitDelay == "16" + - nm_add_ospf_descr_again.current.0.ospfIfPol.attributes.annotation == "orchestrator:ansible" + - nm_add_ospf_descr_again.current.0.ospfIfPol.attributes.descr == "Ansible test ospf interface policy changed" + - nm_add_ospf_descr_again.current.0.ospfIfPol.attributes.name == "ansible_ospf" + - nm_add_ospf_descr_again.current.0.ospfIfPol.attributes.cost == "11" + - nm_add_ospf_descr_again.current.0.ospfIfPol.attributes.ctrl == "mtu-ignore" + - nm_add_ospf_descr_again.current.0.ospfIfPol.attributes.deadIntvl == "12" + - nm_add_ospf_descr_again.current.0.ospfIfPol.attributes.helloIntvl == "13" + - nm_add_ospf_descr_again.current.0.ospfIfPol.attributes.nwT == "bcast" + - nm_add_ospf_descr_again.current.0.ospfIfPol.attributes.pfxSuppress == "disable" + - nm_add_ospf_descr_again.current.0.ospfIfPol.attributes.prio == "14" + - nm_add_ospf_descr_again.current.0.ospfIfPol.attributes.rexmitIntvl == "15" + - nm_add_ospf_descr_again.current.0.ospfIfPol.attributes.xmitDelay == "16" + +- name: Change cost of ospf interface policy + cisco.aci.aci_interface_policy_ospf: + <<: *interface_policy_ospf_present + cost: 451 + ignore_errors: true + register: err_change_ospf_cost + +- name: Change dead_interval of ospf interface policy + cisco.aci.aci_interface_policy_ospf: + <<: *interface_policy_ospf_present + dead_interval: 65539 + ignore_errors: true + register: err_change_ospf_dead_interval + +- name: Change hello_interval of ospf interface policy + cisco.aci.aci_interface_policy_ospf: + <<: *interface_policy_ospf_present + hello_interval: 65538 + ignore_errors: true + register: err_change_ospf_hello_interval +- name: Change priority of ospf interface policy + cisco.aci.aci_interface_policy_ospf: + <<: *interface_policy_ospf_present + priority: 256 + ignore_errors: true + register: err_change_ospf_priority + +- name: Change retransmit_interval of ospf interface policy + cisco.aci.aci_interface_policy_ospf: + <<: *interface_policy_ospf_present + retransmit_interval: 65537 + ignore_errors: true + register: err_change_ospf_retransmit_interval + +- name: Change transmit_delay of ospf interface policy + cisco.aci.aci_interface_policy_ospf: + <<: *interface_policy_ospf_present + transmit_delay: 451 + ignore_errors: true + register: err_change_ospf_transmit_delay + +- name: Verify cost change and error input values + assert: + that: + - err_change_ospf_cost is not changed + - err_change_ospf_cost.msg == "Parameter 'cost' is only valid in range between 1 and 450." + - err_change_ospf_dead_interval is not changed + - err_change_ospf_dead_interval.msg == "Parameter 'dead_interval' is only valid in range between 1 and 65536." + - err_change_ospf_hello_interval is not changed + - err_change_ospf_hello_interval.msg == "Parameter 'hello_interval' is only valid in range between 1 and 65536." + - err_change_ospf_priority is not changed + - err_change_ospf_priority.msg == "Parameter 'priority' is only valid in range between 1 and 255." + - err_change_ospf_retransmit_interval is not changed + - err_change_ospf_retransmit_interval.msg == "Parameter 'retransmit_interval' is only valid in range between 1 and 65536." + - err_change_ospf_transmit_delay is not changed + - err_change_ospf_transmit_delay.msg == "Parameter 'transmit_delay' is only valid in range between 1 and 450." # ADD OSPF INTERFACE POLICY AGAIN - name: Add ospf interface policy again with no description (check_mode) diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_port_channel/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_port_channel/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_port_channel/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_port_channel/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_port_channel/tasks/main.yml new file mode 100644 index 000000000..36c84b30f --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_port_channel/tasks/main.yml @@ -0,0 +1,174 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Clean Environment + - name: Ensure first port channel interface policy does not exist + aci_interface_policy_port_channel: &aci_interface_policy_port_channel_absent + <<: *aci_info + name: anstest_policy + description: test for port channel interface policy + max_links: 8 + min_links: 2 + mode: active + fast_select: false + graceful_convergence: false + load_defer: true + suspend_individual: false + symmetric_hash: true + state: absent + + - name: Ensure second port channel interface policy does not exist + aci_interface_policy_port_channel: &aci_interface_policy_port_channel_2_absent + <<: *aci_info + name: anstest_policy_2 + fast_select: true + graceful_convergence: true + suspend_individual: true + state: absent + + - name: Create first port channel interface policy (check_mode) + aci_interface_policy_port_channel: &aci_interface_policy_port_channel_present + <<: *aci_interface_policy_port_channel_absent + state: present + check_mode: true + register: cm_add_interface_policy_port_channel_1 + + - name: Create first port channel interface policy (normal_mode) + aci_interface_policy_port_channel: + <<: *aci_interface_policy_port_channel_present + register: nm_add_interface_policy_port_channel_1 + + - name: Create first port channel interface policy again - testing idempotency + aci_interface_policy_port_channel: + <<: *aci_interface_policy_port_channel_present + register: idempotency_add_interface_policy_port_channel_1 + + - name: Create second port channel interface policy + aci_interface_policy_port_channel: &aci_interface_policy_port_channel_2_present + <<: *aci_interface_policy_port_channel_2_absent + state: present + register: nm_add_interface_policy_port_channel_2 + + - name: Modify first port channel interface policy with max links above 16 - testing failure message + aci_interface_policy_port_channel: + <<: *aci_interface_policy_port_channel_present + max_links: 17 + ignore_errors: true + register: nm_policy_port_channel_max_links_failure + + - name: Modify first port channel interface policy with min links bellow 1 - testing failure message + aci_interface_policy_port_channel: + <<: *aci_interface_policy_port_channel_present + min_links: 0 + ignore_errors: true + register: nm_policy_port_channel_min_links_failure + + - name: Asserts for creation tasks + assert: + that: + - cm_add_interface_policy_port_channel_1 is changed + - cm_add_interface_policy_port_channel_1.previous == [] + - cm_add_interface_policy_port_channel_1.current == [] + - nm_add_interface_policy_port_channel_1 is changed + - nm_add_interface_policy_port_channel_1.current.0.lacpLagPol.attributes.name == "anstest_policy" + - nm_add_interface_policy_port_channel_1.current.0.lacpLagPol.attributes.ctrl == "load-defer,symmetric-hash" + - nm_add_interface_policy_port_channel_1.current.0.lacpLagPol.attributes.maxLinks == "8" + - nm_add_interface_policy_port_channel_1.current.0.lacpLagPol.attributes.minLinks == "2" + - nm_add_interface_policy_port_channel_1.current.0.lacpLagPol.attributes.mode == "active" + - idempotency_add_interface_policy_port_channel_1 is not changed + - nm_add_interface_policy_port_channel_2 is changed + - nm_add_interface_policy_port_channel_2.current.0.lacpLagPol.attributes.name == "anstest_policy_2" + - nm_add_interface_policy_port_channel_2.current.0.lacpLagPol.attributes.ctrl == "fast-sel-hot-stdby,graceful-conv,susp-individual" + - nm_add_interface_policy_port_channel_2.current.0.lacpLagPol.attributes.maxLinks == "16" + - nm_add_interface_policy_port_channel_2.current.0.lacpLagPol.attributes.minLinks == "1" + - nm_add_interface_policy_port_channel_2.current.0.lacpLagPol.attributes.mode == "off" + - nm_policy_port_channel_max_links_failure.msg == "The \"max_links\" must be a value between 1 and 16" + - nm_policy_port_channel_min_links_failure.msg == "The \"min_links\" must be a value between 1 and 16" + + - name: Query all port channel interface policies + aci_interface_policy_port_channel: + <<: *aci_info + state: query + register: query_all_interface_policy_port_channel + + - name: Query first port channel interface policy + aci_interface_policy_port_channel: + <<: *aci_interface_policy_port_channel_present + state: query + register: query_first_interface_policy_port_channel + + - name: Asserts for query tasks + assert: + that: + - query_all_interface_policy_port_channel is not changed + - query_all_interface_policy_port_channel.current | length >= 2 + - '"class/lacpLagPol.json" in query_all_interface_policy_port_channel.url' + - query_first_interface_policy_port_channel is not changed + - query_first_interface_policy_port_channel.current.0.lacpLagPol.attributes.name == "anstest_policy" + - query_first_interface_policy_port_channel.current.0.lacpLagPol.attributes.ctrl == "load-defer,symmetric-hash" + - query_first_interface_policy_port_channel.current.0.lacpLagPol.attributes.maxLinks == "8" + - query_first_interface_policy_port_channel.current.0.lacpLagPol.attributes.minLinks == "2" + - query_first_interface_policy_port_channel.current.0.lacpLagPol.attributes.mode == "active" + + - name: Delete first port channel interface policy (check_mode) + aci_interface_policy_port_channel: + <<: *aci_interface_policy_port_channel_present + state: absent + check_mode: true + register: cm_delete_interface_policy_port_channel_1 + + - name: Delete first port channel interface policy (normal_mode) + aci_interface_policy_port_channel: + <<: *aci_interface_policy_port_channel_present + state: absent + register: nm_delete_interface_policy_port_channel_1 + + - name: Delete first port channel interface policy again - testing idempotency + aci_interface_policy_port_channel: + <<: *aci_interface_policy_port_channel_present + state: absent + register: idempotency_delete_interface_policy_port_channel_1 + + - name: Delete second port channel interface policy (normal_mode) + aci_interface_policy_port_channel: + <<: *aci_interface_policy_port_channel_2_present + state: absent + register: nm_delete_interface_policy_port_channel_2 + + - name: Asserts for deletion tasks + assert: + that: + - cm_delete_interface_policy_port_channel_1 is changed + - cm_delete_interface_policy_port_channel_1.proposed == {} + - nm_delete_interface_policy_port_channel_1 is changed + - nm_delete_interface_policy_port_channel_1.previous != [] + - nm_delete_interface_policy_port_channel_1.current == [] + - idempotency_delete_interface_policy_port_channel_1 is not changed + - idempotency_delete_interface_policy_port_channel_1.previous == [] + - nm_delete_interface_policy_port_channel_2 is changed + - nm_delete_interface_policy_port_channel_2.previous != [] + - nm_delete_interface_policy_port_channel_2.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_spine_policy_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_spine_policy_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_spine_policy_group/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_spine_policy_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_spine_policy_group/tasks/main.yml new file mode 100644 index 000000000..fec8415a3 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_spine_policy_group/tasks/main.yml @@ -0,0 +1,130 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Anvitha Jain <anvjain@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + + # CLEAN ENVIRONMENT + - name: Making sure interface_policy_spine_policy_group doesn't exist at beginning of test (Spine Access Port) + cisco.aci.aci_interface_policy_spine_policy_group: &spine_absent + <<: *aci_info + policy_group: spine_pg_test + state: absent + + # ADD Spine Policy Group + - name: Adding a interface policy spine policy group - check mode works + cisco.aci.aci_interface_policy_spine_policy_group: &spine_present + <<: *aci_info + policy_group: spine_pg_test + link_level_policy: link_level_policy_test + link_flap_policy: link_flap_policy_test + cdp_policy: cdp_policy_test + mac_sec_policy: mac_sec_policy_test + attached_entity_profile: policy_group_aep + state: present + check_mode: yes + register: intf_policy_spine_polgrp_check_mode_present + + - name: Adding a interface policy spine policy group - creation works + cisco.aci.aci_interface_policy_spine_policy_group: + <<: *spine_present + register: intf_policy_spine_polgrp_present + + - name: Adding a interface policy spine policy group - idempotency works + cisco.aci.aci_interface_policy_spine_policy_group: + <<: *spine_present + register: intf_policy_spine_polgrp_idempotent + + # UPDATE Spine Policy Group + - name: Adding a interface policy spine policy group description - update works + cisco.aci.aci_interface_policy_spine_policy_group: + <<: *spine_present + description: policygroup description + register: intf_policy_spine_polgrp_update + + - name: Verify present assertions for Spine Policy Group + assert: + that: + - intf_policy_spine_polgrp_check_mode_present is changed + - intf_policy_spine_polgrp_present is changed + - intf_policy_spine_polgrp_present.previous == [] + - intf_policy_spine_polgrp_present.current[0].infraSpAccPortGrp.attributes.name == 'spine_pg_test' + - intf_policy_spine_polgrp_present.current[0].infraSpAccPortGrp.children.0.infraRsLinkFlapPol.attributes.tnFabricLinkFlapPolName == 'link_flap_policy_test' + - intf_policy_spine_polgrp_present.current[0].infraSpAccPortGrp.children.1.infraRsMacsecIfPol.attributes.tnMacsecIfPolName == 'mac_sec_policy_test' + - intf_policy_spine_polgrp_present.current[0].infraSpAccPortGrp.children.2.infraRsAttEntP.attributes.tDn == 'uni/infra/attentp-policy_group_aep' + - intf_policy_spine_polgrp_present.current[0].infraSpAccPortGrp.children.3.infraRsHIfPol.attributes.tnFabricHIfPolName == 'link_level_policy_test' + - intf_policy_spine_polgrp_present.current[0].infraSpAccPortGrp.children.4.infraRsCdpIfPol.attributes.tnCdpIfPolName == 'cdp_policy_test' + - intf_policy_spine_polgrp_present.current[0].infraSpAccPortGrp.attributes.annotation == 'orchestrator:ansible' + - intf_policy_spine_polgrp_idempotent is not changed + - intf_policy_spine_polgrp_idempotent.sent == {} + - intf_policy_spine_polgrp_update is changed + - intf_policy_spine_polgrp_update.current[0].infraSpAccPortGrp.attributes.descr == 'policygroup description' + + # QUERY Spine Policy Group + - name: Query all interface policy spine policy groups + cisco.aci.aci_interface_policy_spine_policy_group: + <<: *aci_info + state: query + register: query_all_spine_policy_groups + + - name: Query interface policy spine policy group + cisco.aci.aci_interface_policy_spine_policy_group: + <<: *aci_info + policy_group: spine_pg_test + state: query + register: query_spine_policy_group + + - name: Verify query assertions for Spine Policy Group + assert: + that: + - query_spine_policy_group is not changed + - query_spine_policy_group.current[0] | length >= 1 + - query_all_spine_policy_groups is not changed + + - name: Remove interface policy spine policy group - check mode + cisco.aci.aci_interface_policy_spine_policy_group: + <<: *spine_absent + check_mode: yes + register: intf_policy_spine_polgrp_check_mode_absent + + - name: Remove interface policy spine policy group - delete works + cisco.aci.aci_interface_policy_spine_policy_group: + <<: *spine_absent + register: intf_policy_spine_polgrp_absent + + - name: Remove interface policy spine policy group - idempotency works + cisco.aci.aci_interface_policy_spine_policy_group: + <<: *spine_absent + register: intf_policy_spine_polgrp_absent_idempotent + + - name: Verify absent assertions for Spine Policy Group + assert: + that: + - intf_policy_spine_polgrp_check_mode_absent is changed + - intf_policy_spine_polgrp_check_mode_absent.previous != [] + - intf_policy_spine_polgrp_absent is changed + - intf_policy_spine_polgrp_absent.previous == intf_policy_spine_polgrp_absent.previous + - intf_policy_spine_polgrp_absent_idempotent is not changed + - intf_policy_spine_polgrp_absent_idempotent.previous == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out/tasks/main.yml new file mode 100644 index 000000000..65474048c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out/tasks/main.yml @@ -0,0 +1,270 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Remove the ansible_l3out + aci_l3out: &aci_l3out_absent + <<: *aci_info + tenant: ansible_tenant + name: ansible_l3out + description: L3Out for ansible_tenant tenant + domain: ansible_dom + vrf: ansible_vrf + state: absent + + - name: Remove the second ansible_l3out + aci_l3out: &aci_l3out_2_absent + <<: *aci_info + tenant: ansible_tenant + name: ansible_l3out_2 + description: Second L3Out + domain: ansible_dom + vrf: ansible_vrf + l3protocol: [ ospf, bgp ] + state: absent + + - name: Add a new L3Out (check_mode) + aci_l3out: &aci_l3out_present + <<: *aci_l3out_absent + state: present + check_mode: true + register: cm_add_l3out + + - name: Add a new L3Out (normal_mode) + aci_l3out: + <<: *aci_l3out_present + register: nm_add_l3out + + - name: create L3Out again - testing idempotency + aci_l3out: + <<: *aci_l3out_present + register: create_idempotency + + - name: Add the second ansible_l3out + aci_l3out: + <<: *aci_l3out_2_absent + state: present + register: cm_add_l3out_2 + + - name: asserts for l3out creation tasks + assert: + that: + - cm_add_l3out is changed + - cm_add_l3out.previous == [] + - cm_add_l3out.current == [] + - nm_add_l3out is changed + - nm_add_l3out.current.0.l3extOut.attributes.descr == cm_add_l3out.sent.l3extOut.attributes.descr == "L3Out for ansible_tenant tenant" + - nm_add_l3out.current.0.l3extOut.attributes.name == cm_add_l3out.sent.l3extOut.attributes.name == "ansible_l3out" + - create_idempotency is not changed + + - name: Add export and import to route_control + aci_l3out: + <<: *aci_l3out_present + route_control: [ import, export ] + register: nm_add_l3out_import_export + + - name: Add export to route_control + aci_l3out: + <<: *aci_l3out_present + route_control: export + register: nm_add_l3out_export + + - name: Add just import to route_control - testing failure message + aci_l3out: + <<: *aci_l3out_present + route_control: import + register: nm_add_l3out_import_error + ignore_errors: true + + - name: asserts for l3out route control tasks + assert: + that: + - nm_add_l3out_import_export is changed + - nm_add_l3out_import_export.current.0.l3extOut.attributes.enforceRtctrl == "export,import" + - nm_add_l3out_export is changed + - nm_add_l3out_export.current.0.l3extOut.attributes.enforceRtctrl == "export" + - nm_add_l3out_import_error.msg == "The route_control parameter is invalid{{':'}} allowed options are export or import,export only" + + - name: Add BGP protocol + aci_l3out: + <<: *aci_l3out_present + l3protocol: bgp + register: nm_add_l3out_bgp + + - name: Add BGP protocol again - testing L3protocol changes + aci_l3out: + <<: *aci_l3out_present + l3protocol: bgp + register: nm_add_l3out_bgp_again + + - name: Add PIM protocol, ospf_spec and asn - testing warning message for asn + aci_l3out: + <<: *aci_l3out_present + l3protocol: pim + asn: 1 + register: nm_add_l3out_pim + + - name: Add EIGRP protocol - testing warning message for OSPF spec + aci_l3out: + <<: *aci_l3out_present + l3protocol: eigrp + asn: 1 + ospf: + description: OSPF warnings message works + register: nm_add_l3out_eigrp + + - name: remove asn - testing failure message + aci_l3out: + <<: *aci_l3out_present + l3protocol: eigrp + asn: null + register: add_l3out_without_asn + ignore_errors: true + + - name: remove protocol - testing static protocol + aci_l3out: + <<: *aci_l3out_present + l3protocol: static + register: nm_remove_l3protocol + + - name: asserts for l3out protocols tasks + assert: + that: + - nm_add_l3out_bgp is changed + - nm_add_l3out_bgp_again is changed + - nm_add_l3out_pim is changed + - nm_add_l3out_pim.warnings.0 == "Parameter 'asn' is only applicable when l3protocol is 'eigrp'. The ASN will be ignored" + - nm_add_l3out_eigrp is changed + - nm_add_l3out_eigrp.current.0.l3extOut.children.0.eigrpExtP.attributes.asn == "1" + - nm_add_l3out_eigrp.warnings.0 == "Parameter 'ospf' is only applicable when l3protocol is 'ospf'. The OPSF specifications will be ignored" + - add_l3out_without_asn.msg == "Parameter 'asn' is required when l3protocol is 'eigrp'" + - nm_remove_l3protocol is changed + + - name: Add OSPF protocol + aci_l3out: + <<: *aci_l3out_present + l3protocol: ospf + ospf: + area_cost: 1 + area_ctrl: [ summary, redistribute ] + area_id: 0.0.0.2 + area_type: regular + multipod_internal: no + description: test for ospf protocol + register: nm_add_l3out_ospf + + - name: asserts for l3out OSPF protocol tasks + assert: + that: + - nm_add_l3out_ospf is changed + - nm_add_l3out_ospf.current.0.l3extOut.children.2.ospfExtP.attributes.areaCost == "1" + - nm_add_l3out_ospf.current.0.l3extOut.children.2.ospfExtP.attributes.areaCtrl == "redistribute,summary" + - nm_add_l3out_ospf.current.0.l3extOut.children.2.ospfExtP.attributes.areaId == "0.0.0.2" + - nm_add_l3out_ospf.current.0.l3extOut.children.2.ospfExtP.attributes.areaType == "regular" + - nm_add_l3out_ospf.current.0.l3extOut.children.2.ospfExtP.attributes.descr == "test for ospf protocol" + - nm_add_l3out_ospf.current.0.l3extOut.children.2.ospfExtP.attributes.multipodInternal == "no" + + - name: get ansible_l3out + aci_l3out: + <<: *aci_l3out_present + state: query + register: get_l3out + + - name: get all l3outs in ansible_tenant + aci_l3out: + <<: *aci_info + tenant: ansible_tenant + state: query + register: get_all_l3out_ansible_tenant + + - name: get all l3outs + aci_l3out: + <<: *aci_info + state: query + register: get_all_l3out + + - name: asserts query tasks + assert: + that: + - get_l3out is not changed + - '"rsp-subtree=full&rsp-subtree-class=bgpExtP,eigrpExtP,l3extRsEctx,l3extRsL3DomAtt,ospfExtP,pimExtP" in get_l3out.filter_string' + - '"tn-ansible_tenant/out-ansible_l3out.json" in get_l3out.url' + - get_all_l3out_ansible_tenant is not changed + - '"ospfExtP" in get_all_l3out_ansible_tenant.current.0.fvTenant.children.0.l3extOut.children.2' + - '"ospfExtP" in get_all_l3out_ansible_tenant.current.0.fvTenant.children.1.l3extOut.children.2' + - '"bgpExtP" in get_all_l3out_ansible_tenant.current.0.fvTenant.children.1.l3extOut.children.3' + - get_all_l3out is not changed + - get_all_l3out.current | length >= 2 + + - name: delete l3out (check_mode) + aci_l3out: + <<: *aci_l3out_present + state: absent + check_mode: true + register: delete_cm + + - name: delete l3out (normal_mode) + aci_l3out: + <<: *aci_l3out_present + state: absent + register: delete_l3out + + - name: delete l3out again - testing idempotency + aci_l3out: + <<: *aci_l3out_present + state: absent + register: delete_idempotency + + - name: asserts for deletion tasks + assert: + that: + - delete_cm is changed + - delete_cm.proposed == {} + - delete_l3out is changed + - delete_l3out.previous != [] + - delete_l3out.method == "DELETE" + - delete_idempotency is not changed + - delete_idempotency.previous == [] + + - name: Delete the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_info + tenant: ansible_tenant + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_bgp_peer/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_bgp_peer/tasks/main.yml index 4e1784a6a..8ed2daee3 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_bgp_peer/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_bgp_peer/tasks/main.yml @@ -201,6 +201,7 @@ address_type_controls: - af-ucast ttl: 2 + local_as_number_config: "replace-as" state: present register: add_eth_bgp_peer when: version.current.0.topSystem.attributes.version is version('4', '>=') @@ -239,6 +240,8 @@ - add_eth_bgp_peer.current.0.bgpPeerP.attributes.peerCtrl == "bfd" - add_eth_bgp_peer.current.0.bgpPeerP.attributes.ttl == "2" - add_eth_bgp_peer.current.0.bgpPeerP.attributes.annotation == 'orchestrator:ansible' + - add_eth_bgp_peer.current.0.bgpPeerP.children.0.bgpLocalAsnP.attributes.asnPropagate == "replace-as" + - add_eth_bgp_peer.current.0.bgpPeerP.children.0.bgpLocalAsnP.attributes.localAsn == "0" when: version.current.0.topSystem.attributes.version is version('4', '>=') - name: verify BGP peer has been created with correct attributes (version < 4) @@ -255,7 +258,7 @@ - name: verify remote AS object has been created correctly assert: that: - - add_eth_bgp_peer.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65456" + - add_eth_bgp_peer.current.0.bgpPeerP.children.2.bgpAsP.attributes.asn == "65456" when: version.current.0.topSystem.attributes.version is version('4', '>=') - name: verify remote AS object has been created correctly @@ -340,7 +343,7 @@ - name: verify remote AS object is still correct (version >= 4) assert: that: - - add_eth_bgp_peer_again.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65456" + - add_eth_bgp_peer_again.current.0.bgpPeerP.children.2.bgpAsP.attributes.asn == "65456" when: version.current.0.topSystem.attributes.version is version('4', '>=') - name: verify remote AS object his still correct (version < 4) @@ -376,6 +379,8 @@ allow_self_as_count: 3 ttl: 4 admin_state: disabled + local_as_number: 101 + local_as_number_config: "dual-as" state: present register: update_eth_bgp_peer when: version.current.0.topSystem.attributes.version is version('4', '>=') @@ -419,6 +424,8 @@ - update_eth_bgp_peer.current.0.bgpPeerP.attributes.ttl == "4" - update_eth_bgp_peer.current.0.bgpPeerP.attributes.allowedSelfAsCnt == "3" - update_eth_bgp_peer.current.0.bgpPeerP.attributes.privateASctrl == "remove-exclusive" + - update_eth_bgp_peer.current.0.bgpPeerP.children.0.bgpLocalAsnP.attributes.asnPropagate == "dual-as" + - update_eth_bgp_peer.current.0.bgpPeerP.children.0.bgpLocalAsnP.attributes.localAsn == "101" when: version.current.0.topSystem.attributes.version is version('4', '>=') - name: verify BGP peer has been updated with correct attributes (version < 4) @@ -437,7 +444,7 @@ - name: verify remote AS object has been updated correctly (version >= 4) assert: that: - - update_eth_bgp_peer.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65457" + - update_eth_bgp_peer.current.0.bgpPeerP.children.2.bgpAsP.attributes.asn == "65457" when: version.current.0.topSystem.attributes.version is version('4', '>=') - name: verify remote AS object has been updated correctly (version < 4) @@ -508,7 +515,7 @@ - name: verify BGP remote AS (version >= 4) assert: that: - - query_eth_bgp_peer.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65457" + - query_eth_bgp_peer.current.0.bgpPeerP.children.2.bgpAsP.attributes.asn == "65457" when: version.current.0.topSystem.attributes.version is version('4', '>=') - name: verify BGP remote AS (version < 4) @@ -641,6 +648,8 @@ profile: "anstest_export" direction: "export" l3out: "anstest_l3out" + local_as_number_config: "dual-as" + local_as_number: 100 state: present check_mode: true register: cm_ln_rtctrl_present @@ -668,6 +677,8 @@ - nm_ln_rtctrl_present.previous | length == 0 - nm_ln_rtctrl_present.current.0.bgpPeerP.attributes.addr == "192.168.50.3" - nm_ln_rtctrl_present.current.0.bgpPeerP.children | length >= 2 + - nm_ln_rtctrl_present.current.0.bgpPeerP.children.2.bgpLocalAsnP.attributes.asnPropagate == "dual-as" + - nm_ln_rtctrl_present.current.0.bgpPeerP.children.2.bgpLocalAsnP.attributes.localAsn == "100" - name: Add BGP Peer to the Node Profile level (version >= 4) - normal mode - idempotency works aci_l3out_bgp_peer: diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_bgp_protocol_profile/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_bgp_protocol_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_bgp_protocol_profile/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_bgp_protocol_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_bgp_protocol_profile/tasks/main.yml new file mode 100644 index 000000000..85b43726c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_bgp_protocol_profile/tasks/main.yml @@ -0,0 +1,184 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a new l3out + aci_l3out: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + description: Ansible L3Out for ansible_tenant tenant + domain: ansible_dom + vrf: ansible_vrf + state: present + + - name: Add a new logical node profile + aci_l3out_logical_node_profile: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile_1 + description: Ansible Logical Node Profile 1 for ansible_l3out L3Out + state: present + + - name: Add a second logical node profile + aci_l3out_logical_node_profile: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile_2 + description: Ansible Logical Node Profile 2 for ansible_l3out L3Out + state: present + + - name: Add a new BGP timers policy + aci_bgp_timers_policy: + <<: *aci_info + tenant: ansible_tenant + bgp_timers_policy: ansible_bgp_timers_policy + description: Ansible BGP timers policy for ansible_tenant tenant + state: present + + - name: Add a new BGP protocol profile + aci_bgp_best_path_policy: + <<: *aci_info + tenant: ansible_tenant + bgp_best_path_policy: ansible_bgp_best_path_policy + description: Ansible BGP protocol profile for ansible_tenant tenant + state: present + + - name: Add a BGP protocol profile (check_mode) + aci_l3out_bgp_protocol_profile: &aci_l3out_bgp_protocol_profile_present + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile_1 + bgp_timers_policy: ansible_bgp_timers_policy + bgp_best_path_policy: ansible_bgp_best_path_policy + state: present + check_mode: true + register: cm_add_bgp_protocol_profile + + - name: Add a BGP protocol profile (normal_mode) + aci_l3out_bgp_protocol_profile: + <<: *aci_l3out_bgp_protocol_profile_present + register: nm_add_bgp_protocol_profile + + - name: Add the first BGP protocol profile again - testing idempotency + aci_l3out_bgp_protocol_profile: + <<: *aci_l3out_bgp_protocol_profile_present + register: nm_add_bgp_protocol_profile_idempotency + + - name: Add a second BGP protocol profile (normal_mode) + aci_l3out_bgp_protocol_profile: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile_2 + state: present + register: nm_add_bgp_protocol_profile_2 + + - name: Asserts for BGP protocol profiles creation tasks + assert: + that: + - cm_add_bgp_protocol_profile is changed + - cm_add_bgp_protocol_profile.previous == [] + - cm_add_bgp_protocol_profile.current == [] + - nm_add_bgp_protocol_profile is changed + - nm_add_bgp_protocol_profile.current.0.bgpProtP.children.0.bgpRsBestPathCtrlPol.attributes.tnBgpBestPathCtrlPolName == "ansible_bgp_best_path_policy" + - nm_add_bgp_protocol_profile.current.0.bgpProtP.children.1.bgpRsBgpNodeCtxPol.attributes.tnBgpCtxPolName == "ansible_bgp_timers_policy" + - nm_add_bgp_protocol_profile_idempotency is not changed + - nm_add_bgp_protocol_profile_2 is changed + - nm_add_bgp_protocol_profile_2.previous == [] + + - name: Query all BGP best path policies + aci_l3out_bgp_protocol_profile: + <<: *aci_info + state: query + register: query_all_bgp_protocol_profile + + - name: Query ansible_bgp_protocol_profile_1 + aci_l3out_bgp_protocol_profile: + <<: *aci_l3out_bgp_protocol_profile_present + state: query + register: query_ansible_bgp_protocol_profile_1 + + - name: Asserts query tasks + assert: + that: + - query_all_bgp_protocol_profile is not changed + - query_all_bgp_protocol_profile.current|length >= 2 + - query_ansible_bgp_protocol_profile_1 is not changed + - query_ansible_bgp_protocol_profile_1.current.0.bgpProtP.children.0.bgpRsBestPathCtrlPol.attributes.tDn == "uni/tn-ansible_tenant/bestpath-ansible_bgp_best_path_policy" + - query_ansible_bgp_protocol_profile_1.current.0.bgpProtP.children.0.bgpRsBestPathCtrlPol.attributes.state == "formed" + - query_ansible_bgp_protocol_profile_1.current.0.bgpProtP.children.1.bgpRsBgpNodeCtxPol.attributes.tDn == "uni/tn-ansible_tenant/bgpCtxP-ansible_bgp_timers_policy" + - query_ansible_bgp_protocol_profile_1.current.0.bgpProtP.children.1.bgpRsBgpNodeCtxPol.attributes.state == "formed" + + - name: Remove BGP protocol profile (check_mode) + aci_l3out_bgp_protocol_profile: &bgp_protocol_profile_absent + <<: *aci_l3out_bgp_protocol_profile_present + state: absent + check_mode: true + register: cm_remove_bgp_protocol_profile + + - name: Remove BGP protocol profile (normal_mode) + aci_l3out_bgp_protocol_profile: + <<: *bgp_protocol_profile_absent + register: nm_remove_bgp_protocol_profile + + - name: Remove BGP protocol profile - testing idempotency + aci_l3out_bgp_protocol_profile: + <<: *bgp_protocol_profile_absent + register: nm_remove_bgp_protocol_profile_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_bgp_protocol_profile is changed + - cm_remove_bgp_protocol_profile.proposed == {} + - nm_remove_bgp_protocol_profile is changed + - nm_remove_bgp_protocol_profile.previous != [] + - nm_remove_bgp_protocol_profile.method == "DELETE" + - nm_remove_bgp_protocol_profile_idempotency is not changed + - nm_remove_bgp_protocol_profile_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extepg/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extepg/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extepg/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extepg/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extepg/tasks/main.yml new file mode 100644 index 000000000..d52fb5ef4 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extepg/tasks/main.yml @@ -0,0 +1,364 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Akini Ross (akinross@cisco.com) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + ansible.builtin.fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + ansible.builtin.set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + aci_tenant: ansible_test + +- name: Verify Cloud and Non-Cloud Sites in use. + ansible.builtin.include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: + - query_cloud.current == [] + block: + + - name: Query system information + aci_system: + <<: *aci_info + id: 1 + state: query + register: version + + # CLEAN TEST ENVIRONMENT + + - name: Ensure clean tenant configuration + cisco.aci.aci_tenant: + <<: *aci_info + tenant: "{{ aci_tenant }}" + state: "{{ item }}" + loop: + - absent + - present + + - name: Ensure clean vrf configuration + cisco.aci.aci_vrf: + <<: *aci_info + tenant: "{{ aci_tenant }}" + vrf: vrf_1 + + - name: Ensure clean l3out configuration + cisco.aci.aci_l3out: + <<: *aci_info + tenant: "{{ aci_tenant }}" + l3out: "{{ item }}" + vrf: vrf_1 + domain: dom_1 + loop: + - l3out_1 + - l3out_2 + + # TEST CREATE L3OUT EXTERNAL EPG + + - name: Add l3out external epg 1 ( check mode ) + cisco.aci.aci_l3out_extepg: &add_l3out_extepg_1 + <<: *aci_info + tenant: "{{ aci_tenant }}" + l3out: l3out_1 + extepg: extepg_1 + state: present + check_mode: true + register: cm_add_l3out_extepg_1 + + - name: Add l3out external epg 1 + cisco.aci.aci_l3out_extepg: + <<: *add_l3out_extepg_1 + route_control_profiles: + import_profile: "" + register: nm_add_l3out_extepg_1 + + - name: Add l3out external epg 1 again + cisco.aci.aci_l3out_extepg: + <<: *add_l3out_extepg_1 + register: nm_add_l3out_extepg_1_again + + - name: Verify add l3out external epg 1 + ansible.builtin.assert: + that: + - cm_add_l3out_extepg_1 is changed + - cm_add_l3out_extepg_1.current == [] + - cm_add_l3out_extepg_1.previous == [] + - cm_add_l3out_extepg_1.proposed.l3extInstP.attributes.name == "extepg_1" + - nm_add_l3out_extepg_1 is changed + - nm_add_l3out_extepg_1.previous == [] + - nm_add_l3out_extepg_1.current.0.l3extInstP.attributes.name == "extepg_1" + - nm_add_l3out_extepg_1.current.0.l3extInstP.attributes.descr == "" + - nm_add_l3out_extepg_1.current.0.l3extInstP.attributes.prefGrMemb == "exclude" + - nm_add_l3out_extepg_1.current.0.l3extInstP.attributes.targetDscp == "unspecified" + - nm_add_l3out_extepg_1_again is not changed + - nm_add_l3out_extepg_1_again.previous.0.l3extInstP.attributes.name == "extepg_1" + - nm_add_l3out_extepg_1_again.previous.0.l3extInstP.attributes.descr == "" + - nm_add_l3out_extepg_1_again.previous.0.l3extInstP.attributes.prefGrMemb == "exclude" + - nm_add_l3out_extepg_1_again.previous.0.l3extInstP.attributes.targetDscp == "unspecified" + - nm_add_l3out_extepg_1_again.current.0.l3extInstP.attributes.name == "extepg_1" + - nm_add_l3out_extepg_1_again.current.0.l3extInstP.attributes.descr == "" + - nm_add_l3out_extepg_1_again.current.0.l3extInstP.attributes.prefGrMemb == "exclude" + - nm_add_l3out_extepg_1_again.current.0.l3extInstP.attributes.targetDscp == "unspecified" + + - name: Change l3out external epg 1 + cisco.aci.aci_l3out_extepg: + <<: *add_l3out_extepg_1 + description: "changed description" + preferred_group: true + dscp: AF12 + register: nm_change_l3out_extepg_1 + + - name: Verify change l3out external epg 1 + ansible.builtin.assert: + that: + - nm_change_l3out_extepg_1 is changed + - nm_change_l3out_extepg_1.previous.0.l3extInstP.attributes.name == "extepg_1" + - nm_change_l3out_extepg_1.previous.0.l3extInstP.attributes.descr == "" + - nm_change_l3out_extepg_1.previous.0.l3extInstP.attributes.prefGrMemb == "exclude" + - nm_change_l3out_extepg_1.previous.0.l3extInstP.attributes.targetDscp == "unspecified" + - nm_change_l3out_extepg_1.current.0.l3extInstP.attributes.name == "extepg_1" + - nm_change_l3out_extepg_1.current.0.l3extInstP.attributes.descr == "changed description" + - nm_change_l3out_extepg_1.current.0.l3extInstP.attributes.prefGrMemb == "include" + - nm_change_l3out_extepg_1.current.0.l3extInstP.attributes.targetDscp == "AF12" + + - name: Add two more l3out external epgs + cisco.aci.aci_l3out_extepg: + <<: *aci_info + tenant: "{{ aci_tenant }}" + l3out: "{{ item.l3out }}" + extepg: "{{ item.extepg }}" + state: present + loop: + - {l3out: l3out_1, extepg: extepg_2} + - {l3out: l3out_2, extepg: extepg_3} + + - name: Add l3out external epg with the new optional params + cisco.aci.aci_l3out_extepg: + <<: *aci_info + tenant: ansible_test + l3out: l3out_1 + extepg: extepg_params + contract_exception_tag: contract_excepted + qos_class: level6 + route_control_profiles: + import_profile: profile1 + export_profile: profile2 + state: present + register: nm_l3out_extepg_optional_params + + - name: Add l3out external epg with the new optional params again + cisco.aci.aci_l3out_extepg: + <<: *aci_info + tenant: ansible_test + l3out: l3out_1 + extepg: extepg_params + contract_exception_tag: contract_excepted + qos_class: level6 + route_control_profiles: + import_profile: profile1 + export_profile: profile2 + state: present + register: nm_l3out_extepg_optional_params_again + + - name: Add l3out external epg with no export route control profile in the task + cisco.aci.aci_l3out_extepg: + <<: *aci_info + tenant: ansible_test + l3out: l3out_1 + extepg: extepg_params + contract_exception_tag: contract_excepted + qos_class: level6 + route_control_profiles: + import_profile: profile1 + state: present + register: nm_l3out_extepg_non_existent_export_profile + + - name: Add l3out external epg with export route control profile having "" + cisco.aci.aci_l3out_extepg: + <<: *aci_info + tenant: ansible_test + l3out: l3out_1 + extepg: extepg_params + contract_exception_tag: contract_excepted + qos_class: level6 + route_control_profiles: + import_profile: profile1 + export_profile: "" + state: present + register: nm_l3out_extepg_remove_export_profile + + - name: Add l3out external epg with export route control profile again + cisco.aci.aci_l3out_extepg: + <<: *aci_info + tenant: ansible_test + l3out: l3out_1 + extepg: extepg_params + contract_exception_tag: contract_excepted + qos_class: level6 + route_control_profiles: + import_profile: profile1 + export: profile2 + state: present + register: nm_l3out_extepg_add_export_profile + + - name: Add l3out external epg with intra_ext_epg_isolation + cisco.aci.aci_l3out_extepg: + <<: *aci_info + tenant: ansible_test + l3out: l3out_1 + extepg: extepg_isolation + intra_ext_epg_isolation: enforced + state: present + register: nm_l3out_extepg_isolation + when: + - version.current.0.topSystem.attributes.version is version('5.0', '>=') + + # TEST QUERY L3OUT EXTERNAL EPG + + - name: Query l3out external epg 1 + cisco.aci.aci_l3out_extepg: + <<: *add_l3out_extepg_1 + state: query + register: query_one + + - name: Query all l3out external epgs ( class query ) + cisco.aci.aci_l3out_extepg: + <<: *aci_info + state: query + register: query_all + + - name: Verify query l3out external epgs + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current | length == 1 + - query_one.current.0.l3extInstP.attributes.name == "extepg_1" + - query_all is not changed + - query_all.current | length >= 3 + + - name: Query l3out external epg with the new optional params + cisco.aci.aci_l3out_extepg: + <<: *aci_info + tenant: ansible_test + l3out: l3out_1 + extepg: extepg_params + state: query + register: query_l3out_extepg_optional_params + + - name: Query l3out external epg with intra_ext_epg_isolation + cisco.aci.aci_l3out_extepg: + <<: *aci_info + tenant: ansible_test + l3out: l3out_1 + extepg: extepg_isolation + state: query + register: query_l3out_extepg_isolation + when: + - version.current.0.topSystem.attributes.version is version('5.0', '>=') + + - name: Gather attribute search results using regex + ansible.builtin.set_fact: + profile1_name: "{{ nm_l3out_extepg_optional_params.current.0.l3extInstP.children | regex_search('profile1') }}" + profile1_direction: "{{ nm_l3out_extepg_optional_params.current.0.l3extInstP.children | regex_search('import') }}" + profile2_name: "{{ nm_l3out_extepg_optional_params.current.0.l3extInstP.children | regex_search('profile2') }}" + profile2_direction: "{{ nm_l3out_extepg_optional_params.current.0.l3extInstP.children | regex_search('export') }}" + profile2_exists: "{{ nm_l3out_extepg_non_existent_export_profile.current.0.l3extInstP.children | regex_search('profile2') }}" + profile2_removed: "{{ nm_l3out_extepg_remove_export_profile.current.0.l3extInstP.children | regex_search('profile2') }}" + profile2_direction_removed: "{{ nm_l3out_extepg_remove_export_profile.current.0.l3extInstP.children | regex_search('export') }}" + query_profile1_name: "{{ query_l3out_extepg_optional_params.current.0.l3extInstP.children | regex_search('profile1') }}" + query_profile1_direction: "{{ query_l3out_extepg_optional_params.current.0.l3extInstP.children | regex_search('import') }}" + query_profile2_name: "{{ query_l3out_extepg_optional_params.current.0.l3extInstP.children | regex_search('profile2') }}" + query_profile2_direction: "{{ query_l3out_extepg_optional_params.current.0.l3extInstP.children | regex_search('export') }}" + + - name: Verify l3out external epg with the new optional params + ansible.builtin.assert: + that: + - nm_l3out_extepg_optional_params is changed + - nm_l3out_extepg_optional_params_again is not changed + - nm_l3out_extepg_non_existent_export_profile is not changed + - nm_l3out_extepg_remove_export_profile is changed + - nm_l3out_extepg_add_export_profile is changed + - query_l3out_extepg_optional_params is not changed + - nm_l3out_extepg_optional_params.current.0.l3extInstP.attributes.name == "extepg_params" + - nm_l3out_extepg_optional_params.current.0.l3extInstP.attributes.prio == "level6" + - profile1_name == "profile1" + - profile1_direction == "import" + - profile2_name == "profile2" + - profile2_direction == "export" + - query_profile1_name == "profile1" + - query_profile1_direction == "import" + - query_profile2_name == "profile2" + - query_profile2_direction == "export" + - profile2_exists == "profile2" + - profile2_removed == "" + - profile2_direction_removed == "" + + - name: Verify l3out external epg with intra_ext_epg_isolation + ansible.builtin.assert: + that: + - nm_l3out_extepg_isolation.current.0.l3extInstP.attributes.pcEnfPref == "enforced" + - query_l3out_extepg_isolation.current.0.l3extInstP.attributes.pcEnfPref == "enforced" + when: + - version.current.0.topSystem.attributes.version is version('5.0', '>=') + + # TEST REMOVAL L3OUT EXTERNAL EPG + + - name: Remove l3out external epg 1 ( check mode ) + cisco.aci.aci_l3out_extepg: &remove_l3out_extepg_1 + <<: *add_l3out_extepg_1 + state: absent + check_mode: true + register: cm_remove_l3out_extepg_1 + + - name: Remove l3out external epg 1 + cisco.aci.aci_l3out_extepg: + <<: *remove_l3out_extepg_1 + register: nm_remove_l3out_extepg_1 + + - name: Remove l3out external epg 1 again + cisco.aci.aci_l3out_extepg: + <<: *remove_l3out_extepg_1 + register: nm_remove_l3out_extepg_1_again + + - name: Remove l3out external epg params + cisco.aci.aci_l3out_extepg: + <<: *aci_info + tenant: ansible_test + l3out: l3out_1 + extepg: extepg_params + state: absent + register: remove_l3out_extepg_params + + - name: Remove l3out external epg with intra_ext_epg_isolation + cisco.aci.aci_l3out_extepg: + <<: *aci_info + tenant: ansible_test + l3out: l3out_1 + extepg: extepg_isolation + state: absent + register: remove_l3out_extepg_isolation + + - name: Verify removal epg monitoring policies + ansible.builtin.assert: + that: + - cm_remove_l3out_extepg_1 is changed + - cm_remove_l3out_extepg_1.proposed == {} + - nm_remove_l3out_extepg_1 is changed + - nm_remove_l3out_extepg_1.previous.0.l3extInstP.attributes.name == "extepg_1" + - nm_remove_l3out_extepg_1.current == [] + - nm_remove_l3out_extepg_1_again is not changed + - nm_remove_l3out_extepg_1_again.previous == [] + - nm_remove_l3out_extepg_1_again.current == [] + - remove_l3out_extepg_params is changed + - remove_l3out_extepg_params.current == [] + - remove_l3out_extepg_isolation.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_profile/tasks/main.yml index 4466369d5..b3ad827f1 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_profile/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_profile/tasks/main.yml @@ -62,6 +62,7 @@ cisco.aci.aci_l3out_logical_interface_profile: &intf_present <<: *np_present interface_profile: INTFS + description: test check_mode: true register: cm_add_intf @@ -77,6 +78,7 @@ - nm_add_intf is changed - cm_add_intf.previous == nm_add_intf.previous == [] - cm_add_intf.sent.l3extLIfP.attributes.name == nm_add_intf.sent.l3extLIfP.attributes.name == 'INTFS' + - cm_add_intf.sent.l3extLIfP.attributes.descr == nm_add_intf.sent.l3extLIfP.attributes.descr == 'test' - nm_add_intf.current.0.l3extLIfP.attributes.annotation == 'orchestrator:ansible' - name: Add profile again, check if idempotency works @@ -94,11 +96,13 @@ cisco.aci.aci_l3out_logical_interface_profile: &intf_update <<: *intf_present nd_policy: NDTEST + description: new test register: update_intf - name: Verify update_intf assert: that: + - update_intf.sent.l3extLIfP.attributes.descr == 'new test' - update_intf is changed - update_intf.previous != [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml index 68bc64b20..1d61ee3e3 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml @@ -1,6 +1,11 @@ # Author: Marcel Zehnder (@maercu) # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + # SET VARS - name: Set vars set_fact: @@ -79,9 +84,9 @@ - cm_add_node is changed - nm_add_node is changed - cm_add_node.previous == nm_add_node.previous == [] - - cm_add_node.sent.l3extRsNodeL3OutAtt.attributes.rtrId == nm_add_node.sent.l3extRsNodeL3OutAtt.attributes.rtrId == '111.111.111.111' - - cm_add_node.sent.l3extRsNodeL3OutAtt.attributes.rtrIdLoopBack == nm_add_node.sent.l3extRsNodeL3OutAtt.attributes.rtrIdLoopBack == 'no' - - cm_add_node.sent.l3extRsNodeL3OutAtt.attributes.tDn == nm_add_node.sent.l3extRsNodeL3OutAtt.attributes.tDn == 'topology/pod-1/node-111' + - cm_add_node.sent.l3extRsNodeL3OutAtt.attributes.rtrId == nm_add_node.current.0.l3extRsNodeL3OutAtt.attributes.rtrId == '111.111.111.111' + - cm_add_node.sent.l3extRsNodeL3OutAtt.attributes.rtrIdLoopBack == nm_add_node.current.0.l3extRsNodeL3OutAtt.attributes.rtrIdLoopBack == 'no' + - cm_add_node.sent.l3extRsNodeL3OutAtt.attributes.tDn == nm_add_node.current.0.l3extRsNodeL3OutAtt.attributes.tDn == 'topology/pod-1/node-111' - nm_add_node.current.0.l3extRsNodeL3OutAtt.attributes.annotation == 'orchestrator:ansible' - name: Add node again, check if idempotency works @@ -101,19 +106,37 @@ router_id: 11.11.11.11 register: update_node + - name: Add loopback address + cisco.aci.aci_l3out_logical_node: &node_add_loopback + <<: *node_update + loopback_address: 11.11.11.12 + register: add_loopback_ip + + - name: Remove loopback address + cisco.aci.aci_l3out_logical_node: &node_remove_loopback + <<: *node_add_loopback + loopback_address: "" + register: remove_loopback_ip + - name: Verify update_node assert: that: - update_node is changed - update_node.previous != [] - - update_node.sent.l3extRsNodeL3OutAtt.attributes.rtrId == '11.11.11.11' + - update_node.current.0.l3extRsNodeL3OutAtt.attributes.rtrId == '11.11.11.11' + - add_loopback_ip is changed + - add_loopback_ip.previous != [] + - add_loopback_ip.current.0.l3extRsNodeL3OutAtt.children.0.l3extLoopBackIfP.attributes.addr == '11.11.11.12' + - remove_loopback_ip is changed + - remove_loopback_ip.previous != [] # ADD ANOTHER NODE - name: Add another node - cisco.aci.aci_l3out_logical_node: + cisco.aci.aci_l3out_logical_node: &second_node_present <<: *node_present node_id: 112 router_id: 12.12.12.12 + loopback_address: 12.12.12.13 # QUERY ALL NODES - name: Query all nodes @@ -131,7 +154,7 @@ # QUERY A SPECIFIC NODE - name: Query a specific node cisco.aci.aci_l3out_logical_node: - <<: *node_update + <<: *second_node_present state: query register: query_spec_node @@ -140,11 +163,13 @@ that: - query_spec_node is not changed - query_spec_node.current|length == 1 + - query_spec_node.current.0.l3extRsNodeL3OutAtt.attributes.rtrId == '12.12.12.12' + - query_spec_node.current.0.l3extRsNodeL3OutAtt.children.0.l3extLoopBackIfP.attributes.addr == '12.12.12.13' # REMOVE NODE - name: Remove node cisco.aci.aci_l3out_logical_node: - <<: *node_update + <<: *node_remove_loopback state: absent register: remove_node @@ -153,3 +178,9 @@ that: - remove_node is changed - remove_node.current == [] + + - name: Remove test tenant - clean-up the environment + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_test + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_route_tag_policy/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_route_tag_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_route_tag_policy/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_route_tag_policy/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_route_tag_policy/tasks/main.yml new file mode 100644 index 000000000..d7ad61c6d --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_route_tag_policy/tasks/main.yml @@ -0,0 +1,149 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: info + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Create tenant for tests + cisco.aci.aci_tenant: &aci_tenant_present + <<: *aci_info + state: present + tenant: ansible_tenant + + - name: Create first l3out route tag policy (check_mode) + cisco.aci.aci_l3out_route_tag_policy: &aci_rtp_present + <<: *aci_tenant_present + rtp: anstest + description: rtp test + tag: 1000 + state: present + check_mode: true + register: cm_add_rtp + + - name: Create first l3out route tag policy (normal_mode) + cisco.aci.aci_l3out_route_tag_policy: + <<: *aci_rtp_present + register: nm_add_rtp + + - name: Create first l3out route tag policy again - testing idempotency + cisco.aci.aci_l3out_route_tag_policy: + <<: *aci_rtp_present + register: add_rtp_idempotency + + - name: Create second l3out route tag policy + cisco.aci.aci_l3out_route_tag_policy: &aci_rtp_present_2 + <<: *aci_tenant_present + rtp: anstest_2 + state: present + register: nm_add_rtp_2 + + - name: asserts for creation tasks + assert: + that: + - cm_add_rtp is changed + - cm_add_rtp.previous == [] + - cm_add_rtp.current == [] + - nm_add_rtp is changed + - nm_add_rtp.current.0.l3extRouteTagPol.attributes.name == "anstest" + - nm_add_rtp.current.0.l3extRouteTagPol.attributes.descr == "rtp test" + - nm_add_rtp.current.0.l3extRouteTagPol.attributes.tag == "1000" + - add_rtp_idempotency is not changed + - nm_add_rtp_2 is changed + - nm_add_rtp_2.current.0.l3extRouteTagPol.attributes.name == "anstest_2" + - nm_add_rtp_2.current.0.l3extRouteTagPol.attributes.tag == "4294967295" + + - name: Query all l3out route tag policies + cisco.aci.aci_l3out_route_tag_policy: + <<: *aci_tenant_present + state: query + register: query_all_rtp + + - name: Query first l3out route tag policy + cisco.aci.aci_l3out_route_tag_policy: + <<: *aci_rtp_present + state: query + register: query_first_rtp + + - name: asserts query tasks + assert: + that: + - query_all_rtp is not changed + - query_all_rtp.current.0.fvTenant.children | length >= 2 + - query_all_rtp.current.0.fvTenant.children.0.l3extRouteTagPol.attributes.name == "anstest_2" + - query_all_rtp.current.0.fvTenant.children.1.l3extRouteTagPol.attributes.name == "anstest" + - query_first_rtp is not changed + - query_first_rtp.current.0.l3extRouteTagPol.attributes.name == "anstest" + - query_first_rtp.current.0.l3extRouteTagPol.attributes.descr == "rtp test" + - query_first_rtp.current.0.l3extRouteTagPol.attributes.tag == "1000" + + - name: Delete first l3out route tag policy (check_mode) + cisco.aci.aci_l3out_route_tag_policy: + <<: *aci_rtp_present + state: absent + check_mode: true + register: cm_delete_rtp + + - name: Delete first l3out route tag policy (normal_mode) + cisco.aci.aci_l3out_route_tag_policy: + <<: *aci_rtp_present + state: absent + register: nm_delete_rtp + + - name: Delete first l3out route tag policy agaim - testing idempotency + cisco.aci.aci_l3out_route_tag_policy: + <<: *aci_rtp_present + state: absent + register: delete_rtp_idempotency + + - name: Delete second l3out route tag policy + cisco.aci.aci_l3out_route_tag_policy: + <<: *aci_rtp_present_2 + state: absent + register: nm_delete_rtp_2 + + - name: asserts for deletion tasks + assert: + that: + - cm_delete_rtp is changed + - cm_delete_rtp.proposed == {} + - nm_delete_rtp is changed + - nm_delete_rtp.previous != [] + - nm_delete_rtp.current == [] + - delete_rtp_idempotency is not changed + - delete_rtp_idempotency.previous == [] + - nm_delete_rtp_2 is changed + - nm_delete_rtp_2.previous != [] + - nm_delete_rtp_2.current == [] + + - name: Remove ansible_tenant - cleanup before ending tests + cisco.aci.aci_tenant: + <<: *aci_tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_group/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_group/tasks/main.yml new file mode 100644 index 000000000..12284c8a6 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_group/tasks/main.yml @@ -0,0 +1,175 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Clean Environment + - name: Create Scheduler + aci_fabric_scheduler: &aci_fabric_scheduler_present + <<: *aci_info + name: anstest_scheduler + state: present + + - name: Create maintenance policy + aci_maintenance_policy: &aci_maintenance_policy_present + <<: *aci_info + name: anstest_policy + scheduler: anstest_scheduler + state: present + + - name: Ensure first maintenance group does not exist + aci_maintenance_group: &aci_maintenance_group_absent + <<: *aci_info + group: anstest_group + policy: anstest_policy + firmware_nodes_type: controller + type_group: all + description: test for maintenance group + state: absent + + - name: Ensure second maintenance group does not exist + aci_maintenance_group: &aci_maintenance_group_2_absent + <<: *aci_info + group: anstest_group_2 + policy: anstest_policy_2 + state: absent + + - name: Create first maintenance group (check_mode) + aci_maintenance_group: &aci_maintenance_group_present + <<: *aci_maintenance_group_absent + state: present + check_mode: true + register: cm_add_maintenance_group_1 + + - name: Create first maintenance group (normal_mode) + aci_maintenance_group: + <<: *aci_maintenance_group_present + register: nm_add_maintenance_group_1 + + - name: Create first maintenance group again - testing idempotency + aci_maintenance_group: + <<: *aci_maintenance_group_present + register: idempotency_add_maintenance_group_1 + + - name: Create second maintenance group + aci_maintenance_group: &aci_maintenance_group_2_present + <<: *aci_maintenance_group_2_absent + state: present + register: nm_add_maintenance_group_2 + + - name: Asserts for creation tasks + assert: + that: + - cm_add_maintenance_group_1 is changed + - cm_add_maintenance_group_1.previous == [] + - cm_add_maintenance_group_1.current == [] + - nm_add_maintenance_group_1 is changed + - nm_add_maintenance_group_1.current.0.maintMaintGrp.attributes.name == "anstest_group" + - nm_add_maintenance_group_1.current.0.maintMaintGrp.attributes.fwtype == "controller" + - nm_add_maintenance_group_1.current.0.maintMaintGrp.attributes.type == "ALL" + - nm_add_maintenance_group_1.current.0.maintMaintGrp.children.0.maintRsMgrpp.attributes.tnMaintMaintPName == "anstest_policy" + - idempotency_add_maintenance_group_1 is not changed + - nm_add_maintenance_group_2 is changed + - nm_add_maintenance_group_2.current.0.maintMaintGrp.attributes.name == "anstest_group_2" + - nm_add_maintenance_group_2.current.0.maintMaintGrp.children.0.maintRsMgrpp.attributes.tnMaintMaintPName == "anstest_policy_2" + - nm_add_maintenance_group_2.current.0.maintMaintGrp.attributes.fwtype == "switch" + - nm_add_maintenance_group_2.current.0.maintMaintGrp.attributes.type == "range" + + + - name: Query all maintenance groups + aci_maintenance_group: + <<: *aci_info + state: query + register: query_all_maintenance_group + + - name: Query first maintenance group + aci_maintenance_group: + <<: *aci_maintenance_group_present + state: query + register: query_first_maintenance_group + + - name: Asserts for query tasks + assert: + that: + - query_all_maintenance_group is not changed + - query_all_maintenance_group.current | length >= 2 + - '"maintRsMgrpp" in query_all_maintenance_group.filter_string' + - '"class/maintMaintGrp.json" in query_all_maintenance_group.url' + - query_all_maintenance_group.current.0.maintMaintGrp.attributes.name == "anstest_group" + - query_all_maintenance_group.current.1.maintMaintGrp.attributes.name == "anstest_group_2" + - query_first_maintenance_group is not changed + - query_first_maintenance_group.current.0.maintMaintGrp.attributes.name == "anstest_group" + - query_first_maintenance_group.current.0.maintMaintGrp.children.0.maintRsMgrpp.attributes.tnMaintMaintPName == "anstest_policy" + - query_first_maintenance_group.current.0.maintMaintGrp.attributes.fwtype == "controller" + - query_first_maintenance_group.current.0.maintMaintGrp.attributes.type == "ALL" + + - name: Delete first maintenance group (check_mode) + aci_maintenance_group: + <<: *aci_maintenance_group_present + state: absent + check_mode: true + register: cm_delete_maintenance_group_1 + + - name: Delete first maintenance group (normal_mode) + aci_maintenance_group: + <<: *aci_maintenance_group_present + state: absent + register: nm_delete_maintenance_group_1 + + - name: Delete first maintenance group again - testing idempotency + aci_maintenance_group: + <<: *aci_maintenance_group_present + state: absent + register: idempotency_delete_maintenance_group_1 + + - name: Delete second maintenance group (normal_mode) + aci_maintenance_group: + <<: *aci_maintenance_group_2_present + state: absent + register: nm_delete_maintenance_group_2 + + - name: Asserts for deletion tasks + assert: + that: + - cm_delete_maintenance_group_1 is changed + - cm_delete_maintenance_group_1.proposed == {} + - nm_delete_maintenance_group_1 is changed + - nm_delete_maintenance_group_1.previous != [] + - nm_delete_maintenance_group_1.current == [] + - idempotency_delete_maintenance_group_1 is not changed + - idempotency_delete_maintenance_group_1.previous == [] + - nm_delete_maintenance_group_2 is changed + - nm_delete_maintenance_group_2.previous != [] + - nm_delete_maintenance_group_2.current == [] + + - name: Delete maintenance policy - clean up the environment + aci_maintenance_policy: + <<: *aci_maintenance_policy_present + state: absent + + - name: Delete scheduler - clean up the environment + aci_fabric_scheduler: + <<: *aci_fabric_scheduler_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_group_node/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_group_node/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_group_node/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_group_node/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_group_node/tasks/main.yml new file mode 100644 index 000000000..9be9ecbe8 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_group_node/tasks/main.yml @@ -0,0 +1,174 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Clean Environment + - name: Create Scheduler + aci_fabric_scheduler: &aci_fabric_scheduler_present + <<: *aci_info + name: anstest_scheduler + state: present + + - name: Create maintenance policy + aci_maintenance_policy: &aci_maintenance_policy_present + <<: *aci_info + name: anstest_policy + scheduler: anstest_scheduler + state: present + + - name: Create maintenance groupe + aci_maintenance_group: &aci_maintenance_group_present + <<: *aci_info + group: anstest_group + policy: anstest_policy + state: present + + - name: Ensure first maintenance group node does not exist + aci_maintenance_group_node: &aci_maintenance_group_node_absent + <<: *aci_info + group: anstest_group + node: 1001 + state: absent + + - name: Ensure second maintenance group node does not exist + aci_maintenance_group_node: &aci_maintenance_group_node_2_absent + <<: *aci_info + group: anstest_group + node: 1002 + state: absent + + - name: Create first maintenance group node (check_mode) + aci_maintenance_group_node: &aci_maintenance_group_node_present + <<: *aci_maintenance_group_node_absent + state: present + check_mode: true + register: cm_add_maintenance_group_node_1 + + - name: Create first maintenance group node (normal_mode) + aci_maintenance_group_node: + <<: *aci_maintenance_group_node_present + register: nm_add_maintenance_group_node_1 + + - name: Create first maintenance group node again - testing idempotency + aci_maintenance_group_node: + <<: *aci_maintenance_group_node_present + register: idempotency_add_maintenance_group_node_1 + + - name: Create second maintenance group node + aci_maintenance_group_node: &aci_maintenance_group_node_2_present + <<: *aci_maintenance_group_node_2_absent + state: present + register: nm_add_maintenance_group_node_2 + + - name: Asserts for creation tasks + assert: + that: + - cm_add_maintenance_group_node_1 is changed + - cm_add_maintenance_group_node_1.previous == [] + - cm_add_maintenance_group_node_1.current == [] + - nm_add_maintenance_group_node_1 is changed + - nm_add_maintenance_group_node_1.current.0.fabricNodeBlk.attributes.from_ == "1001" + - nm_add_maintenance_group_node_1.current.0.fabricNodeBlk.attributes.to_ == "1001" + - idempotency_add_maintenance_group_node_1 is not changed + - nm_add_maintenance_group_node_2 is changed + - nm_add_maintenance_group_node_2.current.0.fabricNodeBlk.attributes.from_ == "1002" + - nm_add_maintenance_group_node_2.current.0.fabricNodeBlk.attributes.to_ == "1002" + + + - name: Query all maintenance group nodes + aci_maintenance_group_node: + <<: *aci_info + state: query + register: query_all_maintenance_group_node + + - name: Query first maintenance group nnode + aci_maintenance_group_node: + <<: *aci_maintenance_group_node_present + state: query + register: query_first_maintenance_group_node + + - name: Asserts for query tasks + assert: + that: + - query_all_maintenance_group_node is not changed + - query_all_maintenance_group_node.current | length >= 2 + - query_first_maintenance_group_node is not changed + - query_first_maintenance_group_node.current.0.fabricNodeBlk.attributes.from_ == "1001" + - query_first_maintenance_group_node.current.0.fabricNodeBlk.attributes.to_ == "1001" + + - name: Delete first maintenance group (check_mode) + aci_maintenance_group_node: + <<: *aci_maintenance_group_node_present + state: absent + check_mode: true + register: cm_delete_maintenance_group_node_1 + + - name: Delete first maintenance group (normal_mode) + aci_maintenance_group_node: + <<: *aci_maintenance_group_node_present + state: absent + register: nm_delete_maintenance_group_node_1 + + - name: Delete first maintenance group again - testing idempotency + aci_maintenance_group_node: + <<: *aci_maintenance_group_node_present + state: absent + register: idempotency_delete_maintenance_group_1 + + - name: Delete second maintenance group (normal_mode) + aci_maintenance_group_node: + <<: *aci_maintenance_group_node_2_present + state: absent + register: nm_delete_maintenance_group_node_2 + + - name: Asserts for deletion tasks + assert: + that: + - cm_delete_maintenance_group_node_1 is changed + - cm_delete_maintenance_group_node_1.proposed == {} + - nm_delete_maintenance_group_node_1 is changed + - nm_delete_maintenance_group_node_1.previous != [] + - nm_delete_maintenance_group_node_1.current == [] + - idempotency_delete_maintenance_group_1 is not changed + - idempotency_delete_maintenance_group_1.previous == [] + - nm_delete_maintenance_group_node_2 is changed + - nm_delete_maintenance_group_node_2.previous != [] + - nm_delete_maintenance_group_node_2.current == [] + + - name: Delete maintenance group - clean up the environment + aci_maintenance_group: + <<: *aci_maintenance_group_present + state: absent + + - name: Delete maintenance policy - clean up the environment + aci_maintenance_policy: + <<: *aci_maintenance_policy_present + state: absent + + - name: Delete scheduler - clean up the environment + aci_fabric_scheduler: + <<: *aci_fabric_scheduler_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_policy/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_policy/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_policy/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_policy/tasks/main.yml new file mode 100644 index 000000000..8628c2a84 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_maintenance_policy/tasks/main.yml @@ -0,0 +1,184 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Clean Environment + - name: Create Scheduler + aci_fabric_scheduler: &aci_fabric_scheduler_present + <<: *aci_info + name: anstest_scheduler + state: present + + - name: Ensure first maintenance policy does not exist + aci_maintenance_policy: &aci_maintenance_policy_absent + <<: *aci_info + name: anstest_policy + description: test for maintenance policy + run_mode: pause_never + graceful: True + scheduler: anstest_scheduler + ignore_compat: true + admin_state: untriggered + download_state: untriggered + notify_condition: notify_always_between_sets + smu_operation: smu_install + smu_operation_flags: smu_reload_skip + state: absent + + - name: Ensure second maintenance policy does not exist + aci_maintenance_policy: &aci_maintenance_policy_2_absent + <<: *aci_info + name: anstest_policy_2 + scheduler: anstest_scheduler + state: absent + + - name: Create first maintenance policy (check_mode) + aci_maintenance_policy: &aci_maintenance_policy_present + <<: *aci_maintenance_policy_absent + state: present + check_mode: true + register: cm_add_maintenance_policy_1 + + - name: Create first maintenance policy (normal_mode) + aci_maintenance_policy: + <<: *aci_maintenance_policy_present + register: nm_add_maintenance_policy_1 + + - name: Create first maintenance policy again - testing idempotency + aci_maintenance_policy: + <<: *aci_maintenance_policy_present + register: idempotency_add_maintenance_policy_1 + + - name: Create second maintenance policy + aci_maintenance_policy: &aci_maintenance_policy_2_present + <<: *aci_maintenance_policy_2_absent + state: present + register: nm_add_maintenance_policy_2 + + - name: Asserts for creation tasks + assert: + that: + - cm_add_maintenance_policy_1 is changed + - cm_add_maintenance_policy_1.previous == [] + - cm_add_maintenance_policy_1.current == [] + - nm_add_maintenance_policy_1 is changed + - nm_add_maintenance_policy_1.current.0.maintMaintP.attributes.adminSt == "untriggered" + - nm_add_maintenance_policy_1.current.0.maintMaintP.attributes.downloadSt == "untriggered" + - nm_add_maintenance_policy_1.current.0.maintMaintP.attributes.notifCond == "notifyAlwaysBetweenSets" + - nm_add_maintenance_policy_1.current.0.maintMaintP.attributes.smuOperation == "smuInstall" + - nm_add_maintenance_policy_1.current.0.maintMaintP.attributes.smuOperationFlags == "smuReloadSkip" + - nm_add_maintenance_policy_1.current.0.maintMaintP.attributes.graceful == "yes" + - nm_add_maintenance_policy_1.current.0.maintMaintP.attributes.ignoreCompat == "yes" + - nm_add_maintenance_policy_1.current.0.maintMaintP.attributes.name == "anstest_policy" + - nm_add_maintenance_policy_1.current.0.maintMaintP.attributes.runMode == "pauseNever" + - nm_add_maintenance_policy_1.current.0.maintMaintP.children.0.maintRsPolScheduler.attributes.tnTrigSchedPName == "anstest_scheduler" + - idempotency_add_maintenance_policy_1 is not changed + - nm_add_maintenance_policy_2 is changed + - nm_add_maintenance_policy_2.current.0.maintMaintP.attributes.adminSt == "untriggered" + - nm_add_maintenance_policy_2.current.0.maintMaintP.attributes.graceful == "no" + - nm_add_maintenance_policy_2.current.0.maintMaintP.attributes.ignoreCompat == "no" + - nm_add_maintenance_policy_2.current.0.maintMaintP.attributes.downloadSt == "untriggered" + - nm_add_maintenance_policy_2.current.0.maintMaintP.attributes.notifCond == "notifyOnlyOnFailures" + - nm_add_maintenance_policy_2.current.0.maintMaintP.attributes.smuOperation == "smuInstall" + - nm_add_maintenance_policy_2.current.0.maintMaintP.attributes.smuOperationFlags == "smuReloadImmediate" + - nm_add_maintenance_policy_2.current.0.maintMaintP.attributes.name == "anstest_policy_2" + - nm_add_maintenance_policy_2.current.0.maintMaintP.attributes.runMode == "pauseOnlyOnFailures" + - nm_add_maintenance_policy_2.current.0.maintMaintP.children.0.maintRsPolScheduler.attributes.tnTrigSchedPName == "anstest_scheduler" + + - name: Query all maintenance policies + aci_maintenance_policy: + <<: *aci_info + state: query + register: query_all_maintenance_policy + + - name: Query first maintenance policy + aci_maintenance_policy: + <<: *aci_maintenance_policy_present + state: query + register: query_first_maintenance_policy + + - name: Asserts for query tasks + assert: + that: + - query_all_maintenance_policy is not changed + - query_all_maintenance_policy.current | length >= 2 + - '"maintRsPolScheduler" in query_all_maintenance_policy.filter_string' + - '"class/maintMaintP.json" in query_all_maintenance_policy.url' + - query_first_maintenance_policy is not changed + - query_first_maintenance_policy.current.0.maintMaintP.attributes.adminSt == "untriggered" + - query_first_maintenance_policy.current.0.maintMaintP.attributes.downloadSt == "untriggered" + - query_first_maintenance_policy.current.0.maintMaintP.attributes.notifCond == "notifyAlwaysBetweenSets" + - query_first_maintenance_policy.current.0.maintMaintP.attributes.smuOperation == "smuInstall" + - query_first_maintenance_policy.current.0.maintMaintP.attributes.smuOperationFlags == "smuReloadSkip" + - query_first_maintenance_policy.current.0.maintMaintP.attributes.graceful == "yes" + - query_first_maintenance_policy.current.0.maintMaintP.attributes.ignoreCompat == "yes" + - query_first_maintenance_policy.current.0.maintMaintP.attributes.name == "anstest_policy" + - query_first_maintenance_policy.current.0.maintMaintP.attributes.runMode == "pauseNever" + - query_first_maintenance_policy.current.0.maintMaintP.children.0.maintRsPolScheduler.attributes.tnTrigSchedPName == "anstest_scheduler" + + - name: Delete first maintenance policy (check_mode) + aci_maintenance_policy: + <<: *aci_maintenance_policy_present + state: absent + check_mode: true + register: cm_delete_maintenance_policy_1 + + - name: Delete first maintenance policy (normal_mode) + aci_maintenance_policy: + <<: *aci_maintenance_policy_present + state: absent + register: nm_delete_maintenance_policy_1 + + - name: Delete first maintenance policy again - testing idempotency + aci_maintenance_policy: + <<: *aci_maintenance_policy_present + state: absent + register: idempotency_delete_maintenance_policy_1 + + - name: Delete second maintenance policy (normal_mode) + aci_maintenance_policy: + <<: *aci_maintenance_policy_2_present + state: absent + register: nm_delete_maintenance_policy_2 + + - name: Asserts for deletion tasks + assert: + that: + - cm_delete_maintenance_policy_1 is changed + - cm_delete_maintenance_policy_1.proposed == {} + - nm_delete_maintenance_policy_1 is changed + - nm_delete_maintenance_policy_1.previous != [] + - nm_delete_maintenance_policy_1.current == [] + - idempotency_delete_maintenance_policy_1 is not changed + - idempotency_delete_maintenance_policy_1.previous == [] + - nm_delete_maintenance_policy_2 is changed + - nm_delete_maintenance_policy_2.previous != [] + - nm_delete_maintenance_policy_2.current == [] + + - name: Delete scheduler - clean up the environment + aci_fabric_scheduler: + <<: *aci_fabric_scheduler_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_match_as_path_regex_term/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_as_path_regex_term/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_as_path_regex_term/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_match_as_path_regex_term/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_as_path_regex_term/tasks/main.yml new file mode 100644 index 000000000..cdabd8b4e --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_as_path_regex_term/tasks/main.yml @@ -0,0 +1,150 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a match rule profile + aci_match_rule: + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + description: match rule profile for ansible_tenant tenant + state: present + register: cm_add_match_rule + + - name: Add a match regex AS-Path term (check_mode) + aci_match_as_path_regex_term: &aci_match_as_path_regex_term_present + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + match_as_path_regex_term: ansible_match_as_path_regex_term_1 + description: match regex AS-Path term 1 for ansible_match_rule match rule profile + regex: .* + state: present + check_mode: true + register: cm_add_match_as_path_regex_term + + - name: Add a match regex AS-Path term (normal_mode) + aci_match_as_path_regex_term: + <<: *aci_match_as_path_regex_term_present + register: nm_add_match_as_path_regex_term + + - name: Add the first match regex AS-Path term again - testing idempotency + aci_match_as_path_regex_term: + <<: *aci_match_as_path_regex_term_present + register: nm_add_match_as_path_regex_term_idempotency + + - name: Add a second match regex AS-Path term (normal_mode) + aci_match_as_path_regex_term: + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + match_as_path_regex_term: ansible_match_as_path_regex_term_2 + description: match regex AS-Path term 2 for ansible_match_rule match rule profile + state: present + register: nm_add_match_as_path_regex_term_2 + + - name: Asserts for match regex AS-Path terms creation tasks + assert: + that: + - cm_add_match_as_path_regex_term is changed + - cm_add_match_as_path_regex_term.previous == [] + - cm_add_match_as_path_regex_term.current == [] + - nm_add_match_as_path_regex_term is changed + - nm_add_match_as_path_regex_term.current.0.rtctrlMatchAsPathRegexTerm.attributes.name == "ansible_match_as_path_regex_term_1" + - nm_add_match_as_path_regex_term.current.0.rtctrlMatchAsPathRegexTerm.attributes.regex == ".*" + - nm_add_match_as_path_regex_term_idempotency is not changed + - nm_add_match_as_path_regex_term_2 is changed + - nm_add_match_as_path_regex_term_2.previous == [] + - nm_add_match_as_path_regex_term_2.current.0.rtctrlMatchAsPathRegexTerm.attributes.name == "ansible_match_as_path_regex_term_2" + - nm_add_match_as_path_regex_term_2.current.0.rtctrlMatchAsPathRegexTerm.attributes.regex == "" + + - name: Query all match regex AS-Path terms + aci_match_as_path_regex_term: + <<: *aci_info + state: query + register: query_all_match_as_path_regex_term + + - name: Query ansible_match_as_path_regex_term_1 + aci_match_as_path_regex_term: + <<: *aci_match_as_path_regex_term_present + state: query + register: query_ansible_match_as_path_regex_term_1 + + - name: Asserts query tasks + assert: + that: + - query_all_match_as_path_regex_term is not changed + - query_all_match_as_path_regex_term.current|length >= 2 + - query_ansible_match_as_path_regex_term_1 is not changed + - query_ansible_match_as_path_regex_term_1.current.0.rtctrlMatchAsPathRegexTerm.attributes.name == "ansible_match_as_path_regex_term_1" + - query_ansible_match_as_path_regex_term_1.current.0.rtctrlMatchAsPathRegexTerm.attributes.regex == ".*" + + - name: Remove match regex AS-Path term for l3out (check_mode) + aci_match_as_path_regex_term: &match_as_path_regex_term_absent + <<: *aci_match_as_path_regex_term_present + state: absent + check_mode: true + register: cm_remove_match_as_path_regex_term + + - name: Remove match regex AS-Path term for l3out (normal_mode) + aci_match_as_path_regex_term: + <<: *match_as_path_regex_term_absent + register: nm_remove_match_as_path_regex_term + + - name: Remove match regex AS-Path term for l3out again - testing previous Removal + aci_match_as_path_regex_term: + <<: *match_as_path_regex_term_absent + register: nm_remove_match_as_path_regex_term_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_match_as_path_regex_term is changed + - cm_remove_match_as_path_regex_term.proposed == {} + - nm_remove_match_as_path_regex_term is changed + - nm_remove_match_as_path_regex_term.previous != [] + - nm_remove_match_as_path_regex_term.method == "DELETE" + - nm_remove_match_as_path_regex_term_idempotency is not changed + - nm_remove_match_as_path_regex_term_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_factor/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_factor/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_factor/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_factor/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_factor/tasks/main.yml new file mode 100644 index 000000000..2cc1f3ac1 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_factor/tasks/main.yml @@ -0,0 +1,157 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a match rule profile + aci_match_rule: + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + description: match rule profile for ansible_tenant tenant + state: present + + - name: Add a match community term + aci_match_community_term: + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + match_community_term: ansible_match_community_term + description: match community term for ansible_match_rule match rule profile + state: present + + - name: Add a match community factor (check_mode) + aci_match_community_factor: &aci_match_community_factor_present + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + match_community_term: ansible_match_community_term + community: regular:as2-nn2:4:15 + scope: non-transitive + description: match community factor 1 for ansible_match_community_term + state: present + check_mode: true + register: cm_add_match_community_factor + + - name: Add a match community factor (normal_mode) + aci_match_community_factor: + <<: *aci_match_community_factor_present + register: nm_add_match_community_factor + + - name: Add the first match community factor again - testing idempotency + aci_match_community_factor: + <<: *aci_match_community_factor_present + register: nm_add_match_community_factor_idempotency + + - name: Add a second match community factor (normal_mode) + aci_match_community_factor: + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + match_community_term: ansible_match_community_term + community: regular:as2-nn2:4:16 + description: match community factor 2 for ansible_match_community_term + state: present + register: nm_add_match_community_factor_2 + + - name: Asserts for match community factors creation tasks + assert: + that: + - cm_add_match_community_factor is changed + - cm_add_match_community_factor.previous == [] + - cm_add_match_community_factor.current == [] + - nm_add_match_community_factor is changed + - nm_add_match_community_factor.current.0.rtctrlMatchCommFactor.attributes.community == "regular:as2-nn2:4:15" + - nm_add_match_community_factor_idempotency is not changed + - nm_add_match_community_factor_2 is changed + - nm_add_match_community_factor_2.previous == [] + - nm_add_match_community_factor_2.current.0.rtctrlMatchCommFactor.attributes.community == "regular:as2-nn2:4:16" + + - name: Query all match community factors + aci_match_community_factor: + <<: *aci_info + state: query + register: query_all_match_community_factor + + - name: Query a specific match community factor + aci_match_community_factor: + <<: *aci_match_community_factor_present + state: query + register: query_ansible_match_community_factor_1 + + - name: Asserts query tasks + assert: + that: + - query_all_match_community_factor is not changed + - query_all_match_community_factor.current|length >= 2 + - query_ansible_match_community_factor_1 is not changed + - query_ansible_match_community_factor_1.current.0.rtctrlMatchCommFactor.attributes.community == "regular:as2-nn2:4:15" + + - name: Remove match community factor (check_mode) + aci_match_community_factor: &match_community_term_absent + <<: *aci_match_community_factor_present + state: absent + check_mode: true + register: cm_remove_match_community_factor + + - name: Remove match community factor (normal_mode) + aci_match_community_factor: + <<: *match_community_term_absent + register: nm_remove_match_community_factor + + - name: Remove match community factor again - testing previous Removal + aci_match_community_factor: + <<: *match_community_term_absent + register: nm_remove_match_community_factor_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_match_community_factor is changed + - cm_remove_match_community_factor.proposed == {} + - nm_remove_match_community_factor is changed + - nm_remove_match_community_factor.previous != [] + - nm_remove_match_community_factor.method == "DELETE" + - nm_remove_match_community_factor_idempotency is not changed + - nm_remove_match_community_factor_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_regex_term/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_regex_term/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_regex_term/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_regex_term/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_regex_term/tasks/main.yml new file mode 100644 index 000000000..c0b12c78c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_regex_term/tasks/main.yml @@ -0,0 +1,152 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a match rule profile + aci_match_rule: + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + description: match rule profile for ansible_tenant tenant + state: present + register: cm_add_match_rule + + - name: Add a match community regex term (check_mode) + aci_match_community_regex_term: &aci_match_community_regex_term_present + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + name: ansible_community_regex_extended + description: match extended community regex term for ansible_match_rule match rule profile + community_type: extended + regex: .* + state: present + check_mode: true + register: cm_add_match_community_regex_term + + - name: Add a match community regex term (normal_mode) + aci_match_community_regex_term: + <<: *aci_match_community_regex_term_present + register: nm_add_match_community_regex_term + + - name: Add the first match community regex term again - testing idempotency + aci_match_community_regex_term: + <<: *aci_match_community_regex_term_present + register: nm_add_match_community_regex_term_idempotency + + - name: Add a second match community regex term (normal_mode) + aci_match_community_regex_term: &aci_match_community_regex_term_2_present + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + description: match regular community regex term for ansible_match_rule match rule profile + state: present + register: nm_add_match_community_regex_term_2 + + - name: Asserts for match community regex terms creation tasks + assert: + that: + - cm_add_match_community_regex_term is changed + - cm_add_match_community_regex_term.previous == [] + - cm_add_match_community_regex_term.current == [] + - nm_add_match_community_regex_term is changed + - nm_add_match_community_regex_term.current.0.rtctrlMatchCommRegexTerm.attributes.regex == ".*" + - nm_add_match_community_regex_term.current.0.rtctrlMatchCommRegexTerm.attributes.name == "ansible_community_regex_extended" + - nm_add_match_community_regex_term.current.0.rtctrlMatchCommRegexTerm.attributes.commType == "extended" + - nm_add_match_community_regex_term_idempotency is not changed + - nm_add_match_community_regex_term_2 is changed + - nm_add_match_community_regex_term_2.previous == [] + - nm_add_match_community_regex_term_2.current.0.rtctrlMatchCommRegexTerm.attributes.regex == "" + - nm_add_match_community_regex_term_2.current.0.rtctrlMatchCommRegexTerm.attributes.commType == "regular" + + - name: Query all match community regex terms + aci_match_community_regex_term: + <<: *aci_info + state: query + community_type: extended + register: query_all_match_community_regex_term + + - name: Query ansible_match_community_regex_term_regular + aci_match_community_regex_term: + <<: *aci_match_community_regex_term_2_present + state: query + register: query_ansible_match_community_regex_term_regular + + - name: Asserts query tasks + assert: + that: + - query_all_match_community_regex_term is not changed + - query_all_match_community_regex_term.current.0.rtctrlMatchCommRegexTerm.attributes.commType == "extended" + - query_ansible_match_community_regex_term_regular is not changed + - query_ansible_match_community_regex_term_regular.current.0.rtctrlMatchCommRegexTerm.attributes.regex == "" + - query_ansible_match_community_regex_term_regular.current.0.rtctrlMatchCommRegexTerm.attributes.commType == "regular" + + - name: Remove match community regex term (check_mode) + aci_match_community_regex_term: &match_community_regex_term_absent + <<: *aci_match_community_regex_term_present + state: absent + check_mode: true + register: cm_remove_match_community_regex_term + + - name: Remove match community regex term (normal_mode) + aci_match_community_regex_term: + <<: *match_community_regex_term_absent + register: nm_remove_match_community_regex_term + + - name: Remove match community regex term again - testing previous Removal + aci_match_community_regex_term: + <<: *match_community_regex_term_absent + register: nm_remove_match_community_regex_term_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_match_community_regex_term is changed + - cm_remove_match_community_regex_term.proposed == {} + - nm_remove_match_community_regex_term is changed + - nm_remove_match_community_regex_term.previous != [] + - nm_remove_match_community_regex_term.method == "DELETE" + - nm_remove_match_community_regex_term_idempotency is not changed + - nm_remove_match_community_regex_term_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_term/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_term/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_term/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_term/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_term/tasks/main.yml new file mode 100644 index 000000000..aecf89096 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_community_term/tasks/main.yml @@ -0,0 +1,146 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a match rule profile + aci_match_rule: + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + description: match rule profile for ansible_tenant tenant + state: present + register: cm_add_match_rule + + - name: Add a match community term (check_mode) + aci_match_community_term: &aci_match_community_term_present + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + match_community_term: ansible_match_community_term_1 + description: match community term 1 for ansible_match_rule match rule profile + state: present + check_mode: true + register: cm_add_match_community_term + + - name: Add a match community term (normal_mode) + aci_match_community_term: + <<: *aci_match_community_term_present + register: nm_add_match_community_term + + - name: Add the first match community term again - testing idempotency + aci_match_community_term: + <<: *aci_match_community_term_present + register: nm_add_match_community_term_idempotency + + - name: Add a second match community term (normal_mode) + aci_match_community_term: + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + match_community_term: ansible_match_community_term_2 + description: match community term 2 for ansible_match_rule match rule profile + state: present + register: nm_add_match_community_term_2 + + - name: Asserts for match community terms creation tasks + assert: + that: + - cm_add_match_community_term is changed + - cm_add_match_community_term.previous == [] + - cm_add_match_community_term.current == [] + - nm_add_match_community_term is changed + - nm_add_match_community_term.current.0.rtctrlMatchCommTerm.attributes.name == "ansible_match_community_term_1" + - nm_add_match_community_term_idempotency is not changed + - nm_add_match_community_term_2 is changed + - nm_add_match_community_term_2.previous == [] + - nm_add_match_community_term_2.current.0.rtctrlMatchCommTerm.attributes.name == "ansible_match_community_term_2" + + - name: Query all match community terms + aci_match_community_term: + <<: *aci_info + state: query + register: query_all_match_community_term + + - name: Query ansible_match_community_term_1 + aci_match_community_term: + <<: *aci_match_community_term_present + state: query + register: query_ansible_match_community_term_1 + + - name: Asserts query tasks + assert: + that: + - query_all_match_community_term is not changed + - query_all_match_community_term.current|length >= 2 + - query_ansible_match_community_term_1 is not changed + - query_ansible_match_community_term_1.current.0.rtctrlMatchCommTerm.attributes.name == "ansible_match_community_term_1" + + - name: Remove match community term (check_mode) + aci_match_community_term: &match_community_term_absent + <<: *aci_match_community_term_present + state: absent + check_mode: true + register: cm_remove_match_community_term + + - name: Remove match community term (normal_mode) + aci_match_community_term: + <<: *match_community_term_absent + register: nm_remove_match_community_term + + - name: Remove match community term again - testing previous Removal + aci_match_community_term: + <<: *match_community_term_absent + register: nm_remove_match_community_term_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_match_community_term is changed + - cm_remove_match_community_term.proposed == {} + - nm_remove_match_community_term is changed + - nm_remove_match_community_term.previous != [] + - nm_remove_match_community_term.method == "DELETE" + - nm_remove_match_community_term_idempotency is not changed + - nm_remove_match_community_term_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_match_route_destination/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_route_destination/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_route_destination/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_match_route_destination/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_route_destination/tasks/main.yml new file mode 100644 index 000000000..b4d49c2ff --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_route_destination/tasks/main.yml @@ -0,0 +1,159 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> +# Copyright: (c) 2023, Tim Cragg (@timcragg) <tcragg@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a match rule profile + aci_match_rule: + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + description: subject profile for ansible_tenant tenant + state: present + register: cm_add_match_rule + + - name: Add a match route destination rule (check_mode) + aci_match_route_destination: &aci_match_route_destination_present + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + description: match route destination rule 1 for ansible_match_rule match rule profile + ip: 11.11.11.11/24 + aggregate: yes + from_prefix_length: 0 + to_prefix_length: 32 + state: present + check_mode: true + register: cm_add_match_route_destination + + - name: Add a match route destination rule (normal_mode) + aci_match_route_destination: + <<: *aci_match_route_destination_present + register: nm_add_match_route_destination + + - name: Add the first match route destination rule again - testing idempotency + aci_match_route_destination: + <<: *aci_match_route_destination_present + register: nm_add_match_route_destination_idempotency + + - name: Add a second match route destination rule (normal_mode) + aci_match_route_destination: + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + description: match route destination rule 2 for ansible_match_rule match rule profile + ip: 11.11.11.12/24 + state: present + register: nm_add_match_route_destination_2 + + - name: Asserts for match route destination rule creation tasks + assert: + that: + - cm_add_match_route_destination is changed + - cm_add_match_route_destination.previous == [] + - cm_add_match_route_destination.current == [] + - nm_add_match_route_destination is changed + - nm_add_match_route_destination.current.0.rtctrlMatchRtDest.attributes.ip == "11.11.11.11/24" + - nm_add_match_route_destination.current.0.rtctrlMatchRtDest.attributes.aggregate == "yes" + - nm_add_match_route_destination.current.0.rtctrlMatchRtDest.attributes.fromPfxLen == "0" + - nm_add_match_route_destination.current.0.rtctrlMatchRtDest.attributes.toPfxLen == "32" + - nm_add_match_route_destination_idempotency is not changed + - nm_add_match_route_destination_2 is changed + - nm_add_match_route_destination_2.previous == [] + - nm_add_match_route_destination_2.current.0.rtctrlMatchRtDest.attributes.ip == "11.11.11.12/24" + - nm_add_match_route_destination_2.current.0.rtctrlMatchRtDest.attributes.aggregate == "no" + - nm_add_match_route_destination_2.current.0.rtctrlMatchRtDest.attributes.fromPfxLen == "0" + - nm_add_match_route_destination_2.current.0.rtctrlMatchRtDest.attributes.toPfxLen == "0" + + - name: Query all match regex AS-Path terms + aci_match_route_destination: + <<: *aci_info + state: query + register: query_all_match_route_destination + + - name: Query ansible_match_route_destination_1 + aci_match_route_destination: + <<: *aci_match_route_destination_present + state: query + register: query_ansible_match_route_destination_1 + + - name: Asserts query tasks + assert: + that: + - query_all_match_route_destination is not changed + - query_all_match_route_destination.current|length >= 2 + - query_ansible_match_route_destination_1 is not changed + - query_ansible_match_route_destination_1.current.0.rtctrlMatchRtDest.attributes.ip == "11.11.11.11/24" + - query_ansible_match_route_destination_1.current.0.rtctrlMatchRtDest.attributes.aggregate == "yes" + - query_ansible_match_route_destination_1.current.0.rtctrlMatchRtDest.attributes.fromPfxLen == "0" + - query_ansible_match_route_destination_1.current.0.rtctrlMatchRtDest.attributes.toPfxLen == "32" + + - name: Remove match route destination rule (check_mode) + aci_match_route_destination: &match_route_destination_absent + <<: *aci_match_route_destination_present + state: absent + check_mode: true + register: cm_remove_match_route_destination + + - name: Remove match route destination rule (normal_mode) + aci_match_route_destination: + <<: *match_route_destination_absent + register: nm_remove_match_route_destination + + - name: Remove match route destination rule again - testing previous Removal + aci_match_route_destination: + <<: *match_route_destination_absent + register: nm_remove_match_route_destination_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_match_route_destination is changed + - cm_remove_match_route_destination.proposed == {} + - nm_remove_match_route_destination is changed + - nm_remove_match_route_destination.previous != [] + - nm_remove_match_route_destination.method == "DELETE" + - nm_remove_match_route_destination_idempotency is not changed + - nm_remove_match_route_destination_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_match_rule/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_rule/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_rule/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_match_rule/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_rule/tasks/main.yml new file mode 100644 index 000000000..23509494c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_match_rule/tasks/main.yml @@ -0,0 +1,136 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> +# Copyright: (c) 2023, Tim Cragg (@timcragg) <tcragg@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a match rule profile (check_mode) + aci_match_rule: &aci_match_rule_present + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule_1 + description: match rule profile 1 for ansible_tenant tenant + state: present + check_mode: true + register: cm_add_match_rule + + - name: Add a match rule profile (normal_mode) + aci_match_rule: + <<: *aci_match_rule_present + register: nm_add_match_rule + + - name: Add the first match rule profile again - testing idempotency + aci_match_rule: + <<: *aci_match_rule_present + register: nm_add_match_rule_idempotency + + - name: Add a second match rule profile (normal_mode) + aci_match_rule: + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule_2 + description: match rule profile 2 for ansible_tenant tenant + state: present + register: nm_add_match_rule_2 + + - name: Asserts for match rule profiles creation tasks + assert: + that: + - cm_add_match_rule is changed + - cm_add_match_rule.previous == [] + - cm_add_match_rule.current == [] + - nm_add_match_rule is changed + - nm_add_match_rule.current.0.rtctrlSubjP.attributes.name == "ansible_match_rule_1" + - nm_add_match_rule_idempotency is not changed + - nm_add_match_rule_2 is changed + - nm_add_match_rule_2.previous == [] + - nm_add_match_rule_2.current.0.rtctrlSubjP.attributes.name == "ansible_match_rule_2" + + - name: Query all match rule profiles + aci_match_rule: + <<: *aci_info + state: query + register: query_all_match_rule + + - name: Query ansible_match_rule_1 + aci_match_rule: + <<: *aci_match_rule_present + state: query + register: query_ansible_match_rule_1 + + - name: Asserts query tasks + assert: + that: + - query_all_match_rule is not changed + - query_all_match_rule.current|length >= 2 + - query_ansible_match_rule_1 is not changed + - query_ansible_match_rule_1.current.0.rtctrlSubjP.attributes.name == "ansible_match_rule_1" + + - name: Remove match rule profile for l3out (check_mode) + aci_match_rule: &match_rule_absent + <<: *aci_match_rule_present + state: absent + check_mode: true + register: cm_remove_match_rule + + - name: Remove match rule profile for l3out (normal_mode) + aci_match_rule: + <<: *match_rule_absent + register: nm_remove_match_rule + + - name: Remove match rule profile for l3out again - testing previous Removal + aci_match_rule: + <<: *match_rule_absent + register: nm_remove_match_rule_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_match_rule is changed + - cm_remove_match_rule.proposed == {} + - nm_remove_match_rule is changed + - nm_remove_match_rule.previous != [] + - nm_remove_match_rule.method == "DELETE" + - nm_remove_match_rule_idempotency is not changed + - nm_remove_match_rule_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/error_handling.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/error_handling.yml index 1c503c5f2..49c6fca53 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/error_handling.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/error_handling.yml @@ -27,11 +27,10 @@ assert: that: - error_on_name_resolution is failed - - error_on_name_resolution.msg.startswith("Connection failed for https://foo.bar.cisco.com/api/aaaLogin.json. Request failed:") + - error_on_name_resolution.msg.startswith("Connection failed for https://foo.bar.cisco.com/api/aaaLogin.json.") - "'current' not in error_on_name_resolution" - "'previous' not in error_on_name_resolution" - "'sent' not in error_on_name_resolution" - - "'proposed' not in error_on_name_resolution" - "'filter_string' not in error_on_name_resolution" - name: Error when required parameter is missing @@ -59,7 +58,6 @@ - "'current' not in error_on_missing_required_param" - "'previous' not in error_on_missing_required_param" - "'sent' not in error_on_missing_required_param" - - "'proposed' not in error_on_missing_required_param" - "'filter_string' not in error_on_missing_required_param" - name: Error when attributes are missing @@ -90,7 +88,6 @@ - "'current' not in error_on_missing_attributes" - "'previous' not in error_on_missing_attributes" - "'sent' not in error_on_missing_attributes" - - "'proposed' not in error_on_missing_attributes" - "'filter_string' not in error_on_missing_attributes" - name: Error when input does not validate @@ -123,7 +120,6 @@ - "'current' not in error_on_input_validation" - "'previous' not in error_on_input_validation" - "'sent' not in error_on_input_validation" - - "'proposed' not in error_on_input_validation" - "'filter_string' not in error_on_input_validation" - name: Error when invalid attributes are used @@ -156,7 +152,6 @@ - "'current' not in error_on_invalid_attributes" - "'previous' not in error_on_invalid_attributes" - "'sent' not in error_on_invalid_attributes" - - "'proposed' not in error_on_invalid_attributes" - "'filter_string' not in error_on_invalid_attributes" - name: Error on invalid object @@ -188,7 +183,6 @@ - "'current' not in error_on_invalid_object" - "'previous' not in error_on_invalid_object" - "'sent' not in error_on_invalid_object" - - "'proposed' not in error_on_invalid_object" # Test case for certificate based error issue: https://github.com/CiscoDevNet/ansible-aci/issues/339 # Original error was with ospfCtxPol but same behaviour detected for tenant creation thus simplifying the test case @@ -227,4 +221,104 @@ cisco.aci.aci_rest: <<: *tenant content: - <fvTenant name="test_tenant_cert_auth" status="deleted"/>
\ No newline at end of file + <fvTenant name="test_tenant_cert_auth" status="deleted"/> + +# Test cases for import error handling + +- name: Uninstall lxml for error checking + ansible.builtin.pip: &lxml + name: lxml + state: absent + ignore_errors: true # ignore errors to because of multiple executions for hosts at the same time + +- name: Uninstall xmljson for error checking + ansible.builtin.pip: &xmljson + name: xmljson + state: absent + ignore_errors: true # ignore errors to because of multiple executions for hosts at the same time + +- name: Uninstall pyyaml for error checking + ansible.builtin.pip: &pyyaml + name: pyyaml + state: absent + ignore_errors: true # ignore errors to because of multiple executions for hosts at the same time + when: ansible_connection == "local" + +- name: Create tenant with invalid src attribute + cisco.aci.aci_rest: + <<: *tenant + ignore_errors: true + register: err_missing_lxml + +- name: Install lxml + ansible.builtin.pip: + <<: *lxml + state: present + ignore_errors: true # ignore errors to because of multiple executions for hosts at the same time + +- name: Create tenant with invalid src attribute + cisco.aci.aci_rest: + <<: *tenant + ignore_errors: true + register: err_missing_xmljson + +- name: Install xmljson + ansible.builtin.pip: + <<: *xmljson + state: present + ignore_errors: true # ignore errors to because of multiple executions for hosts at the same time + +- name: Install pyyaml + ansible.builtin.pip: + <<: *pyyaml + state: present + ignore_errors: true # ignore errors to because of multiple executions for hosts at the same time + when: ansible_connection == "local" + +# Test case for invalid src + +- name: Create tenant with invalid src attribute + cisco.aci.aci_rest: + <<: *tenant + src: "./targets/aci_rest/invalid_src.txt" + content: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: err_src_attribute + +# Test case for invalid path extension + +- name: Create tenant with invalid path extension + cisco.aci.aci_rest: + <<: *tenant + path: /api/mo/uni.invalid + ignore_errors: true + register: err_extension + +# Parse failures + +- name: Create tenant with fail to parse xml + cisco.aci.aci_rest: + <<: *tenant + src: "./targets/aci_rest/tasks/xml_files/fail_parse.xml" + content: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: err_fail_parse_xml + +- name: Create tenant with fail to parse json + cisco.aci.aci_rest: + <<: *tenant + path: /api/mo/uni.json + src: "./targets/aci_rest/tasks/xml_files/fail_parse.json" + content: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: err_fail_parse_json + +- name: Assertions checks for import error handling, invalid src, invalid path extension and parse failures + assert: + that: + - err_missing_lxml.msg == "The lxml python library is missing, or lacks etree support." + - err_missing_xmljson.msg == "The xmljson python library is missing, or lacks cobra support." + - err_src_attribute.msg == "Cannot find/access src './targets/aci_rest/invalid_src.txt'" + - err_extension.msg == "Failed to find REST API payload type (neither .xml nor .json)." + - err_fail_parse_xml.msg.startswith("Failed to parse provided XML payload") + - err_fail_parse_json.msg.startswith("Failed to parse provided JSON/YAML payload") diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/json_inline.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/json_inline.yml index dd27525f9..3d5c9be48 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/json_inline.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/json_inline.yml @@ -18,7 +18,7 @@ method: delete # ADD TENANT -- name: Add tenant (normal mode) +- name: Add tenant (check mode) cisco.aci.aci_rest: &tenant_present host: '{{ aci_hostname }}' username: '{{ aci_username }}' @@ -37,12 +37,35 @@ } } } - delegate_to: localhost + register: cm_add_tenant + check_mode: true + +- name: Verify checkmode did not create tenant + cisco.aci.aci_tenant: + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + name: ansible_test + state: query + register: cm_verify_checkmode_tenant + +- name: Verify checkmode POST operation + assert: + that: + - cm_add_tenant is changed + - cm_add_tenant.proposed.fvTenant.attributes.name == "ansible_test" + - cm_verify_checkmode_tenant.current == [] + +- name: Add tenant (normal mode) + cisco.aci.aci_rest: *tenant_present register: nm_add_tenant - name: Add tenant again (normal mode) cisco.aci.aci_rest: *tenant_present - delegate_to: localhost register: nm_add_tenant_again - name: Verify add_tenant @@ -72,12 +95,10 @@ } } } - delegate_to: localhost register: nm_add_tenant_descr - name: Change description of tenant again (normal mode) cisco.aci.aci_rest: *tenant_changed - delegate_to: localhost register: nm_add_tenant_descr_again - name: Verify add_tenant_descr @@ -89,7 +110,6 @@ # ADD TENANT AGAIN - name: Add tenant again with no description (normal mode) cisco.aci.aci_rest: *tenant_present - delegate_to: localhost register: nm_add_tenant_again_no_descr - name: Verify add_tenant_again_no_descr @@ -109,7 +129,6 @@ output_level: '{{ aci_output_level | default("info") }}' path: /api/mo/uni/tn-[ansible_test].json method: get - delegate_to: localhost register: nm_query_all_tenants - name: Verify query_all_tenants @@ -129,7 +148,6 @@ output_level: '{{ aci_output_level | default("info") }}' path: /api/mo/uni/tn-[ansible_test].json method: get - delegate_to: localhost register: nm_query_tenant - name: Verify query_tenant @@ -140,12 +158,10 @@ # REMOVE TENANT - name: Remove tenant (normal mode) cisco.aci.aci_rest: *tenant_absent - delegate_to: localhost register: nm_remove_tenant - name: Remove tenant again (normal mode) cisco.aci.aci_rest: *tenant_absent - delegate_to: localhost register: nm_remove_tenant_again - name: Verify remove_tenant @@ -157,7 +173,6 @@ # QUERY NON-EXISTING TENANT - name: Query non-existing tenant (normal mode) cisco.aci.aci_rest: *tenant_query - delegate_to: localhost register: nm_query_non_tenant - name: Verify query_non_tenant diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/json_string.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/json_string.yml index bbbd57cd4..7a1dfd8ce 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/json_string.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/json_string.yml @@ -18,7 +18,7 @@ method: delete # ADD TENANT -- name: Add tenant (normal mode) +- name: Add tenant (check mode) cisco.aci.aci_rest: &tenant_present host: '{{ aci_hostname }}' username: '{{ aci_username }}' @@ -38,6 +38,31 @@ } } output_path: "/tmp/ansible_output_file.log" + register: cm_add_tenant + check_mode: true + +- name: Verify checkmode did not create tenant + cisco.aci.aci_tenant: + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + name: ansible_test + state: query + register: cm_verify_checkmode_tenant + +- name: Verify checkmode POST operation + assert: + that: + - cm_add_tenant is changed + - cm_add_tenant.proposed.fvTenant.attributes.name == "ansible_test" + - cm_verify_checkmode_tenant.current == [] + +- name: Add tenant (normal mode) + cisco.aci.aci_rest: *tenant_present register: nm_add_tenant - name: Add tenant again (normal mode) diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/main.yml index 0952dd85b..c06f0cee2 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/main.yml @@ -24,8 +24,8 @@ - include_tasks: xml_string.yml tags: xml_string -- include_tasks: error_handling.yml - tags: error_handling - - include_tasks: xml_file.yml tags: xml_file + +- include_tasks: error_handling.yml + tags: error_handling diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_file.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_file.yml index cdde037c4..fea63112b 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_file.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_file.yml @@ -32,10 +32,25 @@ check_mode: true register: cm_add_tenant +- name: Verify checkmode did not create tenant + cisco.aci.aci_tenant: + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + name: ans_test_create + state: query + register: cm_verify_checkmode_tenant + - name: Assertions check for add tenant using ans_test_create xml template file with check mode assert: that: - - cm_add_tenant is not changed + - cm_add_tenant is changed + - '"ans_test_create" in cm_add_tenant.proposed' + - cm_verify_checkmode_tenant.current == [] - name: Add tenant using ans_test_create xml template file with normal mode cisco.aci.aci_rest: @@ -95,7 +110,7 @@ - name: Assertions check for update tenant description using ans_test_update xml template file with check mode assert: that: - - cm_update_tenant is not changed + - cm_update_tenant is changed - name: Update tenant description using ans_test_update xml template file with normal mode cisco.aci.aci_rest: @@ -168,7 +183,7 @@ - name: Assertions check for delete tenant using ans_test_delete xml template file with check mode assert: that: - - cm_delete_tenant is not changed + - cm_delete_tenant is changed - name: Delete tenant using ans_test_delete xml template file with normal mode cisco.aci.aci_rest: diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/fail_parse.json b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/fail_parse.json new file mode 100644 index 000000000..b2d10f46a --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/fail_parse.json @@ -0,0 +1 @@ +{wrong_payload
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/fail_parse.xml b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/fail_parse.xml new file mode 100644 index 000000000..96877ed2d --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/fail_parse.xml @@ -0,0 +1 @@ +wrong_payload
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_string.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_string.yml index c87291779..d1424bafa 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_string.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_string.yml @@ -18,6 +18,66 @@ method: delete # ADD TENANT +- name: Add tenant (check mode) + cisco.aci.aci_rest: + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + path: /api/mo/uni.xml + method: post + content: + <fvTenant name="ansible_test"/> + register: cm_add_tenant + check_mode: true + +- name: Add tenant 2 (check mode) + cisco.aci.aci_rest: + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + path: /api/mo/uni.xml + method: post + content: + { + "fvTenant": { + "attributes": { + "name": "ansible_test" + } + } + } + register: cm_add_tenant_2 + check_mode: true + +- name: Verify checkmode did not create tenant + cisco.aci.aci_tenant: &tenant_cm_query + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + name: ansible_test + state: query + register: cm_verify_checkmode_tenant + +- name: Verify checkmode POST operation + assert: + that: + - cm_add_tenant is changed + - '"ansible_test" in cm_add_tenant.proposed' + - cm_add_tenant_2 is changed + - '"ansible_test" in cm_add_tenant.proposed' + - cm_verify_checkmode_tenant.current == [] + - name: Add tenant (normal mode) cisco.aci.aci_rest: &tenant_present host: '{{ aci_hostname }}' diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/yaml_inline.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/yaml_inline.yml index d7538f9a6..6cd06afcd 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/yaml_inline.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/yaml_inline.yml @@ -18,7 +18,7 @@ method: delete # ADD TENANT -- name: Add tenant (normal mode) +- name: Add tenant (check mode) cisco.aci.aci_rest: &tenant_present host: '{{ aci_hostname }}' username: '{{ aci_username }}' @@ -33,6 +33,31 @@ fvTenant: attributes: name: ansible_test + register: cm_add_tenant + check_mode: true + +- name: Verify checkmode did not create tenant + cisco.aci.aci_tenant: + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + name: ansible_test + state: query + register: cm_verify_checkmode_tenant + +- name: Verify checkmode POST operation + assert: + that: + - cm_add_tenant is changed + - cm_add_tenant.proposed.fvTenant.attributes.name == "ansible_test" + - cm_verify_checkmode_tenant.current == [] + +- name: Add tenant (normal mode) + cisco.aci.aci_rest: *tenant_present register: nm_add_tenant - name: Add tenant again (normal mode) diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/yaml_string.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/yaml_string.yml index d7538f9a6..895045474 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/yaml_string.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/yaml_string.yml @@ -18,7 +18,7 @@ method: delete # ADD TENANT -- name: Add tenant (normal mode) +- name: Add tenant (check mode) cisco.aci.aci_rest: &tenant_present host: '{{ aci_hostname }}' username: '{{ aci_username }}' @@ -29,10 +29,35 @@ output_level: '{{ aci_output_level | default("info") }}' path: /api/mo/uni.json method: post - content: + content: | fvTenant: attributes: name: ansible_test + register: cm_add_tenant + check_mode: true + +- name: Verify checkmode did not create tenant + cisco.aci.aci_tenant: + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + name: ansible_test + state: query + register: cm_verify_checkmode_tenant + +- name: Verify checkmode POST operation + assert: + that: + - cm_add_tenant is changed + - cm_add_tenant.proposed.fvTenant.attributes.name == "ansible_test" + - cm_verify_checkmode_tenant.current == [] + +- name: Add tenant (normal mode) + cisco.aci.aci_rest: *tenant_present register: nm_add_tenant - name: Add tenant again (normal mode) diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_route_control_context/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_route_control_context/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_route_control_context/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_route_control_context/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_route_control_context/tasks/main.yml new file mode 100644 index 000000000..83f46e4b8 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_route_control_context/tasks/main.yml @@ -0,0 +1,197 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> +# Copyright: (c) 2023, Tim Cragg (@timcragg) <tcragg@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a new action rule profile + aci_tenant_action_rule_profile: &aci_action_rule_present + <<: *aci_info + tenant: ansible_tenant + action_rule: ansible_action_rule + description: Ansible action rule profile for ansible_tenant tenant + state: present + + - name: Add a new L3Out + aci_l3out: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + description: Ansible l3Out for ansible_tenant tenant + domain: ansible_dom + vrf: ansible_vrf + state: present + + - name: Add a route control profile for l3out + aci_route_control_profile: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + route_control_profile: ansible_rtctrl_profile_l3out + description: Ansible Route Control Profile for ansible_l3out l3Out + state: present + + - name: Add a subject profile + aci_match_rule: &aci_match_rule_present + <<: *aci_info + tenant: ansible_tenant + match_rule: ansible_match_rule + description: Ansible Subject Profile for ansible_tenant tenant + state: present + + - name: Add a route control context policy for l3out (check_mode) + aci_route_control_context: &aci_route_control_context_present + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + route_control_profile: ansible_rtctrl_profile_l3out + route_control_context: ansible_route_control_context_l3out + description: Ansible route control Context Policy for ansible_rtctrl_profile_l3out route control profile + match_rule: ansible_match_rule + action_rule: ansible_action_rule + action: deny + order: 5 + state: present + check_mode: true + register: cm_add_route_control_context_l3out + + - name: Add a route control context policy again (normal_mode) + aci_route_control_context: + <<: *aci_route_control_context_present + register: nm_add_route_control_context_l3out + + - name: Add a route control context policy again - testing idempotency + aci_route_control_context: + <<: *aci_route_control_context_present + register: nm_add_route_control_context_l3out_idempotency + + - name: Add a route control profile for tenant + aci_route_control_profile: + <<: *aci_info + tenant: ansible_tenant + route_control_profile: ansible_rtctrl_profile_tenant + description: Route Control Profile for ansible_tenant tenant + state: present + + - name: Add a route control context policy for tenant + aci_route_control_context: + <<: *aci_info + tenant: ansible_tenant + route_control_profile: ansible_rtctrl_profile_tenant + route_control_context: ansible_route_control_context_tenant + description: Ansible route control Context Policy for ansible_rtctrl_profile_tenant route control profile + state: present + register: nm_add_route_control_context_tenant + + - name: Asserts for route control profiles creation tasks + assert: + that: + - cm_add_route_control_context_l3out is changed + - cm_add_route_control_context_l3out.previous == [] + - cm_add_route_control_context_l3out.current == [] + - nm_add_route_control_context_l3out is changed + - nm_add_route_control_context_l3out.current.0.rtctrlCtxP.attributes.name == "ansible_route_control_context_l3out" + - nm_add_route_control_context_l3out.current.0.rtctrlCtxP.attributes.action == "deny" + - nm_add_route_control_context_l3out.current.0.rtctrlCtxP.attributes.order == "5" + - nm_add_route_control_context_l3out.current.0.rtctrlCtxP.children.0.rtctrlScope.children.0.rtctrlRsScopeToAttrP.attributes.tnRtctrlAttrPName == "ansible_action_rule" + - nm_add_route_control_context_l3out.current.0.rtctrlCtxP.children.1.rtctrlRsCtxPToSubjP.attributes.tnRtctrlSubjPName == "ansible_match_rule" + - nm_add_route_control_context_l3out_idempotency is not changed + - nm_add_route_control_context_tenant is changed + - nm_add_route_control_context_tenant.previous == [] + - nm_add_route_control_context_tenant.current.0.rtctrlCtxP.attributes.name == "ansible_route_control_context_tenant" + - nm_add_route_control_context_tenant.current.0.rtctrlCtxP.attributes.action == "permit" + - nm_add_route_control_context_tenant.current.0.rtctrlCtxP.attributes.order == "0" + + - name: Query all route control context policies + aci_route_control_context: + <<: *aci_info + state: query + register: query_all_route_control_context + + - name: Query ansible_route_control_context_l3out route control context policy + aci_route_control_context: + <<: *aci_info + route_control_context: ansible_route_control_context_l3out + state: query + register: query_route_control_context_l3out + + - name: Asserts query tasks + assert: + that: + - query_all_route_control_context is not changed + - query_all_route_control_context.current|length >= 2 + - query_route_control_context_l3out is not changed + - query_route_control_context_l3out.current.0.rtctrlCtxP.attributes.name == "ansible_route_control_context_l3out" + - query_route_control_context_l3out.current.0.rtctrlCtxP.attributes.action == "deny" + - query_route_control_context_l3out.current.0.rtctrlCtxP.attributes.order == "5" + - query_route_control_context_l3out.current.0.rtctrlCtxP.children.0.rtctrlScope.children.0.rtctrlRsScopeToAttrP.attributes.tDn == "uni/tn-ansible_tenant/attr-ansible_action_rule" + - query_route_control_context_l3out.current.0.rtctrlCtxP.children.1.rtctrlRsCtxPToSubjP.attributes.tDn == "uni/tn-ansible_tenant/subj-ansible_match_rule" + + - name: Remove route control context policy for l3out (check_mode) + aci_route_control_context: &aci_route_control_context_absent + <<: *aci_route_control_context_present + state: absent + check_mode: true + register: cm_remove_route_control_context + + - name: Remove route control context policy for l3out (normal_mode) + aci_route_control_context: + <<: *aci_route_control_context_absent + register: nm_remove_remove_route_control_context + + - name: Remove route control profile for l3out again - testing previous Removal + aci_route_control_context: + <<: *aci_route_control_context_absent + register: nm_remove_route_control_context_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_route_control_context is changed + - cm_remove_route_control_context.proposed == {} + - nm_remove_remove_route_control_context is changed + - nm_remove_remove_route_control_context.previous != [] + - nm_remove_remove_route_control_context.method == "DELETE" + - nm_remove_route_control_context_idempotency is not changed + - nm_remove_route_control_context_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_route_control_profile/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_route_control_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_route_control_profile/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_route_control_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_route_control_profile/tasks/main.yml new file mode 100644 index 000000000..db0022100 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_route_control_profile/tasks/main.yml @@ -0,0 +1,145 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> +# Copyright: (c) 2023, Tim Cragg (@timcragg) <tcragg@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a new L3Out + aci_l3out: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + description: L3Out for ansible_tenant tenant + domain: ansible_dom + vrf: ansible_vrf + state: present + + - name: Add route control profile for l3out (check_mode) + aci_route_control_profile: &aci_route_control_profile_present + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + route_control_profile: ansible_rtctrl_profile_l3out + description: Route Control Profile for ansible_l3out L3Out + auto_continue: no + policy_type: combinable + state: present + check_mode: true + register: cm_add_route_control_profile + + - name: Add route control profile for l3out (normal_mode) + aci_route_control_profile: + <<: *aci_route_control_profile_present + register: nm_add_route_control_profile + + - name: Add route control profile for l3out again - testing idempotency + aci_route_control_profile: + <<: *aci_route_control_profile_present + register: nm_add_route_control_profile_idempotency + + - name: Add route control profile for tenant (normal_mode) + aci_route_control_profile: + <<: *aci_info + tenant: ansible_tenant + route_control_profile: ansible_rtctrl_profile_tenant + description: Route Control Profile for ansible_tenant tenant + state: present + register: nm_add_route_control_profile_2 + + - name: Asserts for route control profiles creation tasks + assert: + that: + - cm_add_route_control_profile is changed + - cm_add_route_control_profile.previous == [] + - cm_add_route_control_profile.current == [] + - nm_add_route_control_profile is changed + - nm_add_route_control_profile_idempotency is not changed + - nm_add_route_control_profile_2 is changed + - nm_add_route_control_profile_2.previous == [] + + - name: Query all route control profiles + aci_route_control_profile: + <<: *aci_info + state: query + register: query_all_route_control_profile + + - name: Query ansible_rtctrl_profile_l3out + aci_route_control_profile: + <<: *aci_route_control_profile_present + state: query + register: query_ansible_rtctrl_profile_l3out + + - name: Asserts query tasks + assert: + that: + - query_all_route_control_profile is not changed + - query_all_route_control_profile.current|length >= 2 + + - name: Remove route control profile for l3out (check_mode) + aci_route_control_profile: &route_control_profile_absent + <<: *aci_route_control_profile_present + state: absent + check_mode: true + register: cm_remove_route_control_profile + + - name: Remove route control profile for l3out (normal_mode) + aci_route_control_profile: + <<: *route_control_profile_absent + register: nm_remove_route_control_profile + + - name: Remove route control profile for l3out again - testing previous Removal + aci_route_control_profile: + <<: *route_control_profile_absent + register: nm_remove_route_control_profile_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_route_control_profile is changed + - cm_remove_route_control_profile.proposed == {} + - nm_remove_route_control_profile is changed + - nm_remove_route_control_profile.previous != [] + - nm_remove_route_control_profile.method == "DELETE" + - nm_remove_route_control_profile_idempotency is not changed + - nm_remove_route_control_profile_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_user/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_user/tasks/main.yml index 1b2608189..aabfd4c67 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_user/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_user/tasks/main.yml @@ -1,16 +1,16 @@ # Test code for the ACI modules # Copyright: (c) 2021, Tim Cragg (@timcragg) +# Copyright: (c) 2023, Akini Ross (@akinross) # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) - name: Test that we have an ACI APIC host, ACI username and ACI password - fail: + ansible.builtin.fail: msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined -# GET Credentials from the inventory - name: Set vars - set_fact: + ansible.builtin.set_fact: aci_info: &aci_info host: "{{ aci_hostname }}" username: "{{ aci_username }}" @@ -18,26 +18,25 @@ validate_certs: '{{ aci_validate_certs | default(false) }}' use_ssl: '{{ aci_use_ssl | default(true) }}' use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + output_level: '{{ aci_output_level | default("info") }}' # CLEAN ENVIRONMENT - name: Remove ansible_snmp_policy if it already exists - aci_snmp_policy: + cisco.aci.aci_snmp_policy: <<: *aci_info name: ansible_snmp_policy state: absent -# ADD snmp policy -- name: Add snmp policy - aci_snmp_policy: +# CREATE SNMP USER +- name: Create snmp policy + cisco.aci.aci_snmp_policy: <<: *aci_info name: ansible_snmp_policy admin_state: enabled state: present -# ADD snmp user -- name: Add snmp user - aci_snmp_user: +- name: Create a snmp user (checkmode) + cisco.aci.aci_snmp_user: &snmp_user <<: *aci_info policy: ansible_snmp_policy name: ansible_snmp_user @@ -46,66 +45,223 @@ privacy_type: aes-128 privacy_key: "priv-test-key" state: present - register: add_snmp_user + register: cm_create_snmp_user + check_mode: true -- name: Verify that ansible_snmp_community has been created with correct attributes - assert: +- name: Create a snmp user + cisco.aci.aci_snmp_user: + <<: *snmp_user + register: nm_create_snmp_user + +- name: Create a snmp user again without secrets + cisco.aci.aci_snmp_user: + <<: *snmp_user + auth_key: "{{ fake_var | default(omit) }}" + privacy_key: "{{ fake_var | default(omit) }}" + register: nm_create_snmp_user_again + +- name: Verify create of ansible_snmp_user + ansible.builtin.assert: + that: + - cm_create_snmp_user is changed + - cm_create_snmp_user.proposed.snmpUserP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/user-ansible_snmp_user" + - cm_create_snmp_user.proposed.snmpUserP.attributes.name == "ansible_snmp_user" + - cm_create_snmp_user.proposed.snmpUserP.attributes.authType == "hmac-sha1-96" + - cm_create_snmp_user.proposed.snmpUserP.attributes.privType == "aes-128" + - cm_create_snmp_user.proposed.snmpUserP.attributes.annotation == 'orchestrator:ansible' + - cm_create_snmp_user.previous == [] + - nm_create_snmp_user is changed + - nm_create_snmp_user.current.0.snmpUserP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/user-ansible_snmp_user" + - nm_create_snmp_user.current.0.snmpUserP.attributes.name == "ansible_snmp_user" + - nm_create_snmp_user.current.0.snmpUserP.attributes.authType == "hmac-sha1-96" + - nm_create_snmp_user.current.0.snmpUserP.attributes.privType == "aes-128" + - nm_create_snmp_user.current.0.snmpUserP.attributes.annotation == 'orchestrator:ansible' + - nm_create_snmp_user.current.0.snmpUserP.attributes.descr == "" + - nm_create_snmp_user.previous == [] + - nm_create_snmp_user_again is not changed + - nm_create_snmp_user_again.previous.0.snmpUserP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/user-ansible_snmp_user" + - nm_create_snmp_user_again.previous.0.snmpUserP.attributes.name == "ansible_snmp_user" + - nm_create_snmp_user_again.previous.0.snmpUserP.attributes.authType == "hmac-sha1-96" + - nm_create_snmp_user_again.previous.0.snmpUserP.attributes.privType == "aes-128" + - nm_create_snmp_user_again.previous.0.snmpUserP.attributes.annotation == 'orchestrator:ansible' + - nm_create_snmp_user_again.previous.0.snmpUserP.attributes.descr == "" + - nm_create_snmp_user_again.current.0.snmpUserP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/user-ansible_snmp_user" + - nm_create_snmp_user_again.current.0.snmpUserP.attributes.name == "ansible_snmp_user" + - nm_create_snmp_user_again.current.0.snmpUserP.attributes.authType == "hmac-sha1-96" + - nm_create_snmp_user_again.current.0.snmpUserP.attributes.privType == "aes-128" + - nm_create_snmp_user_again.current.0.snmpUserP.attributes.annotation == 'orchestrator:ansible' + - nm_create_snmp_user_again.current.0.snmpUserP.attributes.descr == "" + +# CHANGE SNMP USER +- name: Change a snmp user (checkmode) + cisco.aci.aci_snmp_user: &snmp_user_changed + <<: *snmp_user + descr: description_change + register: cm_change_snmp_user + check_mode: true + +- name: Change a snmp user + cisco.aci.aci_snmp_user: + <<: *snmp_user_changed + register: nm_change_snmp_user + +- name: Change a snmp user again without secrets + cisco.aci.aci_snmp_user: + <<: *snmp_user_changed + auth_key: "{{ fake_var | default(omit) }}" + privacy_key: "{{ fake_var | default(omit) }}" + register: nm_change_snmp_user_again + +- name: Verify change of ansible_snmp_user + ansible.builtin.assert: that: - - add_snmp_user.current.0.snmpUserP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/user-ansible_snmp_user" - - add_snmp_user.current.0.snmpUserP.attributes.name == "ansible_snmp_user" - - add_snmp_user.current.0.snmpUserP.attributes.authType == "hmac-sha1-96" - - add_snmp_user.current.0.snmpUserP.attributes.privType == "aes-128" - - add_snmp_user.current.0.snmpUserP.attributes.annotation == 'orchestrator:ansible' - -# QUERY snmp user -- name: Query snmp user - aci_snmp_user: + - cm_change_snmp_user is changed + - cm_change_snmp_user.previous.0.snmpUserP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/user-ansible_snmp_user" + - cm_change_snmp_user.previous.0.snmpUserP.attributes.name == "ansible_snmp_user" + - cm_change_snmp_user.previous.0.snmpUserP.attributes.authType == "hmac-sha1-96" + - cm_change_snmp_user.previous.0.snmpUserP.attributes.privType == "aes-128" + - cm_change_snmp_user.previous.0.snmpUserP.attributes.annotation == 'orchestrator:ansible' + - cm_change_snmp_user.previous.0.snmpUserP.attributes.descr == "" + - cm_change_snmp_user.proposed.snmpUserP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/user-ansible_snmp_user" + - cm_change_snmp_user.proposed.snmpUserP.attributes.name == "ansible_snmp_user" + - cm_change_snmp_user.proposed.snmpUserP.attributes.authType == "hmac-sha1-96" + - cm_change_snmp_user.proposed.snmpUserP.attributes.privType == "aes-128" + - cm_change_snmp_user.proposed.snmpUserP.attributes.annotation == 'orchestrator:ansible' + - cm_change_snmp_user.proposed.snmpUserP.attributes.descr == "description_change" + - nm_change_snmp_user is changed + - nm_change_snmp_user.previous.0.snmpUserP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/user-ansible_snmp_user" + - nm_change_snmp_user.previous.0.snmpUserP.attributes.name == "ansible_snmp_user" + - nm_change_snmp_user.previous.0.snmpUserP.attributes.authType == "hmac-sha1-96" + - nm_change_snmp_user.previous.0.snmpUserP.attributes.privType == "aes-128" + - nm_change_snmp_user.previous.0.snmpUserP.attributes.annotation == 'orchestrator:ansible' + - nm_change_snmp_user.previous.0.snmpUserP.attributes.descr == "" + - nm_change_snmp_user.current.0.snmpUserP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/user-ansible_snmp_user" + - nm_change_snmp_user.current.0.snmpUserP.attributes.name == "ansible_snmp_user" + - nm_change_snmp_user.current.0.snmpUserP.attributes.authType == "hmac-sha1-96" + - nm_change_snmp_user.current.0.snmpUserP.attributes.privType == "aes-128" + - nm_change_snmp_user.current.0.snmpUserP.attributes.annotation == 'orchestrator:ansible' + - nm_change_snmp_user.current.0.snmpUserP.attributes.descr == "description_change" + - nm_change_snmp_user_again is not changed + - nm_change_snmp_user_again.previous.0.snmpUserP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/user-ansible_snmp_user" + - nm_change_snmp_user_again.previous.0.snmpUserP.attributes.name == "ansible_snmp_user" + - nm_change_snmp_user_again.previous.0.snmpUserP.attributes.authType == "hmac-sha1-96" + - nm_change_snmp_user_again.previous.0.snmpUserP.attributes.privType == "aes-128" + - nm_change_snmp_user_again.previous.0.snmpUserP.attributes.annotation == 'orchestrator:ansible' + - nm_change_snmp_user_again.previous.0.snmpUserP.attributes.descr == "description_change" + - nm_change_snmp_user_again.current.0.snmpUserP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/user-ansible_snmp_user" + - nm_change_snmp_user_again.current.0.snmpUserP.attributes.name == "ansible_snmp_user" + - nm_change_snmp_user_again.current.0.snmpUserP.attributes.authType == "hmac-sha1-96" + - nm_change_snmp_user_again.current.0.snmpUserP.attributes.privType == "aes-128" + - nm_change_snmp_user_again.current.0.snmpUserP.attributes.annotation == 'orchestrator:ansible' + - nm_change_snmp_user_again.current.0.snmpUserP.attributes.descr == "description_change" + +# QUERY SNMP USER +- name: Create another snmp user with auth_type hmac-sha2-224 + cisco.aci.aci_snmp_user: + <<: *snmp_user + name: ansible_snmp_user_2 + auth_type: hmac-sha2-224 + register: nm_create_snmp_user_2 + +- name: Create another snmp user with auth_type hmac-sha2-256 + cisco.aci.aci_snmp_user: + <<: *snmp_user + name: ansible_snmp_user_3 + auth_type: hmac-sha2-256 + register: nm_create_snmp_user_3 + +- name: Create another snmp user with auth_type hmac-sha2-384 + cisco.aci.aci_snmp_user: + <<: *snmp_user + name: ansible_snmp_user_4 + auth_type: hmac-sha2-384 + register: nm_create_snmp_user_4 + +- name: Create another snmp user with auth_type hmac-sha2-512 + cisco.aci.aci_snmp_user: + <<: *snmp_user + name: ansible_snmp_user_5 + auth_type: hmac-sha2-512 + register: nm_create_snmp_user_5 + +- name: Verify change of ansible_snmp_user + ansible.builtin.assert: + that: + - nm_create_snmp_user_2 is changed + - nm_create_snmp_user_2.current.0.snmpUserP.attributes.authType == "hmac-sha2-224" + - nm_create_snmp_user_3 is changed + - nm_create_snmp_user_3.current.0.snmpUserP.attributes.authType == "hmac-sha2-256" + - nm_create_snmp_user_4 is changed + - nm_create_snmp_user_4.current.0.snmpUserP.attributes.authType == "hmac-sha2-384" + - nm_create_snmp_user_5 is changed + - nm_create_snmp_user_5.current.0.snmpUserP.attributes.authType == "hmac-sha2-512" + +- name: Query ansible_snmp_user + cisco.aci.aci_snmp_user: <<: *aci_info policy: ansible_snmp_policy name: ansible_snmp_user state: query register: query_snmp_user -- name: Verify the attributes under query_snmp_client_group - assert: +- name: Verify query of ansible_snmp_user + ansible.builtin.assert: that: - query_snmp_user is not changed + - query_snmp_user.current | length == 1 - query_snmp_user.current.0.snmpUserP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/user-ansible_snmp_user" - query_snmp_user.current.0.snmpUserP.attributes.name == "ansible_snmp_user" - query_snmp_user.current.0.snmpUserP.attributes.authType == "hmac-sha1-96" - query_snmp_user.current.0.snmpUserP.attributes.privType == "aes-128" -- name: Query all snmp communities - aci_snmp_user: +- name: Query all snmp users + cisco.aci.aci_snmp_user: <<: *aci_info state: query register: query_snmp_user_all -- name: Verify query_snmp_user_all - assert: +- name: Verify query of all snmp users + ansible.builtin.assert: that: - query_snmp_user_all is not changed + - query_snmp_user_all.current | length >= 5 -# DELETE snmp user -- name: Remove the snmp user - aci_snmp_user: +# REMOVE SNMP USER +- name: Remove the snmp user (checkmode) + cisco.aci.aci_snmp_user: &snmp_user_remove <<: *aci_info policy: ansible_snmp_policy name: ansible_snmp_user state: absent - register: remove_snmp_user + register: cm_remove_snmp_user + check_mode: true + +- name: Remove the snmp user + cisco.aci.aci_snmp_user: + <<: *snmp_user_remove + register: nm_remove_snmp_user + +- name: Remove the snmp user again + cisco.aci.aci_snmp_user: + <<: *snmp_user_remove + register: nm_remove_snmp_user_again - name: Verify remove_snmp_user - assert: + ansible.builtin.assert: that: - - remove_snmp_user is changed - - remove_snmp_user.current == [] - - remove_snmp_user.previous.0.snmpUserP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/user-ansible_snmp_user" - - remove_snmp_user.previous.0.snmpUserP.attributes.name == "ansible_snmp_user" + - cm_remove_snmp_user is changed + - cm_remove_snmp_user.previous.0.snmpUserP.attributes.name == "ansible_snmp_user" + - cm_remove_snmp_user.proposed == {} + - nm_remove_snmp_user is changed + - nm_remove_snmp_user.current == [] + - nm_remove_snmp_user.previous.0.snmpUserP.attributes.name == "ansible_snmp_user" + - nm_remove_snmp_user_again is not changed + - nm_remove_snmp_user_again.current == [] + - nm_remove_snmp_user_again.previous == [] -# DELETE snmp policy +# CLEAN ENVIRONMENT - name: Remove the snmp policy - aci_snmp_policy: + cisco.aci.aci_snmp_policy: <<: *aci_info name: ansible_snmp_policy state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_static_binding_to_epg/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_static_binding_to_epg/tasks/main.yml index 180848e28..0e9096b85 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_static_binding_to_epg/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_static_binding_to_epg/tasks/main.yml @@ -306,7 +306,7 @@ - 104 - 105 ignore_errors: true - register: fex_vpc_three extpaths + register: fex_vpc_three_extpaths - name: Bind static-binding to epg - fex_port_channel with multiple extpaths (check_mode) cisco.aci.aci_static_binding_to_epg: diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_remote_dest/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_remote_dest/tasks/main.yml index 0840aec20..82839ddf7 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_remote_dest/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_remote_dest/tasks/main.yml @@ -46,7 +46,6 @@ facility: local1 syslog_port: 5678 description: ansible syslog remote destination - mgmt_epg: oob-default format: aci admin_state: enabled severity: warnings @@ -66,11 +65,7 @@ - add_syslog_remote_dest.current.0.syslogRemoteDest.attributes.adminState == "enabled" - add_syslog_remote_dest.current.0.syslogRemoteDest.attributes.severity == "warnings" - add_syslog_remote_dest.current.0.syslogRemoteDest.attributes.annotation == 'orchestrator:ansible' - -- name: Verify that ansible_syslog_remote_dest children have correct attributes - assert: - that: - - add_syslog_remote_dest.current.0.syslogRemoteDest.children.0.fileRsARemoteHostToEpg.attributes.tDn == "uni/tn-mgmt/mgmtp-default/oob-default" + - '"children" not in add_syslog_remote_dest.current.0.syslogRemoteDest' # ADD syslog remote dest again to check idempotency - name: Add syslog remote dest @@ -82,7 +77,6 @@ facility: local1 syslog_port: 5678 description: ansible syslog remote destination - mgmt_epg: oob-default format: aci admin_state: enabled severity: warnings @@ -124,6 +118,11 @@ - update_syslog_remote_dest.current.0.syslogRemoteDest.attributes.adminState == "disabled" - update_syslog_remote_dest.current.0.syslogRemoteDest.attributes.severity == "information" +- name: Verify that ansible_syslog_remote_dest children have correct attributes + assert: + that: + - update_syslog_remote_dest.current.0.syslogRemoteDest.children.0.fileRsARemoteHostToEpg.attributes.tDn == "uni/tn-mgmt/mgmtp-default/oob-default" + # QUERY syslog source - name: Query the syslog source aci_syslog_remote_dest: diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_source/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_source/tasks/main.yml index c237d17fe..a7180649f 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_source/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_source/tasks/main.yml @@ -40,10 +40,6 @@ aci_syslog_source: <<: *aci_info name: ansible_syslog_src - include: - - audit - - events - - faults min_severity: errors destination_group: ansible_syslog_group state: present @@ -54,7 +50,7 @@ that: - add_syslog_src.current.0.syslogSrc.attributes.dn == "uni/fabric/moncommon/slsrc-ansible_syslog_src" - add_syslog_src.current.0.syslogSrc.attributes.name == "ansible_syslog_src" - - add_syslog_src.current.0.syslogSrc.attributes.incl == "audit,events,faults" + - add_syslog_src.current.0.syslogSrc.attributes.incl == "faults" - add_syslog_src.current.0.syslogSrc.attributes.minSev == "errors" - add_syslog_src.current.0.syslogSrc.attributes.annotation == 'orchestrator:ansible' @@ -68,10 +64,6 @@ aci_syslog_source: <<: *aci_info name: ansible_syslog_src - include: - - audit - - events - - faults min_severity: errors destination_group: ansible_syslog_group state: present @@ -88,7 +80,9 @@ <<: *aci_info name: ansible_syslog_src include: - - faults + - audit + - events + - faults min_severity: information destination_group: ansible_syslog_group state: present @@ -99,7 +93,7 @@ that: - update_syslog_src.current.0.syslogSrc.attributes.dn == "uni/fabric/moncommon/slsrc-ansible_syslog_src" - update_syslog_src.current.0.syslogSrc.attributes.name == "ansible_syslog_src" - - update_syslog_src.current.0.syslogSrc.attributes.incl == "faults" + - update_syslog_src.current.0.syslogSrc.attributes.incl == "audit,events,faults" - update_syslog_src.current.0.syslogSrc.attributes.minSev == "information" # QUERY syslog source @@ -116,7 +110,7 @@ - query_syslog_src is not changed - query_syslog_src.current.0.syslogSrc.attributes.dn == "uni/fabric/moncommon/slsrc-ansible_syslog_src" - query_syslog_src.current.0.syslogSrc.attributes.name == "ansible_syslog_src" - - query_syslog_src.current.0.syslogSrc.attributes.incl == "faults" + - query_syslog_src.current.0.syslogSrc.attributes.incl == "audit,events,faults" - query_syslog_src.current.0.syslogSrc.attributes.minSev == "information" - name: Query all syslog sources diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_system_banner/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_system_banner/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_system_banner/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_system_banner/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_system_banner/tasks/main.yml new file mode 100644 index 000000000..5b9cb96f0 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_system_banner/tasks/main.yml @@ -0,0 +1,221 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Tim Cragg (@timcragg) +# Copyright: (c) 2023, Akini Ross (@akinross) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +# CLEANUP ENVIRONMENT +- name: Clear the current alias and banner configuration + cisco.aci.aci_system_banner: &aci_banner_clear + <<: *aci_info + annotation: "" + gui_alias: "" + controller_banner: "" + application_banner: "" + severity: info + switch_banner: "" + gui_banner: "" + +# UPDATE ALIAS AND BANNER CONFIGURATION +- name: Update alias and banner configuration (check mode) + cisco.aci.aci_system_banner: &aci_banner + <<: *aci_info + gui_alias: "Ansible Test GUI Alias" + controller_banner: "Ansible Test Controller Banner" + application_banner: "Ansible Test Application Banner" + severity: critical + switch_banner: "Ansible Test Switch Banner" + gui_banner: "Ansible Test GUI Banner" + check_mode: true + register: cm_update_banner + +- name: Update alias and banner configuration + cisco.aci.aci_system_banner: + <<: *aci_banner + register: nm_update_banner + +- name: Update alias and banner configuration again + cisco.aci.aci_system_banner: + <<: *aci_banner + register: nm_update_banner_again + +- name: Verify alias and banner configuration + ansible.builtin.assert: + that: + - cm_update_banner is changed + - cm_update_banner.proposed.aaaPreLoginBanner.attributes.annotation == "orchestrator:ansible" + - cm_update_banner.proposed.aaaPreLoginBanner.attributes.bannerMessage == "Ansible Test Application Banner" + - cm_update_banner.proposed.aaaPreLoginBanner.attributes.bannerMessageSeverity == "critical" + - cm_update_banner.proposed.aaaPreLoginBanner.attributes.dn == "uni/userext/preloginbanner" + - cm_update_banner.proposed.aaaPreLoginBanner.attributes.guiMessage == "Ansible Test GUI Banner" + - cm_update_banner.proposed.aaaPreLoginBanner.attributes.isGuiMessageText == "yes" + - cm_update_banner.proposed.aaaPreLoginBanner.attributes.guiTextMessage == "Ansible Test GUI Alias" + - cm_update_banner.proposed.aaaPreLoginBanner.attributes.message == "Ansible Test Controller Banner" + - cm_update_banner.proposed.aaaPreLoginBanner.attributes.showBannerMessage == "yes" + - cm_update_banner.proposed.aaaPreLoginBanner.attributes.switchMessage == "Ansible Test Switch Banner" + - cm_update_banner.current.0.aaaPreLoginBanner.attributes.annotation == "" + - cm_update_banner.current.0.aaaPreLoginBanner.attributes.bannerMessage == "" + - cm_update_banner.current.0.aaaPreLoginBanner.attributes.bannerMessageSeverity == "info" + - cm_update_banner.current.0.aaaPreLoginBanner.attributes.dn == "uni/userext/preloginbanner" + - cm_update_banner.current.0.aaaPreLoginBanner.attributes.guiMessage == "" + - cm_update_banner.current.0.aaaPreLoginBanner.attributes.isGuiMessageText == "yes" + - cm_update_banner.current.0.aaaPreLoginBanner.attributes.guiTextMessage == "" + - cm_update_banner.current.0.aaaPreLoginBanner.attributes.message == "" + - cm_update_banner.current.0.aaaPreLoginBanner.attributes.showBannerMessage == "no" + - cm_update_banner.current.0.aaaPreLoginBanner.attributes.switchMessage == "" + - nm_update_banner is changed + - nm_update_banner.current.0.aaaPreLoginBanner.attributes.annotation == "orchestrator:ansible" + - nm_update_banner.current.0.aaaPreLoginBanner.attributes.bannerMessage == "Ansible Test Application Banner" + - nm_update_banner.current.0.aaaPreLoginBanner.attributes.bannerMessageSeverity == "critical" + - nm_update_banner.current.0.aaaPreLoginBanner.attributes.dn == "uni/userext/preloginbanner" + - nm_update_banner.current.0.aaaPreLoginBanner.attributes.guiMessage == "Ansible Test GUI Banner" + - nm_update_banner.current.0.aaaPreLoginBanner.attributes.isGuiMessageText == "yes" + - nm_update_banner.current.0.aaaPreLoginBanner.attributes.guiTextMessage == "Ansible Test GUI Alias" + - nm_update_banner.current.0.aaaPreLoginBanner.attributes.message == "Ansible Test Controller Banner" + - nm_update_banner.current.0.aaaPreLoginBanner.attributes.showBannerMessage == "yes" + - nm_update_banner.current.0.aaaPreLoginBanner.attributes.switchMessage == "Ansible Test Switch Banner" + - nm_update_banner.previous.0.aaaPreLoginBanner.attributes.annotation == "" + - nm_update_banner.previous.0.aaaPreLoginBanner.attributes.bannerMessage == "" + - nm_update_banner.previous.0.aaaPreLoginBanner.attributes.bannerMessageSeverity == "info" + - nm_update_banner.previous.0.aaaPreLoginBanner.attributes.dn == "uni/userext/preloginbanner" + - nm_update_banner.previous.0.aaaPreLoginBanner.attributes.guiMessage == "" + - nm_update_banner.previous.0.aaaPreLoginBanner.attributes.isGuiMessageText == "yes" + - nm_update_banner.previous.0.aaaPreLoginBanner.attributes.guiTextMessage == "" + - nm_update_banner.previous.0.aaaPreLoginBanner.attributes.message == "" + - nm_update_banner.previous.0.aaaPreLoginBanner.attributes.showBannerMessage == "no" + - nm_update_banner.previous.0.aaaPreLoginBanner.attributes.switchMessage == "" + - nm_update_banner_again is not changed + - nm_update_banner_again.current.0.aaaPreLoginBanner.attributes.annotation == "orchestrator:ansible" + - nm_update_banner_again.current.0.aaaPreLoginBanner.attributes.bannerMessage == "Ansible Test Application Banner" + - nm_update_banner_again.current.0.aaaPreLoginBanner.attributes.bannerMessageSeverity == "critical" + - nm_update_banner_again.current.0.aaaPreLoginBanner.attributes.dn == "uni/userext/preloginbanner" + - nm_update_banner_again.current.0.aaaPreLoginBanner.attributes.guiMessage == "Ansible Test GUI Banner" + - nm_update_banner_again.current.0.aaaPreLoginBanner.attributes.isGuiMessageText == "yes" + - nm_update_banner_again.current.0.aaaPreLoginBanner.attributes.guiTextMessage == "Ansible Test GUI Alias" + - nm_update_banner_again.current.0.aaaPreLoginBanner.attributes.message == "Ansible Test Controller Banner" + - nm_update_banner_again.current.0.aaaPreLoginBanner.attributes.showBannerMessage == "yes" + - nm_update_banner_again.current.0.aaaPreLoginBanner.attributes.switchMessage == "Ansible Test Switch Banner" + - nm_update_banner_again.previous.0.aaaPreLoginBanner.attributes.annotation == "orchestrator:ansible" + - nm_update_banner_again.previous.0.aaaPreLoginBanner.attributes.bannerMessage == "Ansible Test Application Banner" + - nm_update_banner_again.previous.0.aaaPreLoginBanner.attributes.bannerMessageSeverity == "critical" + - nm_update_banner_again.previous.0.aaaPreLoginBanner.attributes.dn == "uni/userext/preloginbanner" + - nm_update_banner_again.previous.0.aaaPreLoginBanner.attributes.guiMessage == "Ansible Test GUI Banner" + - nm_update_banner_again.previous.0.aaaPreLoginBanner.attributes.isGuiMessageText == "yes" + - nm_update_banner_again.previous.0.aaaPreLoginBanner.attributes.guiTextMessage == "Ansible Test GUI Alias" + - nm_update_banner_again.previous.0.aaaPreLoginBanner.attributes.message == "Ansible Test Controller Banner" + - nm_update_banner_again.previous.0.aaaPreLoginBanner.attributes.showBannerMessage == "yes" + - nm_update_banner_again.previous.0.aaaPreLoginBanner.attributes.switchMessage == "Ansible Test Switch Banner" + +- name: Update alias and banner configuration with http url + cisco.aci.aci_system_banner: + <<: *aci_banner + gui_banner: http://www.cisco.com + register: nm_update_banner_with_url_http + +- name: Update alias and banner configuration with https url + cisco.aci.aci_system_banner: + <<: *aci_banner + gui_banner: https://www.cisco.com + register: nm_update_banner_with_url_https + +- name: Verify alias and banner configuration with url + ansible.builtin.assert: + that: + - nm_update_banner_with_url_http is changed + - nm_update_banner_with_url_http.current.0.aaaPreLoginBanner.attributes.annotation == "orchestrator:ansible" + - nm_update_banner_with_url_http.current.0.aaaPreLoginBanner.attributes.bannerMessage == "Ansible Test Application Banner" + - nm_update_banner_with_url_http.current.0.aaaPreLoginBanner.attributes.bannerMessageSeverity == "critical" + - nm_update_banner_with_url_http.current.0.aaaPreLoginBanner.attributes.dn == "uni/userext/preloginbanner" + - nm_update_banner_with_url_http.current.0.aaaPreLoginBanner.attributes.guiMessage == "http://www.cisco.com" + - nm_update_banner_with_url_http.current.0.aaaPreLoginBanner.attributes.isGuiMessageText == "no" + - nm_update_banner_with_url_http.current.0.aaaPreLoginBanner.attributes.guiTextMessage == "Ansible Test GUI Alias" + - nm_update_banner_with_url_http.current.0.aaaPreLoginBanner.attributes.message == "Ansible Test Controller Banner" + - nm_update_banner_with_url_http.current.0.aaaPreLoginBanner.attributes.showBannerMessage == "yes" + - nm_update_banner_with_url_http.current.0.aaaPreLoginBanner.attributes.switchMessage == "Ansible Test Switch Banner" + - nm_update_banner_with_url_http.previous.0.aaaPreLoginBanner.attributes.annotation == "orchestrator:ansible" + - nm_update_banner_with_url_http.previous.0.aaaPreLoginBanner.attributes.bannerMessage == "Ansible Test Application Banner" + - nm_update_banner_with_url_http.previous.0.aaaPreLoginBanner.attributes.bannerMessageSeverity == "critical" + - nm_update_banner_with_url_http.previous.0.aaaPreLoginBanner.attributes.dn == "uni/userext/preloginbanner" + - nm_update_banner_with_url_http.previous.0.aaaPreLoginBanner.attributes.guiMessage == "Ansible Test GUI Banner" + - nm_update_banner_with_url_http.previous.0.aaaPreLoginBanner.attributes.isGuiMessageText == "yes" + - nm_update_banner_with_url_http.previous.0.aaaPreLoginBanner.attributes.guiTextMessage == "Ansible Test GUI Alias" + - nm_update_banner_with_url_http.previous.0.aaaPreLoginBanner.attributes.message == "Ansible Test Controller Banner" + - nm_update_banner_with_url_http.previous.0.aaaPreLoginBanner.attributes.showBannerMessage == "yes" + - nm_update_banner_with_url_http.previous.0.aaaPreLoginBanner.attributes.switchMessage == "Ansible Test Switch Banner" + - nm_update_banner_with_url_https is changed + - nm_update_banner_with_url_https.current.0.aaaPreLoginBanner.attributes.annotation == "orchestrator:ansible" + - nm_update_banner_with_url_https.current.0.aaaPreLoginBanner.attributes.bannerMessage == "Ansible Test Application Banner" + - nm_update_banner_with_url_https.current.0.aaaPreLoginBanner.attributes.bannerMessageSeverity == "critical" + - nm_update_banner_with_url_https.current.0.aaaPreLoginBanner.attributes.dn == "uni/userext/preloginbanner" + - nm_update_banner_with_url_https.current.0.aaaPreLoginBanner.attributes.guiMessage == "https://www.cisco.com" + - nm_update_banner_with_url_https.current.0.aaaPreLoginBanner.attributes.isGuiMessageText == "no" + - nm_update_banner_with_url_https.current.0.aaaPreLoginBanner.attributes.guiTextMessage == "Ansible Test GUI Alias" + - nm_update_banner_with_url_https.current.0.aaaPreLoginBanner.attributes.message == "Ansible Test Controller Banner" + - nm_update_banner_with_url_https.current.0.aaaPreLoginBanner.attributes.showBannerMessage == "yes" + - nm_update_banner_with_url_https.current.0.aaaPreLoginBanner.attributes.switchMessage == "Ansible Test Switch Banner" + - nm_update_banner_with_url_https.previous.0.aaaPreLoginBanner.attributes.annotation == "orchestrator:ansible" + - nm_update_banner_with_url_https.previous.0.aaaPreLoginBanner.attributes.bannerMessage == "Ansible Test Application Banner" + - nm_update_banner_with_url_https.previous.0.aaaPreLoginBanner.attributes.bannerMessageSeverity == "critical" + - nm_update_banner_with_url_https.previous.0.aaaPreLoginBanner.attributes.dn == "uni/userext/preloginbanner" + - nm_update_banner_with_url_https.previous.0.aaaPreLoginBanner.attributes.guiMessage == "http://www.cisco.com" + - nm_update_banner_with_url_https.previous.0.aaaPreLoginBanner.attributes.isGuiMessageText == "no" + - nm_update_banner_with_url_https.previous.0.aaaPreLoginBanner.attributes.guiTextMessage == "Ansible Test GUI Alias" + - nm_update_banner_with_url_https.previous.0.aaaPreLoginBanner.attributes.message == "Ansible Test Controller Banner" + - nm_update_banner_with_url_https.previous.0.aaaPreLoginBanner.attributes.showBannerMessage == "yes" + - nm_update_banner_with_url_https.previous.0.aaaPreLoginBanner.attributes.switchMessage == "Ansible Test Switch Banner" + +# QUERY ALIAS AND BANNER CONFIGURATION +- name: Query alias and banner configuration + cisco.aci.aci_system_banner: + <<: *aci_banner + state: query + register: query + +- name: Verify alias and banner configuration query + ansible.builtin.assert: + that: + - query is not changed + - query.current.0.aaaPreLoginBanner.attributes.annotation == "orchestrator:ansible" + - query.current.0.aaaPreLoginBanner.attributes.bannerMessage == "Ansible Test Application Banner" + - query.current.0.aaaPreLoginBanner.attributes.bannerMessageSeverity == "critical" + - query.current.0.aaaPreLoginBanner.attributes.dn == "uni/userext/preloginbanner" + - query.current.0.aaaPreLoginBanner.attributes.guiMessage == "https://www.cisco.com" + - query.current.0.aaaPreLoginBanner.attributes.isGuiMessageText == "no" + - query.current.0.aaaPreLoginBanner.attributes.guiTextMessage == "Ansible Test GUI Alias" + - query.current.0.aaaPreLoginBanner.attributes.message == "Ansible Test Controller Banner" + - query.current.0.aaaPreLoginBanner.attributes.showBannerMessage == "yes" + +# ERROR ALIAS AND BANNER CONFIGURATION INPUT +- name: Update alias and banner configuration (error) + cisco.aci.aci_system_banner: + <<: *aci_info + severity: critical + ignore_errors: true + register: err_update_banner_severity + +- name: Verify alias and banner configuration error + ansible.builtin.assert: + that: + - err_update_banner_severity is failed + - err_update_banner_severity.msg == "missing parameter(s) required by 'severity'{{":"}} application_banner" + +# CLEANUP ENVIRONMENT +- name: Clear the current alias and banner configuration + cisco.aci.aci_system_banner: + <<: *aci_banner_clear diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_system_endpoint_controls/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_system_endpoint_controls/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_system_endpoint_controls/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_system_endpoint_controls/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_system_endpoint_controls/tasks/main.yml new file mode 100644 index 000000000..fa98657f6 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_system_endpoint_controls/tasks/main.yml @@ -0,0 +1,307 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Tim Cragg (@timcragg) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will skip execution for cloud sites + block: + + # CONFIGURE SYSTEM ENDPOINT CONTROLS SETTINGS TO DEFAULT + - name: Set system endpoint controls settings to default prior to test + cisco.aci.aci_system_endpoint_controls: + <<: *aci_info + ip_aging: + admin_state: false + roque_ep_control: + admin_state: false + interval: 60 + multiplication_factor: 4 + hold_interval: 1800 + ep_loop_protection: + admin_state: false + interval: 60 + multiplication_factor: 4 + action: [ port ] + + # CONFIGURE SYSTEM ENDPOINT CONTROLS SETTINGS + - name: Set system endpoint controls settings (check_mode) + cisco.aci.aci_system_endpoint_controls: &endpoint_controls + <<: *aci_info + ip_aging: + admin_state: true + roque_ep_control: + admin_state: true + interval: 50 + multiplication_factor: 10 + hold_interval: 2000 + ep_loop_protection: + admin_state: true + interval: 70 + multiplication_factor: 15 + action: [ bd, port ] + check_mode: true + register: cm_set_endpoint_controls + + - name: Set system endpoint controls settings + cisco.aci.aci_system_endpoint_controls: + <<: *endpoint_controls + register: nm_set_endpoint_controls + + - name: Set system endpoint controls settings again + cisco.aci.aci_system_endpoint_controls: + <<: *endpoint_controls + register: nm_set_endpoint_controls_again + + - name: Verify set system endpoint controls + ansible.builtin.assert: + that: + - cm_set_endpoint_controls is changed + - cm_set_endpoint_controls.proposed.infraInfra.children.0.epIpAgingP.attributes.adminSt == "enabled" + - cm_set_endpoint_controls.proposed.infraInfra.children.0.epIpAgingP.attributes.name == "default" + - cm_set_endpoint_controls.proposed.infraInfra.children.1.epControlP.attributes.adminSt == "enabled" + - cm_set_endpoint_controls.proposed.infraInfra.children.1.epControlP.attributes.name == "default" + - cm_set_endpoint_controls.proposed.infraInfra.children.1.epControlP.attributes.holdIntvl == "2000" + - cm_set_endpoint_controls.proposed.infraInfra.children.1.epControlP.attributes.rogueEpDetectIntvl == "50" + - cm_set_endpoint_controls.proposed.infraInfra.children.1.epControlP.attributes.rogueEpDetectMult == "10" + - cm_set_endpoint_controls.proposed.infraInfra.children.2.epLoopProtectP.attributes.adminSt == "enabled" + - cm_set_endpoint_controls.proposed.infraInfra.children.2.epLoopProtectP.attributes.name == "default" + - cm_set_endpoint_controls.proposed.infraInfra.children.2.epLoopProtectP.attributes.action == "bd-learn-disable,port-disable" + - cm_set_endpoint_controls.proposed.infraInfra.children.2.epLoopProtectP.attributes.loopDetectIntvl == "70" + - cm_set_endpoint_controls.proposed.infraInfra.children.2.epLoopProtectP.attributes.loopDetectMult == "15" + - nm_set_endpoint_controls is changed + - nm_set_endpoint_controls.current.0.infraInfra.children.0.epIpAgingP.attributes.adminSt == "enabled" + - nm_set_endpoint_controls.current.0.infraInfra.children.0.epIpAgingP.attributes.name == "default" + - nm_set_endpoint_controls.current.0.infraInfra.children.1.epControlP.attributes.adminSt == "enabled" + - nm_set_endpoint_controls.current.0.infraInfra.children.1.epControlP.attributes.name == "default" + - nm_set_endpoint_controls.current.0.infraInfra.children.1.epControlP.attributes.holdIntvl == "2000" + - nm_set_endpoint_controls.current.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectIntvl == "50" + - nm_set_endpoint_controls.current.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectMult == "10" + - nm_set_endpoint_controls.current.0.infraInfra.children.2.epLoopProtectP.attributes.adminSt == "enabled" + - nm_set_endpoint_controls.current.0.infraInfra.children.2.epLoopProtectP.attributes.name == "default" + - nm_set_endpoint_controls.current.0.infraInfra.children.2.epLoopProtectP.attributes.action == "bd-learn-disable,port-disable" + - nm_set_endpoint_controls.current.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectIntvl == "70" + - nm_set_endpoint_controls.current.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectMult == "15" + - nm_set_endpoint_controls_again is not changed + - nm_set_endpoint_controls_again.current.0.infraInfra.children.0.epIpAgingP.attributes.adminSt == "enabled" + - nm_set_endpoint_controls_again.current.0.infraInfra.children.0.epIpAgingP.attributes.name == "default" + - nm_set_endpoint_controls_again.current.0.infraInfra.children.1.epControlP.attributes.adminSt == "enabled" + - nm_set_endpoint_controls_again.current.0.infraInfra.children.1.epControlP.attributes.name == "default" + - nm_set_endpoint_controls_again.current.0.infraInfra.children.1.epControlP.attributes.holdIntvl == "2000" + - nm_set_endpoint_controls_again.current.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectIntvl == "50" + - nm_set_endpoint_controls_again.current.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectMult == "10" + - nm_set_endpoint_controls_again.current.0.infraInfra.children.2.epLoopProtectP.attributes.adminSt == "enabled" + - nm_set_endpoint_controls_again.current.0.infraInfra.children.2.epLoopProtectP.attributes.name == "default" + - nm_set_endpoint_controls_again.current.0.infraInfra.children.2.epLoopProtectP.attributes.action == "bd-learn-disable,port-disable" + - nm_set_endpoint_controls_again.current.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectIntvl == "70" + - nm_set_endpoint_controls_again.current.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectMult == "15" + - nm_set_endpoint_controls_again.previous.0.infraInfra.children.0.epIpAgingP.attributes.adminSt == "enabled" + - nm_set_endpoint_controls_again.previous.0.infraInfra.children.0.epIpAgingP.attributes.name == "default" + - nm_set_endpoint_controls_again.previous.0.infraInfra.children.1.epControlP.attributes.adminSt == "enabled" + - nm_set_endpoint_controls_again.previous.0.infraInfra.children.1.epControlP.attributes.name == "default" + - nm_set_endpoint_controls_again.previous.0.infraInfra.children.1.epControlP.attributes.holdIntvl == "2000" + - nm_set_endpoint_controls_again.previous.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectIntvl == "50" + - nm_set_endpoint_controls_again.previous.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectMult == "10" + - nm_set_endpoint_controls_again.previous.0.infraInfra.children.2.epLoopProtectP.attributes.adminSt == "enabled" + - nm_set_endpoint_controls_again.previous.0.infraInfra.children.2.epLoopProtectP.attributes.name == "default" + - nm_set_endpoint_controls_again.previous.0.infraInfra.children.2.epLoopProtectP.attributes.action == "bd-learn-disable,port-disable" + - nm_set_endpoint_controls_again.previous.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectIntvl == "70" + - nm_set_endpoint_controls_again.previous.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectMult == "15" + + - name: Set ip aging system endpoint controls settings to default + cisco.aci.aci_system_endpoint_controls: + <<: *aci_info + ip_aging: + admin_state: false + register: nm_ip_aging + + - name: Set roque ep control system endpoint controls settings to default + cisco.aci.aci_system_endpoint_controls: + <<: *aci_info + roque_ep_control: + admin_state: false + interval: 60 + multiplication_factor: 4 + hold_interval: 1800 + register: nm_roque_ep_control + + - name: Set ep loop protection system endpoint controls settings without action to default + cisco.aci.aci_system_endpoint_controls: + <<: *aci_info + ep_loop_protection: + admin_state: false + interval: 60 + multiplication_factor: 4 + register: nm_ep_loop_protection_no_action + + - name: Set ep loop protection system endpoint controls settings action to default + cisco.aci.aci_system_endpoint_controls: + <<: *aci_info + ep_loop_protection: + action: port + register: nm_ep_loop_protection_action + + - name: Set system endpoint controls settings without config in config containers + cisco.aci.aci_system_endpoint_controls: + <<: *aci_info + ip_aging: + roque_ep_control: + ep_loop_protection: + register: nm_no_config_in_config_containers + + - name: Set system endpoint controls settings without config (error) + cisco.aci.aci_system_endpoint_controls: + <<: *aci_info + register: err_no_config + ignore_errors: true + + - name: Verify individual set system endpoint controls and error + ansible.builtin.assert: + that: + - nm_ip_aging is changed + - nm_ip_aging.previous.0.infraInfra.children.0.epIpAgingP.attributes.adminSt == "enabled" + - nm_ip_aging.previous.0.infraInfra.children.0.epIpAgingP.attributes.name == "default" + - nm_ip_aging.previous.0.infraInfra.children.1.epControlP.attributes.adminSt == "enabled" + - nm_ip_aging.previous.0.infraInfra.children.1.epControlP.attributes.name == "default" + - nm_ip_aging.previous.0.infraInfra.children.1.epControlP.attributes.holdIntvl == "2000" + - nm_ip_aging.previous.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectIntvl == "50" + - nm_ip_aging.previous.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectMult == "10" + - nm_ip_aging.previous.0.infraInfra.children.2.epLoopProtectP.attributes.adminSt == "enabled" + - nm_ip_aging.previous.0.infraInfra.children.2.epLoopProtectP.attributes.name == "default" + - nm_ip_aging.previous.0.infraInfra.children.2.epLoopProtectP.attributes.action == "bd-learn-disable,port-disable" + - nm_ip_aging.previous.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectIntvl == "70" + - nm_ip_aging.previous.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectMult == "15" + - nm_ip_aging.current.0.infraInfra.children.0.epIpAgingP.attributes.adminSt == "disabled" + - nm_ip_aging.current.0.infraInfra.children.0.epIpAgingP.attributes.name == "default" + - nm_ip_aging.current.0.infraInfra.children.1.epControlP.attributes.adminSt == "enabled" + - nm_ip_aging.current.0.infraInfra.children.1.epControlP.attributes.name == "default" + - nm_ip_aging.current.0.infraInfra.children.1.epControlP.attributes.holdIntvl == "2000" + - nm_ip_aging.current.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectIntvl == "50" + - nm_ip_aging.current.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectMult == "10" + - nm_ip_aging.current.0.infraInfra.children.2.epLoopProtectP.attributes.adminSt == "enabled" + - nm_ip_aging.current.0.infraInfra.children.2.epLoopProtectP.attributes.name == "default" + - nm_ip_aging.current.0.infraInfra.children.2.epLoopProtectP.attributes.action == "bd-learn-disable,port-disable" + - nm_ip_aging.current.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectIntvl == "70" + - nm_ip_aging.current.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectMult == "15" + - nm_roque_ep_control is changed + - nm_roque_ep_control.previous.0.infraInfra.children.0.epIpAgingP.attributes.adminSt == "disabled" + - nm_roque_ep_control.previous.0.infraInfra.children.0.epIpAgingP.attributes.name == "default" + - nm_roque_ep_control.previous.0.infraInfra.children.1.epControlP.attributes.adminSt == "enabled" + - nm_roque_ep_control.previous.0.infraInfra.children.1.epControlP.attributes.name == "default" + - nm_roque_ep_control.previous.0.infraInfra.children.1.epControlP.attributes.holdIntvl == "2000" + - nm_roque_ep_control.previous.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectIntvl == "50" + - nm_roque_ep_control.previous.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectMult == "10" + - nm_roque_ep_control.previous.0.infraInfra.children.2.epLoopProtectP.attributes.adminSt == "enabled" + - nm_roque_ep_control.previous.0.infraInfra.children.2.epLoopProtectP.attributes.name == "default" + - nm_roque_ep_control.previous.0.infraInfra.children.2.epLoopProtectP.attributes.action == "bd-learn-disable,port-disable" + - nm_roque_ep_control.previous.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectIntvl == "70" + - nm_roque_ep_control.previous.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectMult == "15" + - nm_roque_ep_control.current.0.infraInfra.children.0.epIpAgingP.attributes.adminSt == "disabled" + - nm_roque_ep_control.current.0.infraInfra.children.0.epIpAgingP.attributes.name == "default" + - nm_roque_ep_control.current.0.infraInfra.children.1.epControlP.attributes.adminSt == "disabled" + - nm_roque_ep_control.current.0.infraInfra.children.1.epControlP.attributes.name == "default" + - nm_roque_ep_control.current.0.infraInfra.children.1.epControlP.attributes.holdIntvl == "1800" + - nm_roque_ep_control.current.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectIntvl == "60" + - nm_roque_ep_control.current.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectMult == "4" + - nm_roque_ep_control.current.0.infraInfra.children.2.epLoopProtectP.attributes.adminSt == "enabled" + - nm_roque_ep_control.current.0.infraInfra.children.2.epLoopProtectP.attributes.name == "default" + - nm_roque_ep_control.current.0.infraInfra.children.2.epLoopProtectP.attributes.action == "bd-learn-disable,port-disable" + - nm_roque_ep_control.current.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectIntvl == "70" + - nm_roque_ep_control.current.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectMult == "15" + - nm_ep_loop_protection_no_action is changed + - nm_ep_loop_protection_no_action.previous.0.infraInfra.children.0.epIpAgingP.attributes.adminSt == "disabled" + - nm_ep_loop_protection_no_action.previous.0.infraInfra.children.0.epIpAgingP.attributes.name == "default" + - nm_ep_loop_protection_no_action.previous.0.infraInfra.children.1.epControlP.attributes.adminSt == "disabled" + - nm_ep_loop_protection_no_action.previous.0.infraInfra.children.1.epControlP.attributes.name == "default" + - nm_ep_loop_protection_no_action.previous.0.infraInfra.children.1.epControlP.attributes.holdIntvl == "1800" + - nm_ep_loop_protection_no_action.previous.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectIntvl == "60" + - nm_ep_loop_protection_no_action.previous.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectMult == "4" + - nm_ep_loop_protection_no_action.previous.0.infraInfra.children.2.epLoopProtectP.attributes.adminSt == "enabled" + - nm_ep_loop_protection_no_action.previous.0.infraInfra.children.2.epLoopProtectP.attributes.name == "default" + - nm_ep_loop_protection_no_action.previous.0.infraInfra.children.2.epLoopProtectP.attributes.action == "bd-learn-disable,port-disable" + - nm_ep_loop_protection_no_action.previous.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectIntvl == "70" + - nm_ep_loop_protection_no_action.previous.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectMult == "15" + - nm_ep_loop_protection_no_action.current.0.infraInfra.children.0.epIpAgingP.attributes.adminSt == "disabled" + - nm_ep_loop_protection_no_action.current.0.infraInfra.children.0.epIpAgingP.attributes.name == "default" + - nm_ep_loop_protection_no_action.current.0.infraInfra.children.1.epControlP.attributes.adminSt == "disabled" + - nm_ep_loop_protection_no_action.current.0.infraInfra.children.1.epControlP.attributes.name == "default" + - nm_ep_loop_protection_no_action.current.0.infraInfra.children.1.epControlP.attributes.holdIntvl == "1800" + - nm_ep_loop_protection_no_action.current.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectIntvl == "60" + - nm_ep_loop_protection_no_action.current.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectMult == "4" + - nm_ep_loop_protection_no_action.current.0.infraInfra.children.2.epLoopProtectP.attributes.adminSt == "disabled" + - nm_ep_loop_protection_no_action.current.0.infraInfra.children.2.epLoopProtectP.attributes.name == "default" + - nm_ep_loop_protection_no_action.current.0.infraInfra.children.2.epLoopProtectP.attributes.action == "bd-learn-disable,port-disable" + - nm_ep_loop_protection_no_action.current.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectIntvl == "60" + - nm_ep_loop_protection_no_action.current.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectMult == "4" + - nm_ep_loop_protection_action is changed + - nm_ep_loop_protection_action.previous.0.infraInfra.children.0.epIpAgingP.attributes.adminSt == "disabled" + - nm_ep_loop_protection_action.previous.0.infraInfra.children.0.epIpAgingP.attributes.name == "default" + - nm_ep_loop_protection_action.previous.0.infraInfra.children.1.epControlP.attributes.adminSt == "disabled" + - nm_ep_loop_protection_action.previous.0.infraInfra.children.1.epControlP.attributes.name == "default" + - nm_ep_loop_protection_action.previous.0.infraInfra.children.1.epControlP.attributes.holdIntvl == "1800" + - nm_ep_loop_protection_action.previous.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectIntvl == "60" + - nm_ep_loop_protection_action.previous.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectMult == "4" + - nm_ep_loop_protection_action.previous.0.infraInfra.children.2.epLoopProtectP.attributes.adminSt == "disabled" + - nm_ep_loop_protection_action.previous.0.infraInfra.children.2.epLoopProtectP.attributes.name == "default" + - nm_ep_loop_protection_action.previous.0.infraInfra.children.2.epLoopProtectP.attributes.action == "bd-learn-disable,port-disable" + - nm_ep_loop_protection_action.previous.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectIntvl == "60" + - nm_ep_loop_protection_action.previous.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectMult == "4" + - nm_ep_loop_protection_action.current.0.infraInfra.children.0.epIpAgingP.attributes.adminSt == "disabled" + - nm_ep_loop_protection_action.current.0.infraInfra.children.0.epIpAgingP.attributes.name == "default" + - nm_ep_loop_protection_action.current.0.infraInfra.children.1.epControlP.attributes.adminSt == "disabled" + - nm_ep_loop_protection_action.current.0.infraInfra.children.1.epControlP.attributes.name == "default" + - nm_ep_loop_protection_action.current.0.infraInfra.children.1.epControlP.attributes.holdIntvl == "1800" + - nm_ep_loop_protection_action.current.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectIntvl == "60" + - nm_ep_loop_protection_action.current.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectMult == "4" + - nm_ep_loop_protection_action.current.0.infraInfra.children.2.epLoopProtectP.attributes.adminSt == "disabled" + - nm_ep_loop_protection_action.current.0.infraInfra.children.2.epLoopProtectP.attributes.name == "default" + - nm_ep_loop_protection_action.current.0.infraInfra.children.2.epLoopProtectP.attributes.action == "port-disable" + - nm_ep_loop_protection_action.current.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectIntvl == "60" + - nm_ep_loop_protection_action.current.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectMult == "4" + - nm_no_config_in_config_containers is not changed + - err_no_config is not changed + - err_no_config is failed + - err_no_config.msg == "state is present but any of the following are missing{{":"}} ip_aging, roque_ep_control, ep_loop_protection" + + # QUERY SYSTEM ENDPOINT CONTROLS SETTINGS + - name: Query system endpoint controls settings + cisco.aci.aci_system_endpoint_controls: + <<: *aci_info + state: query + register: query_endpoint_controls + + - name: Verify system endpoint controls query + ansible.builtin.assert: + that: + - query_endpoint_controls is not changed + - query_endpoint_controls.current.0.infraInfra.children.0.epIpAgingP.attributes.adminSt == "disabled" + - query_endpoint_controls.current.0.infraInfra.children.0.epIpAgingP.attributes.name == "default" + - query_endpoint_controls.current.0.infraInfra.children.1.epControlP.attributes.adminSt == "disabled" + - query_endpoint_controls.current.0.infraInfra.children.1.epControlP.attributes.name == "default" + - query_endpoint_controls.current.0.infraInfra.children.1.epControlP.attributes.holdIntvl == "1800" + - query_endpoint_controls.current.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectIntvl == "60" + - query_endpoint_controls.current.0.infraInfra.children.1.epControlP.attributes.rogueEpDetectMult == "4" + - query_endpoint_controls.current.0.infraInfra.children.2.epLoopProtectP.attributes.adminSt == "disabled" + - query_endpoint_controls.current.0.infraInfra.children.2.epLoopProtectP.attributes.name == "default" + - query_endpoint_controls.current.0.infraInfra.children.2.epLoopProtectP.attributes.action == "port-disable" + - query_endpoint_controls.current.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectIntvl == "60" + - query_endpoint_controls.current.0.infraInfra.children.2.epLoopProtectP.attributes.loopDetectMult == "4" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_system_global_aes_passphrase_encryption/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_system_global_aes_passphrase_encryption/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_system_global_aes_passphrase_encryption/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_system_global_aes_passphrase_encryption/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_system_global_aes_passphrase_encryption/tasks/main.yml new file mode 100644 index 000000000..732a4d4f3 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_system_global_aes_passphrase_encryption/tasks/main.yml @@ -0,0 +1,84 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Tim Cragg (@timcragg) <tcragg@cisco.com> +# Copyright: (c) 2023, Akini Ross (@akinross) <akinross@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +# SET VARS +- name: Set vars + set_fact: + aci_info: &aci_info + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("info") }}' + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will skip execution for cloud sites + block: + + - name: Clear existing passphrase + cisco.aci.aci_system_global_aes_passphrase_encryption: + <<: *aci_info + state: absent + + - name: Set passphrase + cisco.aci.aci_system_global_aes_passphrase_encryption: + <<: *aci_info + passphrase: ansible_passphrase + state: present + + - name: Query key configured + cisco.aci.aci_system_global_aes_passphrase_encryption: + <<: *aci_info + state: query + register: query_passphrase + + - name: Enable encryption + cisco.aci.aci_system_global_aes_passphrase_encryption: + <<: *aci_info + enable: yes + state: present + + - name: Query encryption enabled + cisco.aci.aci_system_global_aes_passphrase_encryption: + <<: *aci_info + state: query + register: query_encryption + + - name: Verify passphrase and encryption settings + ansible.builtin.assert: + that: + - query_passphrase.current.0.pkiExportEncryptionKey.attributes.keyConfigured == "yes" + - query_passphrase.current.0.pkiExportEncryptionKey.attributes.strongEncryptionEnabled == "no" + - query_encryption.current.0.pkiExportEncryptionKey.attributes.keyConfigured == "yes" + - query_encryption.current.0.pkiExportEncryptionKey.attributes.strongEncryptionEnabled == "yes" + + # CLEAR PASSPHRASE + - name: Clear encryption key + cisco.aci.aci_system_global_aes_passphrase_encryption: + <<: *aci_info + state: absent + + - name: Query cleared encryption key + cisco.aci.aci_system_global_aes_passphrase_encryption: + <<: *aci_info + state: query + register: query_deletion + + - name: Verify encryption key is deleted + ansible.builtin.assert: + that: + - query_deletion.current.0.pkiExportEncryptionKey.attributes.keyConfigured == "no" + - query_deletion.current.0.pkiExportEncryptionKey.attributes.strongEncryptionEnabled == "no" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/filter_plugins/generate_ips.py b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/filter_plugins/generate_ips.py new file mode 100644 index 000000000..130fbb786 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/filter_plugins/generate_ips.py @@ -0,0 +1,28 @@ +# Copyright (c) 2023 Cisco and/or its affiliates. +# Copyright: (c) 2023, Shreyas Srish (@shrsr) <ssrish@cisco.com> + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +from ipaddress import ip_network +import random + +RANGE_IPV4 = list(ip_network("192.0.2.0/24").hosts()) + list(ip_network("198.51.100.0/24").hosts()) + list(ip_network("203.0.113.0/24").hosts()) + + +class FilterModule(object): + def filters(self): + return { + "generate_random_ips": self.generate_random_ips, + } + + def generate_random_ips(self, given_ip, insert_given_ip_at, number_of_ips): + ips = "" + for i in range(number_of_ips): + if i == insert_given_ip_at - 1: + ips += given_ip + else: + ips += str((random.choice(RANGE_IPV4))) + ips += "," + return ips.rstrip(",") diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/admin.crt b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/admin.crt new file mode 100644 index 000000000..cfac5531e --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/admin.crt @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICODCCAaGgAwIBAgIJAIt8XMntue0VMA0GCSqGSIb3DQEBCwUAMDQxDjAMBgNV +BAMMBUFkbWluMRUwEwYDVQQKDAxZb3VyIENvbXBhbnkxCzAJBgNVBAYTAlVTMCAX +DTE4MDEwOTAwNTk0NFoYDzIxMTcxMjE2MDA1OTQ0WjA0MQ4wDAYDVQQDDAVBZG1p +bjEVMBMGA1UECgwMWW91ciBDb21wYW55MQswCQYDVQQGEwJVUzCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAohG/7axtt7CbSaMP7r+2mhTKbNgh0Ww36C7Ta14i +v+VmLyKkQHnXinKGhp6uy3Nug+15a+eIu7CrgpBVMQeCiWfsnwRocKcQJWIYDrWl +XHxGQn31yYKR6mylE7Dcj3rMFybnyhezr5D8GcP85YRPmwG9H2hO/0Y1FUnWu9Iw +AQkCAwEAAaNQME4wHQYDVR0OBBYEFD0jLXfpkrU/ChzRvfruRs/fy1VXMB8GA1Ud +IwQYMBaAFD0jLXfpkrU/ChzRvfruRs/fy1VXMAwGA1UdEwQFMAMBAf8wDQYJKoZI +hvcNAQELBQADgYEAOmvre+5tgZ0+F3DgsfxNQqLTrGiBgGCIymPkP/cBXXkNuJyl +3ac7tArHQc7WEA4U2R2rZbEq8FC3UJJm4nUVtCPvEh3G9OhN2xwYev79yt6pIn/l +KU0Td2OpVyo0eLqjoX5u2G90IBWzhyjFbo+CcKMrSVKj1YOdG0E3OuiJf00= +-----END CERTIFICATE----- diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/admin.key b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/admin.key new file mode 100644 index 000000000..63bb00cc0 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/admin.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKIRv+2sbbewm0mj +D+6/tpoUymzYIdFsN+gu02teIr/lZi8ipEB514pyhoaerstzboPteWvniLuwq4KQ +VTEHgoln7J8EaHCnECViGA61pVx8RkJ99cmCkepspROw3I96zBcm58oXs6+Q/BnD +/OWET5sBvR9oTv9GNRVJ1rvSMAEJAgMBAAECgYByu3QO0qF9h7X3JEu0Ld4cKBnB +giQ2uJC/et7KxIJ/LOvw9GopBthyt27KwG1ntBkJpkTuAaQHkyNns7vLkNB0S0IR ++owVFEcKYq9VCHTaiQU8TDp24gN+yPTrpRuH8YhDVq5SfVdVuTMgHVQdj4ya4VlF +Gj+a7+ipxtGiLsVGrQJBAM7p0Fm0xmzi+tBOASUAcVrPLcteFIaTBFwfq16dm/ON +00Khla8Et5kMBttTbqbukl8mxFjBEEBlhQqb6EdQQ0sCQQDIhHx1a9diG7y/4DQA +4KvR3FCYwP8PBORlSamegzCo+P1OzxiEo0amX7yQMA5UyiP/kUsZrme2JBZgna8S +p4R7AkEAr7rMhSOPUnMD6V4WgsJ5g1Jp5kqkzBaYoVUUSms5RASz4+cwJVCwTX91 +Y1jcpVIBZmaaY3a0wrx13ajEAa0dOQJBAIpjnb4wqpsEh7VpmJqOdSdGxb1XXfFQ +sA0T1OQYqQnFppWwqrxIL+d9pZdiA1ITnNqyvUFBNETqDSOrUHwwb2cCQGArE+vu +ffPUWQ0j+fiK+covFG8NL7H+26NSGB5+Xsn9uwOGLj7K/YT6CbBtr9hJiuWjM1Al +0V4ltlTuu2mTMaw= +-----END PRIVATE KEY----- diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/admin_invalid.key b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/admin_invalid.key new file mode 100644 index 000000000..22f5fae45 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/admin_invalid.key @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +This is an invalid private key +-----END PRIVATE KEY----- diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/openssh_rsa.key b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/openssh_rsa.key new file mode 100644 index 000000000..0c18da5c5 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/openssh_rsa.key @@ -0,0 +1,16 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAlwAAAAdzc2gtcn +NhAAAAAwEAAQAAAIEA3VnrdPOQbr3DPF5GbC31W7ScloEpU9BSDqPmpyYPUdsWl21UXBB8 +exip3GVOl+7GbB1WkDKYr7uMuBjsfDzMzZkDAFVEpud+IUzZB7aSfSd+L9bdeFG2sGI+Fv +y1QmiMBT5gcvXaM16vRKe4FywM07/Fmd3REm/+wtmFG/C4sYUAAAIQLuIWNS7iFjUAAAAH +c3NoLXJzYQAAAIEA3VnrdPOQbr3DPF5GbC31W7ScloEpU9BSDqPmpyYPUdsWl21UXBB8ex +ip3GVOl+7GbB1WkDKYr7uMuBjsfDzMzZkDAFVEpud+IUzZB7aSfSd+L9bdeFG2sGI+Fvy1 +QmiMBT5gcvXaM16vRKe4FywM07/Fmd3REm/+wtmFG/C4sYUAAAADAQABAAAAgHj5rhALFg +MQP2X8+GwjahemzHYNPXMLRe2ucl8kE/de0CgOnq56bC4yupMz4xJyc4ufNTI2FPDmhfAP +3x+/cwZeYFsipyGdL1IYbfk0QYSP65Btr2yq8+QyN7zWdFXQ8csT0ImZgNiQKehc69ctLH +XcyelsdwNiUCRZYa7kCpf5AAAAQQCo7OSWQUa16xP9KrKm0F3fnaAKewhQNDIwok5PRgoN +03k/IpGOCAjvNuOb7DkXmVvxjO8Rj4L16vL+RTzHg8n7AAAAQQD7tej6gJy3MLcmrQ4aHb +FeLzQ/ZXS2IgdIRC8rcNB1h9Rso7+fySVFwnmwy2Um7wwsjNnr2xyhigwfQCSyRubfAAAA +QQDhH5EX7+hdm/fPLM6Goz9N3ERbIgBq2Mel5CCi/Ns7vDfBQiEla1atdKTV0S2EYfxIw2 +ehkMGbmXl2/9JHxKgbAAAAFGNpemhhb0BDSVpIQU8tTS05MjhRAQIDBAUG +-----END OPENSSH PRIVATE KEY----- diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/rsa_ansible.key b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/rsa_ansible.key new file mode 100644 index 000000000..ac63a0055 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/rsa_ansible.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDVyLS8/ix6QOH7R83B4WuhsliL6nffBvrkHXXsqViit3OZd+/K +fSrNlZysUvHS4hxfRtJrFQfpkogwXEEupBPF3p0xy7wZzvjjWWJk0NQ8PoVlOhUY +emZTfMX+FFNr9pAjjjaVHb9jCuxko7upAyj8POhhETY2zYoJoa8TR6fLZwIDAQAB +AoGBALo5GzeGMThNTIyW/6Tjt94ifP9kPwcIDYSoJRECczNKmmgVEcxRO/fZW6DA +n+YTEKPuDV059KqB+iAmPKFkS9N41kaq+NUAknlFJPV6Vs3gpvJGqWgu++73dhR5 +cKsHTlK2KBsRtsXnOJ9odKWFjiTnZ1Eyvmhw7ct+Fojb/7ABAkEA9+Wwm+HGlYqw +ghuFaBtNuqC/S2vO6SEfdQvTDQKKO5ROei5m+ryjWj6flbCcG+5dLs8l4Zh3sQUL +kc0RQfHSWQJBANzFkdO6wXXPOw7RhAEP2sA2W2VacMbGynjsoDJXmypeJ7Z+odLb +5gNXET9RA77RY/saIBdwR4JNnku2WnoxU78CQQDhYirVP0vu8H6UfHMpeRGNqdLi +vq0LlrrkDxEe1f1aN/e17HRiaZnXVfKABWeZmXmNMndNifLgtiaTtC+JllRZAkEA +ydAdV0SANvaCETC7j9DzcgP+lm8PatYsHlCIvJxS7m71tKCbw0pbQDBmRtADMXrt +/4vJTEPKSrYzfxiqKstOtwJAXkWXaqVhJeKjbMj1buo6s/1qGIfSrZR/AjozvJ03 +JehevfULS3668jOYJZW6BoNhysx6+Hqf5Id8fB4iDWPQhA== +-----END RSA PRIVATE KEY----- diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/rsa_user.crt b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/rsa_user.crt new file mode 100644 index 000000000..de2223500 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/rsa_user.crt @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICODCCAaGgAwIBAgIUNOqiIBh811X/tPWSUgr9rajJ7t4wDQYJKoZIhvcNAQEL +BQAwLTEOMAwGA1UEAwwFQWRtaW4xDjAMBgNVBAoMBWNpc2NvMQswCQYDVQQGEwJV +UzAgFw0yMDEwMjkyMjQ0NTNaGA8yMTIwMTAwNTIyNDQ1M1owLTEOMAwGA1UEAwwF +QWRtaW4xDjAMBgNVBAoMBWNpc2NvMQswCQYDVQQGEwJVUzCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAwjb3/W3x/bPX+bylh2PjXbcFPwpdTPJwqTxCdUinJRKv +HXW7rwRiV9TdoNZZ946RvVM6l2LzUJyaK4wZZHf6WKJ2veL6LIrORA32vN+ofmpn +XcTAUQ1JVyHbriy0GaT+1wYClqImWj8HxiskgpD+pKc+kzgl33xwwwqyuF1N7ikC +AwEAAaNTMFEwHQYDVR0OBBYEFAK18YAZAaPQW7bHvqRwselDeGskMB8GA1UdIwQY +MBaAFAK18YAZAaPQW7bHvqRwselDeGskMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI +hvcNAQELBQADgYEAgIvzyP0t4CjsmUmgG7QP977c3+Uvbt2wlCwe+rrXlqvuSeaW +l4DaTyv8kYyiqIxgrTVI/G+HbpHgTO2yH57njTIAdRjsJgMU9z0oCazOtVD8KpXj +SKFUtJVbY27BQAnbuDOawX96a0UDY44Ia9NaPuq0/mEcdCKSpQP4ZuvvKVc= +-----END CERTIFICATE----- diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/rsa_user.key b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/rsa_user.key new file mode 100644 index 000000000..354dbbdbb --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/pki/rsa_user.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMI29/1t8f2z1/m8 +pYdj4123BT8KXUzycKk8QnVIpyUSrx11u68EYlfU3aDWWfeOkb1TOpdi81CcmiuM +GWR3+liidr3i+iyKzkQN9rzfqH5qZ13EwFENSVch264stBmk/tcGApaiJlo/B8Yr +JIKQ/qSnPpM4Jd98cMMKsrhdTe4pAgMBAAECgYAX8c8BX9zF+rZWA/wkhRwzIa1z +6EM4iWt6cgN/kkWJPJR6fVl2aoP1cDki60qMSveM8AX5RCnbdnNLiypWSLSEogdd +bRWyFeF4ZXvivd+Lds2u5Ni3PiCrIpHfNvid2ERCaKhblQRdhi/dTH9Z+3kGspwc +jpKzWMmGjBpqWjWOQQJBAOB3cS/AxbwJ6Fzvbi6sLiK6Ry8eSIMlce3Yyw89oU+M +DGkIbggICCYKxXYIWtBbyxthdQudKFZYbLpCkLSMBXsCQQDdf5ICNN2R0ptYLhSX +kQ4tiGigi1hq93+25Ov1rI8eIFSYlKNcyA/cvwv5ptlXmy1UAyoAdGCbS47pgCwT +Nz+rAkEAtzHkR5PuDXSMluS2KRNPJ/qdxB/UEGzMGdEYkNy8vX5QVpyRqK5dcCbU +V2ukKm7wSe11KEBgPnA2dKGFFkU85wJAD895Vpr7bdtAp2yyn5cFEg74mO0ZZJlC +DoYMqb6lgJsCLtn9RzQonbMtYaadQPmcpLCNIPctpiggjV5OxxhcfQJBAM1ETm8p +/9beBPTS8cJdWHvCRE149H/ZCUxqjFZriJzFYvi0xor85eK8/3V7xaWtTkK25i3+ +xWk+sA3DYYDPGM8= +-----END PRIVATE KEY----- diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/tasks/httpapi_connection.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/tasks/httpapi_connection.yml new file mode 100644 index 000000000..214f55fe2 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/tasks/httpapi_connection.yml @@ -0,0 +1,653 @@ +## Tests HTTTP Connection when a list of host are provided + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: "{{ aci_validate_certs | default(false) }}" + use_ssl: "{{ aci_use_ssl | default(true) }}" + use_proxy: "{{ aci_use_proxy | default(true) }}" + timeout: 5 + output_level: debug + +- name: Set vars with the randomly generated list of hosts for the task level operations + ansible.builtin.set_fact: + last_host_active: "{{ aci_hostname | generate_random_ips(5,5) }}" + second_host_active: "{{aci_hostname|generate_random_ips(2,5)}}" + no_host_active: "{{aci_hostname|generate_random_ips(0,5)}}" + +- name: Set the actual connection type specified in the inventory (this var is used at the end of this test) + ansible.builtin.set_fact: + old_connection: "{{ ansible_connection }}" + +- name: Set the connection to httpapi and set session key used in the inventory + ansible.builtin.set_fact: + ansible_user: "{{ aci_username }}" + ansible_password: "{{ aci_password }}" + ansible_connection: ansible.netcommon.httpapi + ansible_httpapi_session_key: {'admin': "{{ lookup('file', 'pki/admin.key') }}"} + ansible_httpapi_validate_certs: "{{ aci_validate_certs | default(false) }}" + ansible_httpapi_use_ssl: "{{ aci_use_ssl | default(true) }}" + ansible_httpapi_use_proxy: "{{ aci_use_proxy | default(true) }}" + ansible_httpapi_port: 443 + ansible_command_timeout: 5 + +- name: Run aci_aaa_user_certificate through the plugin + include_tasks: ../../../../../../integration/targets/aci_aaa_user_certificate/tasks/main.yml + +- name: Add user certificate to be used later in the test + cisco.aci.aci_aaa_user_certificate: + <<: *aci_info + aaa_user: "{{ aci_username }}" + name: admin + certificate: "{{ lookup('file', 'pki/admin.crt') }}" + state: present + +# XML operation, APIC HTTP Error and Connection reset upon changed parameter tests +- name: Add a tenant using an XML string (Check xml operations through plugin) + cisco.aci.aci_rest: + <<: *aci_info + path: api/mo/uni.xml + method: post + content: '<fvTenant name="Sales" descr="Sales departement"/>' + register: tenant_xml_plugin + +- name: Add an AP (with non existent tenant) + cisco.aci.aci_ap: + <<: *aci_info + tenant: ansible_test_non_existent + ap: ap + description: default ap + state: present + ignore_errors: true + register: ap_non_existent_tenant + +- name: Delete Tenant with the wrong username and password (Check that connection resets) + cisco.aci.aci_tenant: + <<: *aci_info + username: wrong_username + password: wrong_password + tenant: ansible_test + state: absent + ignore_errors: true + register: wrong_credentials + +- name: Set the username to null + ansible.builtin.set_fact: + ansible_user: + +- name: Delete Tenant with no username in the task or inventory (Check that username is set to the default value) + cisco.aci.aci_tenant: + host: "{{ aci_hostname }}" + password: "{{ aci_password }}" + validate_certs: "{{ aci_validate_certs | default(false) }}" + use_ssl: "{{ aci_use_ssl | default(true) }}" + use_proxy: "{{ aci_use_proxy | default(true) }}" + timeout: 5 + output_level: debug + tenant: ansible_test + state: absent + ignore_errors: true + register: no_username + +- name: Revert the username to its original value + ansible.builtin.set_fact: + ansible_user: "{{ aci_username }}" + +- name: Flatten the registered instances + ansible.builtin.set_fact: + ap_non_existent_tenant_flattened: "{{ ap_non_existent_tenant.httpapi_logs | flatten }}" + wrong_credentials_flattened: "{{ wrong_credentials.httpapi_logs | flatten }}" + no_username_flattened: "{{ no_username.httpapi_logs | flatten }}" + +- name: Verify XML operation and HTTP error returned by APIC + assert: + that: + - tenant_xml_plugin.status == 200 + - '"Received response from {{ aci_hostname }} for POST operation with HTTP: 400" in ap_non_existent_tenant_flattened' + - '"Re-setting connection due to change in the username" in wrong_credentials_flattened' + - '"Re-setting connection due to change in the password" in wrong_credentials_flattened' + - '"Connection to {{ aci_hostname }} has failed: HTTP Error 401: Unauthorized" in wrong_credentials_flattened' + - '"Establishing login for admin to {{ aci_hostname }}" in no_username_flattened' + +# Simulate HTTP 403 error test +- name: Delete Tenant with only password in the task (Check for 403) + cisco.aci.aci_tenant: + <<: *aci_info + host: "{{ last_host_active }}" + tenant: ansible_test + state: absent + register: op17_task_pwd_delete_tenant + +- name: Add Tenant with only password in the task (Check for 403) + cisco.aci.aci_tenant: + <<: *aci_info + host: "{{ last_host_active }}" + tenant: ansible_test + state: present + register: op17_task_pwd_add_tenant + +- name: logout to render the token invalid + cisco.aci.aci_rest: + <<: *aci_info + host: "{{ last_host_active }}" + path: /api/aaaLogout.json + method: post + rsp_subtree_preserve: true + content: | + { + "aaaUser": { + "attributes": { + "name": "{{ aci_username }}" + } + } + } + +- name: Add an AP with only password in the task (Ensure re-login on the same host) + cisco.aci.aci_ap: + <<: *aci_info + host: "{{ last_host_active }}" + tenant: ansible_test + ap: ap + description: default ap + state: present + register: op18_task_pwd_add_ap + +- name: Flatten the registered instances + ansible.builtin.set_fact: + op18_flattened_task_pwd_add_ap: "{{ op18_task_pwd_add_ap.httpapi_logs | flatten }}" + +- name: Verify forbidden error 403 + assert: + that: + - op17_task_pwd_add_tenant is changed + - op18_task_pwd_add_ap is changed + - '"Failed to receive response from {{ aci_hostname }} with HTTP Error 403: Forbidden" in op18_flattened_task_pwd_add_ap' + - '"Establishing login for {{ aci_username }} to {{ aci_hostname }}" in op18_flattened_task_pwd_add_ap' + - '"Connection to {{ aci_hostname }} was successful" in op18_flattened_task_pwd_add_ap' + +- name: reset connection to test other scenarios + meta: reset_connection + +# Precedence test +- name: Delete Tenant with password and private key in the task (private_key takes precedence) + cisco.aci.aci_tenant: + <<: *aci_info + private_key: "{{ lookup('file', 'pki/admin.key') }}" + tenant: ansible_test + state: absent + register: op1_task_private_key_delete_tenant + +- name: Add Tenant with password and private key in the task (Check for execution on the provided aci_hostname with no attempts at re-connection) + cisco.aci.aci_tenant: + <<: *aci_info + private_key: "{{ lookup('file', 'pki/admin.key') }}" + tenant: ansible_test + state: present + register: op1_task_private_key_add_tenant + +- name: Delete Tenant with only password in the task (password in the task takes precedence) + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_test + state: absent + register: op2_task_pwd_delete_tenant + +- name: Add Tenant with only password in the task (Check for execution on the provided aci_hostname with no attempts at re-connection) + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_test + state: present + register: op2_task_pwd_add_tenant + +- name: Delete Tenant with password and session key in the inventory (session_key takes precedence) + cisco.aci.aci_tenant: + output_level: debug + tenant: ansible_test + state: absent + register: op3_inventory_session_key_delete_tenant + +- name: Add Tenant with password and session key in the inventory (Check for execution on the provided aci_hostname with no attempts at re-connection) + cisco.aci.aci_tenant: + output_level: debug + tenant: ansible_test + state: present + register: op3_inventory_session_key_add_tenant + +- name: Remove session key used in the inventory + ansible.builtin.set_fact: + ansible_httpapi_session_key: + +- name: Delete Tenant with with only password in the inventory (check for authentication with the password in the inventory) + cisco.aci.aci_tenant: + output_level: debug + tenant: ansible_test + state: absent + register: op4_inventory_pwd_delete_tenant + +- name: Add Tenant with with only password in the inventory (Check for execution on the provided aci_hostname with no attempts at re-connection) + cisco.aci.aci_tenant: + output_level: debug + tenant: ansible_test + state: present + register: op4_inventory_pwd_add_tenant + +- name: Flatten the registered instances + ansible.builtin.set_fact: + op1_flattened_task_private_key_delete_tenant: "{{ op1_task_private_key_delete_tenant.httpapi_logs | flatten }}" + op1_flattened_task_private_key_add_tenant: "{{ op1_task_private_key_add_tenant.httpapi_logs | flatten }}" + op2_flattened_task_pwd_delete_tenant: "{{ op2_task_pwd_delete_tenant.httpapi_logs | flatten }}" + op2_flattened_task_pwd_add_tenant: "{{ op2_task_pwd_add_tenant.httpapi_logs | flatten }}" + op3_flattened_inventory_session_key_delete_tenant: "{{ op3_inventory_session_key_delete_tenant.httpapi_logs | flatten }}" + op3_flattened_inventory_session_key_add_tenant: "{{ op3_inventory_session_key_add_tenant.httpapi_logs | flatten }}" + op4_flattened_inventory_pwd_delete_tenant: "{{ op4_inventory_pwd_delete_tenant.httpapi_logs | flatten }}" + op4_flattened_inventory_pwd_add_tenant: "{{ op4_inventory_pwd_add_tenant.httpapi_logs | flatten }}" + +- name: Verify Precedence + assert: + that: + - '"Provided Hosts: [''{{ aci_hostname }}'']" in op1_flattened_task_private_key_delete_tenant' + - '"Initializing operation on {{ aci_hostname }}" in op1_flattened_task_private_key_delete_tenant' + - op1_task_private_key_add_tenant is changed + - '"Connection to {{ aci_hostname }} was successful" not in op1_flattened_task_private_key_add_tenant' + - op2_task_pwd_delete_tenant is changed + - '"Re-setting connection due to change from private/session key authentication to password authentication" in op2_flattened_task_pwd_delete_tenant' + - '"Establishing login for {{ aci_username }} to {{ aci_hostname }}" in op2_flattened_task_pwd_delete_tenant' + - '"Connection to {{ aci_hostname }} was successful" in op2_flattened_task_pwd_delete_tenant' + - op2_task_pwd_add_tenant is changed + - '"Connection to {{ aci_hostname }} was successful" not in op2_flattened_task_pwd_add_tenant' + - op3_inventory_session_key_delete_tenant is changed + - '"Connection to {{ aci_hostname }} was successful" not in op3_flattened_inventory_session_key_delete_tenant' + - op3_inventory_session_key_add_tenant is changed + - '"Connection to {{ aci_hostname }} was successful" not in op3_flattened_inventory_session_key_add_tenant' + - op4_inventory_pwd_delete_tenant is changed + - '"Re-setting connection due to change from private/session key authentication to password authentication" in op4_flattened_inventory_pwd_delete_tenant' + - '"Establishing login for {{ aci_username }} to {{ aci_hostname }}" in op4_flattened_inventory_pwd_delete_tenant' + - '"Connection to {{ aci_hostname }} was successful" in op4_flattened_inventory_pwd_delete_tenant' + - op4_inventory_pwd_add_tenant is changed + - '"Connection to {{ aci_hostname }} was successful" not in op4_flattened_inventory_pwd_add_tenant' + +- name: reset connection to test other scenarios + meta: reset_connection + +# Switching of hosts test with the password in the task +- name: Delete Tenant with only password in the task (Check for successful operation on the last host) + cisco.aci.aci_tenant: + <<: *aci_info + host: "{{ last_host_active }}" + tenant: ansible_test + state: absent + register: op5_task_pwd_delete_tenant + +- name: Add Tenant with only password in the task (Check for execution on the provided aci_hostname with no attempts at re-connection) + cisco.aci.aci_tenant: + <<: *aci_info + host: "{{ last_host_active }}" + tenant: ansible_test + state: present + register: op5_task_pwd_add_tenant + +- name: Flatten the registered instances + ansible.builtin.set_fact: + op5_flattened_task_pwd_delete_tenant: "{{ op5_task_pwd_delete_tenant.httpapi_logs | flatten }}" + op5_flattened_task_pwd_add_tenant: "{{ op5_task_pwd_add_tenant.httpapi_logs | flatten }}" + +- name: Verify switching of hosts with the password in the task + assert: + that: + - op5_task_pwd_delete_tenant is changed + - op5_flattened_task_pwd_delete_tenant | regex_search('Switching host from [0-9]+(?:\.[0-9]+){3} to {{ aci_hostname }}') is not none + - '"Establishing login for {{ aci_username }} to {{ aci_hostname }}" in op5_flattened_task_pwd_delete_tenant' + - '"Connection to {{ aci_hostname }} was successful" in op5_flattened_task_pwd_delete_tenant' + - op5_task_pwd_add_tenant is changed + - '"Connection to {{ aci_hostname }} was successful" not in op5_flattened_task_pwd_add_tenant' + +# Continuing on the connected host test with the password in the task +- name: Delete Tenant with only password in the task + cisco.aci.aci_tenant: + <<: *aci_info + host: "{{ second_host_active }}" + tenant: ansible_test + state: absent + register: op6_task_pwd_delete_tenant + +- name: Add Tenant with only password in the task (Check for execution on the provided aci_hostname with no attempts at re-connection) + cisco.aci.aci_tenant: + <<: *aci_info + host: "{{ second_host_active }}" + tenant: ansible_test + state: present + register: op6_task_pwd_add_tenant + +- name: Flatten the registered instances + ansible.builtin.set_fact: + op6_flattened_task_pwd_delete_tenant: "{{ op6_task_pwd_delete_tenant.httpapi_logs | flatten }}" + op6_flattened_task_pwd_add_tenant: "{{ op6_task_pwd_add_tenant.httpapi_logs | flatten }}" + +- name: Verify continuation of the operations on the connected host with the password in the task + assert: + that: + - op6_task_pwd_delete_tenant is changed + - '"Connected host {{ aci_hostname }} found in the provided hosts. Continuing with it." in op6_flattened_task_pwd_delete_tenant' + - op6_task_pwd_add_tenant is changed + - '"Connection to {{ aci_hostname }} was successful" not in op6_flattened_task_pwd_add_tenant' + +# Change of hosts and no hosts active test with the password in the task +- name: Delete Tenant with only password in the task (Check for failed operation) + cisco.aci.aci_tenant: + <<: *aci_info + host: "{{ no_host_active }}" + tenant: ansible_test + state: absent + register: op7_task_pwd_delete_tenant + ignore_errors: True + +- name: Add Tenant with only password in the task (Check the reset of the provided list of hosts) + cisco.aci.aci_tenant: + <<: *aci_info + host: "{{ second_host_active }}" + tenant: ansible_test + state: present + register: op7_task_pwd_add_tenant + +- name: Verify failure when no hosts are active + assert: + that: + - op7_task_pwd_delete_tenant.error.text | regex_search('No hosts left in the cluster to continue operation! Error on final host [0-9]+(?:\.[0-9]+){3}') is not none + - op7_task_pwd_add_tenant is not changed + +# Switching of hosts test with the the inventory password +- name: Set list of hosts in the inventory with the last host as active + ansible.builtin.set_fact: + ansible_host: "{{aci_hostname|generate_random_ips(5,5)}}" + +- name: Delete Tenant with only password in the inventory (Check for successful operation on the last host) + cisco.aci.aci_tenant: + output_level: debug + tenant: ansible_test + state: absent + register: op8_inventory_pwd_delete_tenant + +- name: Add Tenant with only password in the inventory (Check for execution on the provided aci_hostname with no attempts at re-connection) + cisco.aci.aci_tenant: + output_level: debug + tenant: ansible_test + state: present + register: op8_inventory_pwd_add_tenant + +- name: Flatten the registered instances + ansible.builtin.set_fact: + op8_flattened_inventory_pwd_delete_tenant: "{{ op8_inventory_pwd_delete_tenant.httpapi_logs | flatten }}" + op8_flattened_inventory_pwd_add_tenant: "{{ op8_inventory_pwd_add_tenant.httpapi_logs | flatten }}" + +- name: Verify switching of hosts with the password in the inventory + assert: + that: + - op8_inventory_pwd_delete_tenant is changed + - op8_flattened_inventory_pwd_delete_tenant | regex_search('Switching host from [0-9]+(?:\.[0-9]+){3} to {{ aci_hostname }}') is not none + - '"Establishing login for {{ aci_username }} to {{ aci_hostname }}" in op8_flattened_inventory_pwd_delete_tenant' + - '"Connection to {{ aci_hostname }} was successful" in op8_flattened_inventory_pwd_delete_tenant' + - op8_inventory_pwd_add_tenant is changed + - '"Connection to {{ aci_hostname }} was successful" not in op8_flattened_inventory_pwd_add_tenant' + +# Continuing on the connected host test with the inventory password +- name: Set list of hosts in the inventory with the second host as active + ansible.builtin.set_fact: + ansible_host: "{{aci_hostname|generate_random_ips(2,5)}}" + +- name: Delete Tenant with only password in the inventory (Check for execution on the previously connected host) + cisco.aci.aci_tenant: + output_level: debug + tenant: ansible_test + state: absent + register: op9_inventory_pwd_delete_tenant + +- name: Add Tenant with only password in the inventory (Check for execution on the provided aci_hostname with no attempts at re-connection) + cisco.aci.aci_tenant: + output_level: debug + tenant: ansible_test + state: present + register: op9_inventory_pwd_add_tenant + +- name: Flatten the registered instances + ansible.builtin.set_fact: + op9_flattened_inventory_pwd_delete_tenant: "{{ op9_inventory_pwd_delete_tenant.httpapi_logs | flatten }}" + op9_flattened_inventory_pwd_add_tenant: "{{ op9_inventory_pwd_add_tenant.httpapi_logs | flatten }}" + +- name: Verify switching of hosts with the password in the inventory + assert: + that: + - op9_inventory_pwd_delete_tenant is changed + - op9_flattened_inventory_pwd_delete_tenant | regex_search('Switching host from [0-9]+(?:\.[0-9]+){3} to {{ aci_hostname }}') is not none + - '"Establishing login for {{ aci_username }} to {{ aci_hostname }}" in op9_flattened_inventory_pwd_delete_tenant' + - '"Connection to {{ aci_hostname }} was successful" in op9_flattened_inventory_pwd_delete_tenant' + - op9_inventory_pwd_add_tenant is changed + - '"Connection to {{ aci_hostname }} was successful" not in op9_flattened_inventory_pwd_add_tenant' + +# Change of hosts and no hosts active test with the inventory password +- name: Set list of hosts in the inventory with no active hosts + ansible.builtin.set_fact: + ansible_host: "{{aci_hostname|generate_random_ips(0,5)}}" + +- name: Delete Tenant with only password in the inventory (Check for failed operation) + cisco.aci.aci_tenant: + output_level: debug + tenant: ansible_test + state: absent + register: op10_inventory_pwd_delete_tenant + ignore_errors: True + +- name: Verify failure when no hosts are active in the inventory + assert: + that: + - op10_inventory_pwd_delete_tenant.error.text | regex_search('No hosts left in the cluster to continue operation! Error on final host [0-9]+(?:\.[0-9]+){3}') is not none + +# Switching of hosts test with the private key in the task +- name: Delete Tenant with only private key in the task (Check for successful operation on the last host) + cisco.aci.aci_tenant: + <<: *aci_info + host: "{{ last_host_active }}" + private_key: "{{ lookup('file', 'pki/admin.key') }}" + tenant: ansible_test + state: absent + register: op11_task_private_key_delete_tenant + +- name: Add Tenant with only private key in the task (Check for execution on the provided aci_hostname with no attempts at re-connection) + cisco.aci.aci_tenant: + <<: *aci_info + host: "{{ last_host_active }}" + private_key: "{{ lookup('file', 'pki/admin.key') }}" + tenant: ansible_test + state: present + register: op11_task_private_key_add_tenant + +- name: Flatten the registered instances + ansible.builtin.set_fact: + op11_flattened_task_private_key_delete_tenant: "{{ op11_task_private_key_delete_tenant.httpapi_logs | flatten }}" + op11_flattened_task_private_key_add_tenant: "{{ op11_task_private_key_add_tenant.httpapi_logs | flatten }}" + +- name: Verify switching of hosts with the private key in the task + assert: + that: + - op11_task_private_key_delete_tenant is changed + - op11_flattened_task_private_key_delete_tenant | regex_search('Switching host from [0-9]+(?:\.[0-9]+){3} to {{ aci_hostname }}') is not none + - '"Establishing login for {{ aci_username }} to {{ aci_hostname }}" not in op11_flattened_task_private_key_delete_tenant' + - '"Connection to {{ aci_hostname }} was successful" not in op11_flattened_task_private_key_delete_tenant' + - op11_task_private_key_add_tenant is changed + - '"Connection to {{ aci_hostname }} was successful" not in op11_flattened_task_private_key_add_tenant' + +# Continuing on the connected host test with the private key in the task +- name: Delete Tenant with only private key in the task (Check for execution on the previously connected host) + cisco.aci.aci_tenant: + <<: *aci_info + host: "{{ second_host_active }}" + private_key: "{{ lookup('file', 'pki/admin.key') }}" + tenant: ansible_test + state: absent + register: op12_task_private_key_delete_tenant + +- name: Add Tenant with only private key in the task (Check for execution on the provided aci_hostname with no attempts at re-connection) + cisco.aci.aci_tenant: + <<: *aci_info + host: "{{ second_host_active }}" + private_key: "{{ lookup('file', 'pki/admin.key') }}" + tenant: ansible_test + state: present + register: op12_task_private_key_add_tenant + +- name: Flatten the registered instances + ansible.builtin.set_fact: + op12_flattened_task_private_key_delete_tenant: "{{ op12_task_private_key_delete_tenant.httpapi_logs | flatten }}" + op12_flattened_task_private_key_add_tenant: "{{ op12_task_private_key_add_tenant.httpapi_logs | flatten }}" + +- name: Verify continuation of the operations on the connected host with the password in the task + assert: + that: + - op12_task_private_key_delete_tenant is changed + - '"Connected host {{ aci_hostname }} found in the provided hosts. Continuing with it." in op12_flattened_task_private_key_delete_tenant' + - op12_task_private_key_add_tenant is changed + - '"Connection to {{ aci_hostname }} was successful" not in op12_flattened_task_private_key_add_tenant' + +# Change of hosts and no hosts active test with the private key in the task +- name: Delete Tenant with only private key in the task (Check for failed operation) + cisco.aci.aci_tenant: + <<: *aci_info + host: "{{ no_host_active }}" + private_key: "{{ lookup('file', 'pki/admin.key') }}" + tenant: ansible_test + state: absent + register: op13_task_private_key_delete_tenant + ignore_errors: True + +- name: Add Tenant with only private key in the task (Check the reset of the provided list of hosts) + cisco.aci.aci_tenant: + <<: *aci_info + host: "{{ second_host_active }}" + private_key: "{{ lookup('file', 'pki/admin.key') }}" + tenant: ansible_test + state: present + register: op13_task_private_key_add_tenant + +- name: Verify failure when no hosts are active in the task + assert: + that: + - op13_task_private_key_delete_tenant.error.text | regex_search('No hosts left in the cluster to continue operation! Error on final host [0-9]+(?:\.[0-9]+){3}') is not none + - op13_task_private_key_add_tenant is not changed + +# Switching of hosts test with the the inventory session key +- name: Set list of hosts in the inventory with the last host as active + ansible.builtin.set_fact: + ansible_host: "{{aci_hostname|generate_random_ips(5,5)}}" + ansible_httpapi_session_key: {'admin': "{{ lookup('file', 'pki/admin.key') }}"} + +- name: Delete Tenant with session key in the inventory (Check for successful operation on the last host) + cisco.aci.aci_tenant: + output_level: debug + tenant: ansible_test + state: absent + register: op14_inventory_session_key_delete_tenant + +- name: Add Tenant with session key in the inventory (Check for execution on the provided aci_hostname with no attempts at re-connection) + cisco.aci.aci_tenant: + output_level: debug + tenant: ansible_test + state: present + register: op14_inventory_session_key_add_tenant + +- name: Flatten the registered instances + ansible.builtin.set_fact: + op14_flattened_inventory_session_key_delete_tenant: "{{ op14_inventory_session_key_delete_tenant.httpapi_logs | flatten }}" + op14_flattened_inventory_session_key_add_tenant: "{{ op14_inventory_session_key_add_tenant.httpapi_logs | flatten }}" + +- name: Verify switching of hosts with the session key in the inventory + assert: + that: + - op14_inventory_session_key_delete_tenant is changed + - op14_flattened_inventory_session_key_delete_tenant | regex_search('Switching host from [0-9]+(?:\.[0-9]+){3} to {{ aci_hostname }}') is not none + - '"Establishing login for {{ aci_username }} to {{ aci_hostname }}" not in op14_flattened_inventory_session_key_delete_tenant' + - '"Connection to {{ aci_hostname }} was successful" not in op14_flattened_inventory_session_key_delete_tenant' + - op14_inventory_session_key_add_tenant is changed + - '"Connection to {{ aci_hostname }} was successful" not in op14_flattened_inventory_session_key_add_tenant' + +# Continuing on the connected host test with the inventory session key +- name: Set list of hosts in the inventory with the second host as active + ansible.builtin.set_fact: + ansible_host: "{{aci_hostname|generate_random_ips(2,5)}}" + +- name: Delete Tenant with session key in the inventory (Check for execution on the previously connected host) + cisco.aci.aci_tenant: + output_level: debug + tenant: ansible_test + state: absent + register: op15_inventory_session_key_delete_tenant + +- name: Add Tenant with session key in the inventory (Check for execution on the provided aci_hostname with no attempts at re-connection) + cisco.aci.aci_tenant: + output_level: debug + tenant: ansible_test + state: present + register: op15_inventory_session_key_add_tenant + +- name: Flatten the registered instances + ansible.builtin.set_fact: + op15_flattened_inventory_session_key_delete_tenant: "{{ op15_inventory_session_key_delete_tenant.httpapi_logs | flatten }}" + op15_flattened_inventory_session_key_add_tenant: "{{ op15_inventory_session_key_add_tenant.httpapi_logs | flatten }}" + +- name: Verify switching of hosts with the session key in the inventory + assert: + that: + - op15_inventory_session_key_delete_tenant is changed + - op15_flattened_inventory_session_key_delete_tenant | regex_search('Switching host from [0-9]+(?:\.[0-9]+){3} to {{ aci_hostname }}') is not none + - '"Establishing login for {{ aci_username }} to {{ aci_hostname }}" not in op15_flattened_inventory_session_key_delete_tenant' + - '"Connection to {{ aci_hostname }} was successful" not in op15_flattened_inventory_session_key_delete_tenant' + - op15_inventory_session_key_add_tenant is changed + - '"Connection to {{ aci_hostname }} was successful" not in op15_flattened_inventory_session_key_add_tenant' + +# Change of hosts and no hosts active test with the inventory session key +- name: Set list of hosts in the inventory with no active hosts + ansible.builtin.set_fact: + ansible_host: "{{aci_hostname|generate_random_ips(0,5)}}" + +- name: Delete Tenant with session key in the inventory (Check for failed operation) + cisco.aci.aci_tenant: + output_level: debug + tenant: ansible_test + state: absent + register: op16_inventory_session_key_delete_tenant + ignore_errors: True + +- name: Verify failure when no hosts are active in the inventory + assert: + that: + - op16_inventory_session_key_delete_tenant.error.text | regex_search('No hosts left in the cluster to continue operation! Error on final host [0-9]+(?:\.[0-9]+){3}') is not none + +# Clean up Environment +- name: Delete a tenant using an XML string + cisco.aci.aci_rest: + <<: *aci_info + path: api/mo/uni/tn-[Sales].xml + method: delete + content: '<fvTenant name="Sales" descr="Sales departement"/>' + +- name: Remove user certificate + cisco.aci.aci_aaa_user_certificate: + <<: *aci_info + aaa_user: "{{ aci_username }}" + name: admin + certificate: "{{ lookup('file', 'pki/admin.crt') }}" + state: absent + +- name: Delete Tenant + cisco.aci.aci_tenant: + <<: *aci_info + port: 443 + tenant: ansible_test + state: absent + +- name: Cleanup facts to continue operation using the inventory file + ansible.builtin.set_fact: + ansible_host: "{{ aci_hostname }}" + ansible_connection: "{{ old_connection }}" + ansible_httpapi_session_key: diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/tasks/main.yml index f3eba556e..b8a7a310f 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/tasks/main.yml @@ -9,23 +9,26 @@ msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined +- include_tasks: httpapi_connection.yml + tags: httpapi_connection + - name: Delete old log files to clean test directory file: path: "{{ item }}" state: absent with_items: - - "{{ ansible_host }}_cm_add_tenant.json" - - "{{ ansible_host }}_nm_add_tenant.json" - - "{{ ansible_host }}_cm_add_tenant_again.json" - - "{{ ansible_host }}_nm_add_tenant_again.json" - - "{{ ansible_host }}_cm_add_tenant_descr.json" - - "{{ ansible_host }}_nm_add_tenant_descr.json" - - "{{ ansible_host }}_cm_add_tenant_descr_again.json" - - "{{ ansible_host }}_nm_add_tenant_descr_again.json" - - "{{ ansible_host }}_cm_remove_tenant.json" - - "{{ ansible_host }}_nm_remove_tenant.json" - - "{{ ansible_host }}_cm_remove_tenant_again.json" - - "{{ ansible_host }}_nm_remove_tenant_again.json" + - "{{ aci_hostname }}_cm_add_tenant.json" + - "{{ aci_hostname }}_nm_add_tenant.json" + - "{{ aci_hostname }}_cm_add_tenant_again.json" + - "{{ aci_hostname }}_nm_add_tenant_again.json" + - "{{ aci_hostname }}_cm_add_tenant_descr.json" + - "{{ aci_hostname }}_nm_add_tenant_descr.json" + - "{{ aci_hostname }}_cm_add_tenant_descr_again.json" + - "{{ aci_hostname }}_nm_add_tenant_descr_again.json" + - "{{ aci_hostname }}_cm_remove_tenant.json" + - "{{ aci_hostname }}_nm_remove_tenant.json" + - "{{ aci_hostname }}_cm_remove_tenant_again.json" + - "{{ aci_hostname }}_nm_remove_tenant_again.json" # CLEAN ENVIRONMENT - name: Remove tenant @@ -40,7 +43,6 @@ tenant: ansible_test state: absent - # ADD TENANT - name: Add tenant (check_mode) cisco.aci.aci_tenant: &tenant_present @@ -56,44 +58,44 @@ annotation: ansible_test owner_key: ansible_key owner_tag: ansible_tag - output_path: "{{ ansible_host }}_cm_add_tenant.json" + output_path: "{{ aci_hostname }}_cm_add_tenant.json" check_mode: true register: cm_add_tenant - name: Dump content of files debug: - msg: "{{ lookup('file', ansible_host +'_cm_add_tenant.json')}}" + msg: "{{ lookup('file', aci_hostname +'_cm_add_tenant.json')}}" - name: Add tenant (normal mode) cisco.aci.aci_tenant: <<: *tenant_present - output_path: "{{ ansible_host }}_nm_add_tenant.json" + output_path: "{{ aci_hostname }}_nm_add_tenant.json" register: nm_add_tenant - name: Add tenant again (check_mode) cisco.aci.aci_tenant: <<: *tenant_present - output_path: "{{ ansible_host }}_cm_add_tenant_again.json" + output_path: "{{ aci_hostname }}_cm_add_tenant_again.json" check_mode: true register: cm_add_tenant_again - name: Add tenant again (normal mode) cisco.aci.aci_tenant: <<: *tenant_present - output_path: "{{ ansible_host }}_nm_add_tenant_again.json" + output_path: "{{ aci_hostname }}_nm_add_tenant_again.json" register: nm_add_tenant_again - name: Dump content of files debug: - msg: "{{ lookup('file', ansible_host + '_cm_add_tenant.json')}}" + msg: "{{ lookup('file', aci_hostname + '_cm_add_tenant.json')}}" - name: Store file content on variables for create object set_fact: - fc_cm_add_tenant: "{{ lookup('file', ansible_host + '_cm_add_tenant.json') | from_json }}" - fc_nm_add_tenant: "{{ lookup('file', ansible_host + '_nm_add_tenant.json') | from_json }}" - fc_cm_add_tenant_again: "{{ lookup('file', ansible_host + '_cm_add_tenant_again.json') }}" - fc_nm_add_tenant_again: "{{ lookup('file', ansible_host + '_nm_add_tenant_again.json') }}" + fc_cm_add_tenant: "{{ lookup('file', aci_hostname + '_cm_add_tenant.json') | from_json }}" + fc_nm_add_tenant: "{{ lookup('file', aci_hostname + '_nm_add_tenant.json') | from_json }}" + fc_cm_add_tenant_again: "{{ lookup('file', aci_hostname + '_cm_add_tenant_again.json') }}" + fc_nm_add_tenant_again: "{{ lookup('file', aci_hostname + '_nm_add_tenant_again.json') }}" - name: Log file content verification for create object assert: @@ -119,7 +121,6 @@ - nm_add_tenant.current[0].fvTenant.attributes.ownerTag == 'ansible_tag' - cm_add_tenant.proposed.fvTenant.attributes.ownerTag == 'ansible_tag' - # CHANGE TENANT - name: Change description and annotation/owner_tag/owner_key of tenant (check_mode) cisco.aci.aci_tenant: @@ -128,7 +129,7 @@ annotation: ansible_test_changed owner_key: ansible_key_changed owner_tag: ansible_tag_changed - output_path: "{{ ansible_host }}_cm_add_tenant_descr.json" + output_path: "{{ aci_hostname }}_cm_add_tenant_descr.json" check_mode: true register: cm_add_tenant_descr @@ -139,7 +140,7 @@ annotation: ansible_test_changed owner_key: ansible_key_changed owner_tag: ansible_tag_changed - output_path: "{{ ansible_host }}_nm_add_tenant_descr.json" + output_path: "{{ aci_hostname }}_nm_add_tenant_descr.json" register: nm_add_tenant_descr - name: Change description and annotation/owner_tag/owner_key of tenant again (check_mode) @@ -149,7 +150,7 @@ annotation: ansible_test_changed owner_key: ansible_key_changed owner_tag: ansible_tag_changed - output_path: "{{ ansible_host }}_cm_add_tenant_descr_again.json" + output_path: "{{ aci_hostname }}_cm_add_tenant_descr_again.json" check_mode: true register: cm_add_tenant_descr_again @@ -160,15 +161,15 @@ annotation: ansible_test_changed owner_key: ansible_key_changed owner_tag: ansible_tag_changed - output_path: "{{ ansible_host }}_nm_add_tenant_descr_again.json" + output_path: "{{ aci_hostname }}_nm_add_tenant_descr_again.json" register: nm_add_tenant_descr_again - name: Store file content on variables for update object set_fact: - fc_cm_add_tenant_descr: "{{ lookup('file', ansible_host + '_cm_add_tenant_descr.json') | from_json }}" - fc_nm_add_tenant_descr: "{{ lookup('file', ansible_host + '_nm_add_tenant_descr.json') | from_json }}" - fc_cm_add_tenant_descr_again: "{{ lookup('file', ansible_host + '_cm_add_tenant_descr_again.json') }}" - fc_nm_add_tenant_descr_again: "{{ lookup('file', ansible_host + '_nm_add_tenant_descr_again.json') }}" + fc_cm_add_tenant_descr: "{{ lookup('file', aci_hostname + '_cm_add_tenant_descr.json') | from_json }}" + fc_nm_add_tenant_descr: "{{ lookup('file', aci_hostname + '_nm_add_tenant_descr.json') | from_json }}" + fc_cm_add_tenant_descr_again: "{{ lookup('file', aci_hostname + '_cm_add_tenant_descr_again.json') }}" + fc_nm_add_tenant_descr_again: "{{ lookup('file', aci_hostname + '_nm_add_tenant_descr_again.json') }}" - name: Log file content verification for update object assert: @@ -295,35 +296,35 @@ - name: Remove tenant (check_mode) cisco.aci.aci_tenant: <<: *tenant_absent - output_path: "{{ ansible_host }}_cm_remove_tenant.json" + output_path: "{{ aci_hostname }}_cm_remove_tenant.json" check_mode: true register: cm_remove_tenant - name: Remove tenant (normal mode) cisco.aci.aci_tenant: <<: *tenant_absent - output_path: "{{ ansible_host }}_nm_remove_tenant.json" + output_path: "{{ aci_hostname }}_nm_remove_tenant.json" register: nm_remove_tenant - name: Remove tenant again (check_mode) cisco.aci.aci_tenant: <<: *tenant_absent - output_path: "{{ ansible_host }}_cm_remove_tenant_again.json" + output_path: "{{ aci_hostname }}_cm_remove_tenant_again.json" check_mode: true register: cm_remove_tenant_again - name: Remove tenant again (normal mode) cisco.aci.aci_tenant: <<: *tenant_absent - output_path: "{{ ansible_host }}_nm_remove_tenant_again.json" + output_path: "{{ aci_hostname }}_nm_remove_tenant_again.json" register: nm_remove_tenant_again - name: Store file content on variables for delete object set_fact: - fc_cm_remove_tenant: "{{ lookup('file', ansible_host + '_cm_remove_tenant.json') | from_json }}" - fc_nm_remove_tenant: "{{ lookup('file', ansible_host + '_nm_remove_tenant.json') | from_json }}" - fc_cm_remove_tenant_again: "{{ lookup('file', ansible_host + '_cm_remove_tenant_again.json') }}" - fc_nm_remove_tenant_again: "{{ lookup('file', ansible_host + '_nm_remove_tenant_again.json') }}" + fc_cm_remove_tenant: "{{ lookup('file', aci_hostname + '_cm_remove_tenant.json') | from_json }}" + fc_nm_remove_tenant: "{{ lookup('file', aci_hostname + '_nm_remove_tenant.json') | from_json }}" + fc_cm_remove_tenant_again: "{{ lookup('file', aci_hostname + '_cm_remove_tenant_again.json') }}" + fc_nm_remove_tenant_again: "{{ lookup('file', aci_hostname + '_nm_remove_tenant_again.json') }}" - name: Log file content verification for delete object assert: diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_action_rule_profile/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_action_rule_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_action_rule_profile/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_action_rule_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_action_rule_profile/tasks/main.yml new file mode 100644 index 000000000..b993b0e33 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_action_rule_profile/tasks/main.yml @@ -0,0 +1,146 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Clean Environment + - name: create tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_test + state: present + + - name: Ensure first action rule profile does not exist + aci_tenant_action_rule_profile: &aci_tenant_action_rule_profile_absent + <<: *aci_tenant_present + name: anstest + description: test for action rule profile + state: absent + + - name: Ensure second action rule profile does not exist + aci_tenant_action_rule_profile: &aci_tenant_action_rule_profile_2_absent + <<: *aci_tenant_present + name: anstest_2 + state: absent + + - name: Create first action rule profile (check_mode) + aci_tenant_action_rule_profile: &aci_tenant_action_rule_profile_present + <<: *aci_tenant_action_rule_profile_absent + state: present + check_mode: true + register: cm_add_tenant_action_rule_profile_1 + + - name: Create first action rule profile (normal_mode) + aci_tenant_action_rule_profile: + <<: *aci_tenant_action_rule_profile_present + register: nm_add_tenant_action_rule_profile_1 + + - name: Create first action rule profile again - testing idempotency + aci_tenant_action_rule_profile: + <<: *aci_tenant_action_rule_profile_present + register: idempotency_add_tenant_action_rule_profile_1 + + - name: Create second action rule profile + aci_tenant_action_rule_profile: &aci_tenant_action_rule_profile_2_present + <<: *aci_tenant_action_rule_profile_2_absent + state: present + register: nm_add_tenant_action_rule_profile_2 + + - name: Asserts for creation tasks + assert: + that: + - cm_add_tenant_action_rule_profile_1 is changed + - cm_add_tenant_action_rule_profile_1.previous == [] + - cm_add_tenant_action_rule_profile_1.current == [] + - nm_add_tenant_action_rule_profile_1 is changed + - nm_add_tenant_action_rule_profile_1.current.0.rtctrlAttrP.attributes.name == "anstest" + - idempotency_add_tenant_action_rule_profile_1 is not changed + - nm_add_tenant_action_rule_profile_2 is changed + - nm_add_tenant_action_rule_profile_2.current.0.rtctrlAttrP.attributes.name == "anstest_2" + + - name: Query all action rule profiles + aci_tenant_action_rule_profile: + <<: *aci_info + state: query + register: query_all_tenant_action_rule_profile + + - name: Query first action rule profile + aci_tenant_action_rule_profile: + <<: *aci_tenant_action_rule_profile_present + state: query + register: query_first_tenant_action_rule_profile + + - name: Asserts for query tasks + assert: + that: + - query_all_tenant_action_rule_profile is not changed + - query_all_tenant_action_rule_profile.current | length >= 2 + - '"class/rtctrlAttrP.json" in query_all_tenant_action_rule_profile.url' + - query_first_tenant_action_rule_profile is not changed + - query_first_tenant_action_rule_profile.current.0.rtctrlAttrP.attributes.name == "anstest" + + - name: Delete first action rule profile (check_mode) + aci_tenant_action_rule_profile: + <<: *aci_tenant_action_rule_profile_present + state: absent + check_mode: true + register: cm_delete_tenant_action_rule_profile_1 + + - name: Delete first action rule profile (normal_mode) + aci_tenant_action_rule_profile: + <<: *aci_tenant_action_rule_profile_present + state: absent + register: nm_delete_tenant_action_rule_profile_1 + + - name: Delete first action rule profile again - testing idempotency + aci_tenant_action_rule_profile: + <<: *aci_tenant_action_rule_profile_present + state: absent + register: idempotency_delete_tenant_action_rule_profile_1 + + - name: Delete second action rule profile (normal_mode) + aci_tenant_action_rule_profile: + <<: *aci_tenant_action_rule_profile_2_present + state: absent + register: nm_delete_tenant_action_rule_profile_2 + + - name: Asserts for deletion tasks + assert: + that: + - cm_delete_tenant_action_rule_profile_1 is changed + - cm_delete_tenant_action_rule_profile_1.proposed == {} + - nm_delete_tenant_action_rule_profile_1 is changed + - nm_delete_tenant_action_rule_profile_1.previous != [] + - nm_delete_tenant_action_rule_profile_1.current == [] + - idempotency_delete_tenant_action_rule_profile_1 is not changed + - idempotency_delete_tenant_action_rule_profile_1.previous == [] + - nm_delete_tenant_action_rule_profile_2 is changed + - nm_delete_tenant_action_rule_profile_2.previous != [] + - nm_delete_tenant_action_rule_profile_2.current == [] + + - name: Delete tenant - clean up the environment + aci_tenant: + <<: *aci_tenant_present + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_ep_retention_policy/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_ep_retention_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_ep_retention_policy/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_ep_retention_policy/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_ep_retention_policy/tasks/main.yml new file mode 100644 index 000000000..96ba34077 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_ep_retention_policy/tasks/main.yml @@ -0,0 +1,214 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Clean Environment + - name: create tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_test + state: present + + - name: Ensure first EP retention protocol policy does not exist + aci_tenant_ep_retention_policy: &aci_tenant_ep_retention_policy_absent + <<: *aci_tenant_present + name: ep_policy_anstest + description: test for EP retention protocol policy + bounce_age: 300 + bounce_trigger: flood + hold_interval: 600 + local_ep_interval: 1800 + remote_ep_interval: 600 + move_frequency: 512 + state: absent + + - name: Ensure second EP retention protocol policy does not exist + aci_tenant_ep_retention_policy: &aci_tenant_ep_retention_policy_2_absent + <<: *aci_tenant_present + name: ep_policy_anstest_2 + bounce_age: 0 + local_ep_interval: 0 + remote_ep_interval: 0 + move_frequency: 0 + state: absent + + - name: Create first EP retention protocol policy (check_mode) + aci_tenant_ep_retention_policy: &aci_tenant_ep_retention_policy_present + <<: *aci_tenant_ep_retention_policy_absent + state: present + check_mode: true + register: cm_add_tenant_ep_retention_policy_1 + + - name: Create first EP retention protocol policy (normal_mode) + aci_tenant_ep_retention_policy: + <<: *aci_tenant_ep_retention_policy_present + register: nm_add_tenant_ep_retention_policy_1 + + - name: Create first EP retention protocol policy again - testing idempotency + aci_tenant_ep_retention_policy: + <<: *aci_tenant_ep_retention_policy_present + register: idempotency_add_tenant_ep_retention_policy_1 + + - name: Create second EP retention protocol policy + aci_tenant_ep_retention_policy: &aci_tenant_ep_retention_policy_2_present + <<: *aci_tenant_ep_retention_policy_2_absent + state: present + register: nm_add_tenant_ep_retention_policy_2 + + - name: Modify EP retention protocol policy bounce age - testing failure message + aci_tenant_ep_retention_policy: + <<: *aci_tenant_ep_retention_policy_present + bounce_age: 100 + ignore_errors: true + register: Modify_tenant_ep_retention_policy_bounce_age + + - name: Modify EP retention protocol policy hold interval - testing failure message + aci_tenant_ep_retention_policy: + <<: *aci_tenant_ep_retention_policy_present + hold_interval: 4 + ignore_errors: true + register: Modify_tenant_ep_retention_policy_hold_interval + + - name: Modify EP retention protocol policy move frequency - testing failure message + aci_tenant_ep_retention_policy: + <<: *aci_tenant_ep_retention_policy_present + move_frequency: 65540 + ignore_errors: true + register: Modify_tenant_ep_retention_policy_move_frequency + + - name: Modify EP retention protocol policy local ep interval - testing failure message + aci_tenant_ep_retention_policy: + <<: *aci_tenant_ep_retention_policy_present + local_ep_interval: 119 + ignore_errors: true + register: Modify_tenant_ep_retention_policy_local_ep_interval + + - name: Modify EP retention protocol policy remote ep interval - testing failure message + aci_tenant_ep_retention_policy: + <<: *aci_tenant_ep_retention_policy_present + remote_ep_interval: 119 + ignore_errors: true + register: Modify_tenant_ep_retention_policy_remote_ep_interval + + - name: Asserts for creation tasks + assert: + that: + - cm_add_tenant_ep_retention_policy_1 is changed + - cm_add_tenant_ep_retention_policy_1.previous == [] + - cm_add_tenant_ep_retention_policy_1.current == [] + - nm_add_tenant_ep_retention_policy_1 is changed + - nm_add_tenant_ep_retention_policy_1.current.0.fvEpRetPol.attributes.name == "ep_policy_anstest" + - nm_add_tenant_ep_retention_policy_1.current.0.fvEpRetPol.attributes.bounceAgeIntvl == "300" + - nm_add_tenant_ep_retention_policy_1.current.0.fvEpRetPol.attributes.bounceTrig == "rarp-flood" + - nm_add_tenant_ep_retention_policy_1.current.0.fvEpRetPol.attributes.holdIntvl == "600" + - nm_add_tenant_ep_retention_policy_1.current.0.fvEpRetPol.attributes.localEpAgeIntvl == "1800" + - nm_add_tenant_ep_retention_policy_1.current.0.fvEpRetPol.attributes.moveFreq == "512" + - nm_add_tenant_ep_retention_policy_1.current.0.fvEpRetPol.attributes.remoteEpAgeIntvl == "600" + - idempotency_add_tenant_ep_retention_policy_1 is not changed + - nm_add_tenant_ep_retention_policy_2 is changed + - nm_add_tenant_ep_retention_policy_2.current.0.fvEpRetPol.attributes.bounceAgeIntvl == "infinite" + - nm_add_tenant_ep_retention_policy_2.current.0.fvEpRetPol.attributes.bounceTrig == "protocol" + - nm_add_tenant_ep_retention_policy_2.current.0.fvEpRetPol.attributes.holdIntvl == "300" + - nm_add_tenant_ep_retention_policy_2.current.0.fvEpRetPol.attributes.localEpAgeIntvl == "infinite" + - nm_add_tenant_ep_retention_policy_2.current.0.fvEpRetPol.attributes.moveFreq == "none" + - nm_add_tenant_ep_retention_policy_2.current.0.fvEpRetPol.attributes.remoteEpAgeIntvl == "infinite" + - nm_add_tenant_ep_retention_policy_2.current.0.fvEpRetPol.attributes.name == "ep_policy_anstest_2" + - Modify_tenant_ep_retention_policy_bounce_age.msg == "The bounce_age must be a value of 0 or between 150 and 65535" + - Modify_tenant_ep_retention_policy_hold_interval.msg == "The hold_interval must be a value between 5 and 65535" + - Modify_tenant_ep_retention_policy_move_frequency.msg == "The move_frequency must be a value between 0 and 65535" + - Modify_tenant_ep_retention_policy_local_ep_interval.msg == "The local_ep_interval must be a value of 0 or between 120 and 65535" + - Modify_tenant_ep_retention_policy_remote_ep_interval.msg == "The remote_ep_interval must be a value of 0 or between 120 and 65535" + + - name: Query all EP retention protocol policies + aci_tenant_ep_retention_policy: + <<: *aci_info + state: query + register: query_all_tenant_ep_retention_policy + + - name: Query first EP retention protocol policy + aci_tenant_ep_retention_policy: + <<: *aci_tenant_ep_retention_policy_present + state: query + register: query_first_tenant_ep_retention_policy + + - name: Asserts for query tasks + assert: + that: + - query_all_tenant_ep_retention_policy is not changed + - query_all_tenant_ep_retention_policy.current | length >= 2 + - '"class/fvEpRetPol.json" in query_all_tenant_ep_retention_policy.url' + - query_first_tenant_ep_retention_policy is not changed + - query_first_tenant_ep_retention_policy.current.0.fvEpRetPol.attributes.name == "ep_policy_anstest" + - query_first_tenant_ep_retention_policy.current.0.fvEpRetPol.attributes.bounceAgeIntvl == "300" + - query_first_tenant_ep_retention_policy.current.0.fvEpRetPol.attributes.bounceTrig == "rarp-flood" + - query_first_tenant_ep_retention_policy.current.0.fvEpRetPol.attributes.holdIntvl == "600" + - query_first_tenant_ep_retention_policy.current.0.fvEpRetPol.attributes.localEpAgeIntvl == "1800" + - query_first_tenant_ep_retention_policy.current.0.fvEpRetPol.attributes.moveFreq == "512" + - query_first_tenant_ep_retention_policy.current.0.fvEpRetPol.attributes.remoteEpAgeIntvl == "600" + + - name: Delete first EP retention protocol policy (check_mode) + aci_tenant_ep_retention_policy: + <<: *aci_tenant_ep_retention_policy_present + state: absent + check_mode: true + register: cm_delete_tenant_ep_retention_policy_1 + + - name: Delete first EP retention protocol policy (normal_mode) + aci_tenant_ep_retention_policy: + <<: *aci_tenant_ep_retention_policy_present + state: absent + register: nm_delete_tenant_ep_retention_policy_1 + + - name: Delete first EP retention protocol policy again - testing idempotency + aci_tenant_ep_retention_policy: + <<: *aci_tenant_ep_retention_policy_present + state: absent + register: idempotency_delete_tenant_ep_retention_policy_1 + + - name: Delete second EP retention protocol policy (normal_mode) + aci_tenant_ep_retention_policy: + <<: *aci_tenant_ep_retention_policy_2_present + state: absent + register: nm_delete_tenant_ep_retention_policy_2 + + - name: Asserts for deletion tasks + assert: + that: + - cm_delete_tenant_ep_retention_policy_1 is changed + - cm_delete_tenant_ep_retention_policy_1.proposed == {} + - nm_delete_tenant_ep_retention_policy_1 is changed + - nm_delete_tenant_ep_retention_policy_1.previous != [] + - nm_delete_tenant_ep_retention_policy_1.current == [] + - idempotency_delete_tenant_ep_retention_policy_1 is not changed + - idempotency_delete_tenant_ep_retention_policy_1.previous == [] + - nm_delete_tenant_ep_retention_policy_2 is changed + - nm_delete_tenant_ep_retention_policy_2.previous != [] + - nm_delete_tenant_ep_retention_policy_2.current == [] + + - name: Delete tenant - clean up the environment + aci_tenant: + <<: *aci_tenant_present + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_dst_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_dst_group/tasks/main.yml index d7d807ad8..543a25cd5 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_dst_group/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_dst_group/tasks/main.yml @@ -26,216 +26,230 @@ tenant: ansible_tenant state: absent -- name: Add a new tenant - aci_tenant: - <<: *aci_info - tenant: ansible_tenant - description: Ansible tenant - state: present - -- name: Add span ansible_group - aci_tenant_span_dst_group: - <<: *aci_info - destination_group: ansible_group - description: Test span - destination_ip: 10.0.0.1 - source_ip: 10.0.2.1 - tenant: ansible_tenant - destination_epg: - tenant: Test1 - ap: ap1 - epg: ep1 - version_enforced: false - span_version: version_1 - ttl: 2 - mtu: 1500 - flow_id: 1 - dscp: "CS1" - state: present - register: add_span1 - -- name: Verify add span - assert: - that: - - add_span1 is changed - - add_span1.current.0.spanDestGrp.attributes.name == "ansible_group" - - add_span1.current.0.spanDestGrp.attributes.descr == "Test span" - - add_span1.current.0.spanDestGrp.attributes.dn == "uni/tn-ansible_tenant/destgrp-ansible_group" - - add_span1.current.0.spanDestGrp.children.0.spanDest.attributes.name == "ansible_group" - - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.dscp == "CS1" - - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.srcIpPrefix == "10.0.2.1" - - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ip == "10.0.0.1" - - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ver == "ver1" - - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.mtu == "1500" - - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.flowId == "1" - - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.verEnforced == "no" - - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ttl == "2" - - add_span1.current.0.spanDestGrp.attributes.annotation == 'orchestrator:ansible' - -- name: Add span ansible_group again - aci_tenant_span_dst_group: - <<: *aci_info - destination_group: ansible_group - description: Test span - destination_ip: 10.0.0.1 - source_ip: 10.0.2.1 - tenant: ansible_tenant - destination_epg: - tenant: Test1 - ap: ap1 - epg: ep1 - version_enforced: false - span_version: version_1 - ttl: 2 - mtu: 1500 - flow_id: 1 - dscp: "CS1" - state: present - register: add_span1_again - -- name: Verify add span again - assert: - that: - - add_span1_again is not changed - -- name: Change span ansible_group's src ip - aci_tenant_span_dst_group: - <<: *aci_info - destination_group: ansible_group2 - description: Test span - destination_ip: 10.0.0.2 - source_ip: 10.0.2.1 - tenant: ansible_tenant - destination_epg: - tenant: Test1 - ap: ap1 - epg: ep1 - version_enforced: false - span_version: version_1 - ttl: 2 - mtu: 1500 - flow_id: 1 - dscp: CS1 - state: present - register: change_span1_ip - -- name: Change span ansible_group's dscp - aci_tenant_span_dst_group: - <<: *aci_info - destination_group: ansible_group2 - description: Test span - destination_ip: 10.0.0.2 - source_ip: 10.0.2.1 - tenant: ansible_tenant - destination_epg: - tenant: Test1 - ap: ap1 - epg: ep1 - version_enforced: false - span_version: version_1 - ttl: 2 - mtu: 1500 - flow_id: 1 - dscp: VA - state: present - register: change_span1_dscp - -- name: Verify changes in span - assert: - that: - - change_span1_ip.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ip == "10.0.0.2" - - change_span1_dscp.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.dscp == "VA" - -- name: Add span ansible_group2 - aci_tenant_span_dst_group: - <<: *aci_info - destination_group: ansible_group2 - description: Test span - destination_ip: 10.0.0.1 - source_ip: 10.0.2.1 - tenant: ansible_tenant - destination_epg: - tenant: Test1 - ap: ap1 - epg: ep1 - version_enforced: true - span_version: version_2 - ttl: 2 - mtu: 1500 - flow_id: 1 - dscp: CS1 - state: present - register: add_span2 - -- name: Verify addition of second span - assert: - that: - - add_span2 is changed - - add_span2.current.0.spanDestGrp.attributes.name == "ansible_group2" - - add_span2.current.0.spanDestGrp.attributes.descr == "Test span" - - add_span2.current.0.spanDestGrp.attributes.dn == "uni/tn-ansible_tenant/destgrp-ansible_group2" - - add_span2.current.0.spanDestGrp.children.0.spanDest.attributes.name == "ansible_group2" - - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.dscp == "CS1" - - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.srcIpPrefix == "10.0.2.1" - - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ip == "10.0.0.1" - - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ver == "ver2" - - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.mtu == "1500" - - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.flowId == "1" - - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.verEnforced == "yes" - - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ttl == "2" - -- name: Query span ansible_group - aci_tenant_span_dst_group: - <<: *aci_info - tenant: ansible_tenant - destination_group: ansible_group - state: query - register: query_span_ansible_group - -- name: Query all span dest groups - aci_tenant_span_dst_group: - <<: *aci_info - state: query - register: query_all_span - -- name: Verify Query of span - assert: - that: - - query_span_ansible_group is not changed - - query_span_ansible_group.current.0.spanDestGrp.attributes.name == "ansible_group" - - query_span_ansible_group.current.0.spanDestGrp.attributes.descr == "Test span" - - query_span_ansible_group.current.0.spanDestGrp.attributes.dn == "uni/tn-ansible_tenant/destgrp-ansible_group" - - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.attributes.name == "ansible_group" - - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.dscp == "CS1" - - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.srcIpPrefix == "10.0.2.1" - - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ip == "10.0.0.1" - - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.mtu == "1500" - - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.flowId == "1" - - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.verEnforced == "no" - - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ttl == "2" - - query_all_span is not changed - - query_all_span | length >= 2 - -- name: Remove span ansible_group - aci_tenant_span_dst_group: - <<: *aci_info - tenant: ansible_tenant - destination_group: ansible_group - state: absent - register: remove_span1 - -- name: Remove span ansible_group2 - aci_tenant_span_dst_group: - <<: *aci_info - tenant: ansible_tenant - destination_group: ansible_group2 - state: absent - register: remove_span2 - -- name: Verify Remove of span - assert: - that: - - remove_span1 is changed - - remove_span1.current == [] - - remove_span2 is changed - - remove_span2.current == [] +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + + - name: Add a new tenant + aci_tenant: + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add span ansible_group + aci_tenant_span_dst_group: + <<: *aci_info + destination_group: ansible_group + description: Test span + destination_ip: 10.0.0.1 + source_ip: 10.0.2.1 + tenant: ansible_tenant + destination_epg: + tenant: Test1 + ap: ap1 + epg: ep1 + version_enforced: false + span_version: version_1 + ttl: 2 + mtu: 1500 + flow_id: 1 + dscp: "CS1" + state: present + register: add_span1 + + - name: Verify add span + assert: + that: + - add_span1 is changed + - add_span1.current.0.spanDestGrp.attributes.name == "ansible_group" + - add_span1.current.0.spanDestGrp.attributes.descr == "Test span" + - add_span1.current.0.spanDestGrp.attributes.dn == "uni/tn-ansible_tenant/destgrp-ansible_group" + - add_span1.current.0.spanDestGrp.children.0.spanDest.attributes.name == "ansible_group" + - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.dscp == "CS1" + - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.srcIpPrefix == "10.0.2.1" + - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ip == "10.0.0.1" + - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ver == "ver1" + - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.mtu == "1500" + - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.flowId == "1" + - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.verEnforced == "no" + - add_span1.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ttl == "2" + - add_span1.current.0.spanDestGrp.attributes.annotation == 'orchestrator:ansible' + + - name: Add span ansible_group again + aci_tenant_span_dst_group: + <<: *aci_info + destination_group: ansible_group + description: Test span + destination_ip: 10.0.0.1 + source_ip: 10.0.2.1 + tenant: ansible_tenant + destination_epg: + tenant: Test1 + ap: ap1 + epg: ep1 + version_enforced: false + span_version: version_1 + ttl: 2 + mtu: 1500 + flow_id: 1 + dscp: "CS1" + state: present + register: add_span1_again + + - name: Verify add span again + assert: + that: + - add_span1_again is not changed + + - name: Change span ansible_group's src ip + aci_tenant_span_dst_group: + <<: *aci_info + destination_group: ansible_group2 + description: Test span + destination_ip: 10.0.0.2 + source_ip: 10.0.2.1 + tenant: ansible_tenant + destination_epg: + tenant: Test1 + ap: ap1 + epg: ep1 + version_enforced: false + span_version: version_1 + ttl: 2 + mtu: 1500 + flow_id: 1 + dscp: CS1 + state: present + register: change_span1_ip + + - name: Change span ansible_group's dscp + aci_tenant_span_dst_group: + <<: *aci_info + destination_group: ansible_group2 + description: Test span + destination_ip: 10.0.0.2 + source_ip: 10.0.2.1 + tenant: ansible_tenant + destination_epg: + tenant: Test1 + ap: ap1 + epg: ep1 + version_enforced: false + span_version: version_1 + ttl: 2 + mtu: 1500 + flow_id: 1 + dscp: VA + state: present + register: change_span1_dscp + + - name: Verify changes in span + assert: + that: + - change_span1_ip.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ip == "10.0.0.2" + - change_span1_dscp.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.dscp == "VA" + + - name: Add span ansible_group2 + aci_tenant_span_dst_group: + <<: *aci_info + destination_group: ansible_group2 + description: Test span + destination_ip: 10.0.0.1 + source_ip: 10.0.2.1 + tenant: ansible_tenant + destination_epg: + tenant: Test1 + ap: ap1 + epg: ep1 + version_enforced: true + span_version: version_2 + ttl: 2 + mtu: 1500 + flow_id: 1 + dscp: CS1 + state: present + register: add_span2 + + - name: Verify addition of second span + assert: + that: + - add_span2 is changed + - add_span2.current.0.spanDestGrp.attributes.name == "ansible_group2" + - add_span2.current.0.spanDestGrp.attributes.descr == "Test span" + - add_span2.current.0.spanDestGrp.attributes.dn == "uni/tn-ansible_tenant/destgrp-ansible_group2" + - add_span2.current.0.spanDestGrp.children.0.spanDest.attributes.name == "ansible_group2" + - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.dscp == "CS1" + - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.srcIpPrefix == "10.0.2.1" + - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ip == "10.0.0.1" + - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ver == "ver2" + - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.mtu == "1500" + - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.flowId == "1" + - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.verEnforced == "yes" + - add_span2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ttl == "2" + + - name: Query span ansible_group + aci_tenant_span_dst_group: + <<: *aci_info + tenant: ansible_tenant + destination_group: ansible_group + state: query + register: query_span_ansible_group + + - name: Query all span dest groups + aci_tenant_span_dst_group: + <<: *aci_info + state: query + register: query_all_span + + - name: Verify Query of span + assert: + that: + - query_span_ansible_group is not changed + - query_span_ansible_group.current.0.spanDestGrp.attributes.name == "ansible_group" + - query_span_ansible_group.current.0.spanDestGrp.attributes.descr == "Test span" + - query_span_ansible_group.current.0.spanDestGrp.attributes.dn == "uni/tn-ansible_tenant/destgrp-ansible_group" + - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.attributes.name == "ansible_group" + - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.dscp == "CS1" + - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.srcIpPrefix == "10.0.2.1" + - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ip == "10.0.0.1" + - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.mtu == "1500" + - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.flowId == "1" + - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.verEnforced == "no" + - query_span_ansible_group.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestEpg.attributes.ttl == "2" + - query_all_span is not changed + - query_all_span | length >= 2 + + - name: Remove span ansible_group + aci_tenant_span_dst_group: + <<: *aci_info + tenant: ansible_tenant + destination_group: ansible_group + state: absent + register: remove_span1 + + - name: Remove span ansible_group2 + aci_tenant_span_dst_group: + <<: *aci_info + tenant: ansible_tenant + destination_group: ansible_group2 + state: absent + register: remove_span2 + + - name: Verify Remove of span + assert: + that: + - remove_span1 is changed + - remove_span1.current == [] + - remove_span2 is changed + - remove_span2.current == [] + + # CLEAN ENVIRONMENT + - name: Remove the ansible_tenant + aci_tenant: + <<: *aci_info + tenant: ansible_tenant + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool_encap_block/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool_encap_block/tasks/main.yml index c39259593..5ccf8bfbf 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool_encap_block/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool_encap_block/tasks/main.yml @@ -215,6 +215,7 @@ cisco.aci.aci_vlan_pool_encap_block: &aci_encap_block_query_filter <<: *aci_encap_block_query pool: "{{ fake_var | default(omit) }}" + pool_allocation_mode: "{{ fake_var | default(omit) }}" register: encap_block_query_from_to_name - name: Query assertions @@ -313,6 +314,7 @@ <<: *aci_pool_present state: query pool: "{{ fake_var | default(omit) }}" + pool_allocation_mode: "{{ fake_var | default(omit) }}" register: encap_block_query_all - name: Query assertions diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vrf/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_vrf/tasks/main.yml index fa3f1057c..695f40fe7 100644 --- a/ansible_collections/cisco/aci/tests/integration/targets/aci_vrf/tasks/main.yml +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vrf/tasks/main.yml @@ -62,6 +62,7 @@ policy_control_direction: egress preferred_group: enabled match_type: all + ip_data_plane_learning: disabled register: vrf_present_2 - name: create vrf without all necessary params - failure message works @@ -80,6 +81,7 @@ - vrf_present is changed - vrf_present.sent == vrf_present_check_mode.sent - vrf_present.current.0.fvCtx.attributes.annotation == 'orchestrator:ansible' + - vrf_present.current.0.fvCtx.attributes.ipDataPlaneLearning == 'enabled' - vrf_present.previous == [] - vrf_present_idempotent is not changed - vrf_present_idempotent.previous != [] @@ -88,9 +90,11 @@ - vrf_update.sent != vrf_update.proposed - vrf_update.sent.fvCtx.attributes.descr == 'Ansible Test Update' - vrf_update.sent.fvCtx.attributes.pcEnfPref == 'unenforced' + - vrf_update.current.0.fvCtx.attributes.ipDataPlaneLearning == 'enabled' - vrf_present_2.sent.fvCtx.attributes.name == 'anstest2' - vrf_present_2.sent.fvCtx.attributes.pcEnfDir == 'egress' - vrf_present_2.sent.fvCtx.attributes.descr == 'Ansible Test' + - vrf_present_2.current.0.fvCtx.attributes.ipDataPlaneLearning == 'disabled' - vrf_present_2.current.0.fvCtx.children.0.vzAny.attributes.matchT == 'All' - vrf_present_2.current.0.fvCtx.children.0.vzAny.attributes.prefGrMemb == 'enabled' - vrf_present_missing_param is failed diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vrf_leak_internal_subnet/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_vrf_leak_internal_subnet/aliases new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vrf_leak_internal_subnet/aliases diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vrf_leak_internal_subnet/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_vrf_leak_internal_subnet/tasks/main.yml new file mode 100644 index 000000000..2455f24e4 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vrf_leak_internal_subnet/tasks/main.yml @@ -0,0 +1,233 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Abraham Mughal (@abmughal) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: + - query_cloud.current == [] # This condition will execute only non-cloud sites + - version.current.0.topSystem.attributes.version is version('5', '>=') + block: # block specifies execution of tasks within, based on conditions + - name: Set vars + set_fact: + aci_info: &aci_info + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: '{{ aci_output_level | default("debug") }}' + + - name: delete existing tenant + cisco.aci.aci_tenant: + <<: *aci_info + state: absent + tenant: ansible_test3 + register: tenant_present + + - name: ensure tenant exists for tests to kick off + cisco.aci.aci_tenant: &aci_tenant_present + <<: *aci_info + state: present + tenant: ansible_test3 + register: tenant_present + + - name: create vrf + cisco.aci.aci_vrf: &aci_vrf_present + <<: *aci_tenant_present + vrf: test + description: Ansible Test + register: vrf_present + + - name: create second vrf - creation works + cisco.aci.aci_vrf: + <<: *aci_vrf_present + vrf: test2 + register: vrf_present + + - name: create third vrf - creation works + cisco.aci.aci_vrf: + <<: *aci_vrf_present + vrf: test3 + register: vrf_present + + - name: create leak internal subnet - check_mode + cisco.aci.aci_vrf_leak_internal_subnet: &aci_leak_internal_subnet + <<: *aci_info + state: present + tenant: ansible_test3 + vrf: test + ip: 1.1.1.2 + leak_to: + - vrf: "test2" + tenant: "ansible_test3" + - vrf: "test3" + tenant: "ansible_test3" + description: Ansible Test + check_mode: true + register: leak_sub_check_mode + + - name: create leak internal subnet + cisco.aci.aci_vrf_leak_internal_subnet: + <<: *aci_leak_internal_subnet + register: leak_sub_present + + - name: create leak internal subnet - idempotency check + cisco.aci.aci_vrf_leak_internal_subnet: + <<: *aci_info + state: present + tenant: ansible_test3 + vrf: test + ip: 1.1.1.2 + leak_to: + - vrf: "test2" + tenant: "ansible_test3" + - vrf: "test3" + tenant: "ansible_test3" + description: Ansible Test + register: leak_sub_idempotent + + - name: create second leak internal subnet + cisco.aci.aci_vrf_leak_internal_subnet: + <<: *aci_info + tenant: ansible_test3 + vrf: test2 + leak_to: + - vrf: "test" + tenant: "ansible_test3" + description: Ansible Test + ip: 1.1.1.2 + register: leak_sub_present_2 + + - name: Sort the list of leaked internal subnets for present + ansible.builtin.set_fact: + attributes_list_present: "{{ leak_sub_present.current.0.leakInternalSubnet.children | map(attribute='leakTo.attributes') | list | sort(attribute='ctxName') }}" + + - name: present asserts + assert: + that: + - vrf_present is changed + - leak_sub_check_mode is changed + - leak_sub_check_mode.proposed.leakInternalSubnet.attributes.ip == '1.1.1.2' + - leak_sub_check_mode.proposed.leakInternalSubnet.children.0.leakTo.attributes.ctxName == 'test2' + - leak_sub_check_mode.proposed.leakInternalSubnet.children.0.leakTo.attributes.tenantName == 'ansible_test3' + - leak_sub_check_mode.proposed.leakInternalSubnet.children.1.leakTo.attributes.ctxName == 'test3' + - leak_sub_check_mode.proposed.leakInternalSubnet.children.1.leakTo.attributes.tenantName == 'ansible_test3' + - leak_sub_present.current.0.leakInternalSubnet.attributes.ip == '1.1.1.2' + - attributes_list_present.0.tenantName == 'ansible_test3' + - attributes_list_present.0.ctxName == 'test2' + - attributes_list_present.1.tenantName == 'ansible_test3' + - attributes_list_present.1.ctxName == 'test3' + - leak_sub_idempotent is not changed + - leak_sub_present_2.current.0.leakInternalSubnet.attributes.ip == '1.1.1.2' + - leak_sub_present_2.current.0.leakInternalSubnet.children.0.leakTo.attributes.ctxName == 'test' + - leak_sub_present_2.current.0.leakInternalSubnet.children.0.leakTo.attributes.tenantName == 'ansible_test3' + + - name: query all + cisco.aci.aci_vrf_leak_internal_subnet: &aci_query + <<: *aci_info + state: query + ip: 1.1.1.2 + register: query_all + + - name: query one leak internal subnet + cisco.aci.aci_vrf_leak_internal_subnet: + <<: *aci_tenant_present + state: query + vrf: test + ip: 1.1.1.2 + register: query + + - name: absent case + cisco.aci.aci_vrf_leak_internal_subnet: + <<: *aci_info + tenant: ansible_test3 + vrf: test2 + leak_to: + - vrf: "test" + tenant: "ansible_test3" + description: Ansible Test + ip: 1.1.1.2 + state: absent + register: leak_sub_absent + + - name: Sort the list of leaked internal subnets for query + ansible.builtin.set_fact: + attributes_list_query_all: "{{ query_all.current.0.leakInternalSubnet.children | map(attribute='leakTo.attributes') | list | sort(attribute='ctxName') }}" + attributes_list_query: "{{ query.current.0.leakInternalSubnet.children | map(attribute='leakTo.attributes') | list | sort(attribute='ctxName') }}" + + - name: query asserts + assert: + that: + - query_all is not changed + - query is not changed + - query_all.current.0.leakInternalSubnet.attributes.ip == '1.1.1.2' + - attributes_list_query_all.0.ctxName == 'test2' + - attributes_list_query_all.0.tenantName == 'ansible_test3' + - attributes_list_query_all.1.ctxName == 'test3' + - attributes_list_query_all.1.tenantName == 'ansible_test3' + - query_all.current.1.leakInternalSubnet.attributes.ip == '1.1.1.2' + - query_all.current.1.leakInternalSubnet.children.0.leakTo.attributes.ctxName == 'test' + - query_all.current.1.leakInternalSubnet.children.0.leakTo.attributes.tenantName == 'ansible_test3' + - attributes_list_query.0.ctxName == 'test2' + - attributes_list_query.0.tenantName == 'ansible_test3' + - attributes_list_query.1.ctxName == 'test3' + - attributes_list_query.1.tenantName == 'ansible_test3' + - leak_sub_absent.proposed == {} + + - name: delete leak internal subnet - check_mode + cisco.aci.aci_vrf_leak_internal_subnet: &aci_delete + <<: *aci_vrf_present + vrf: test + leak_to: + - vrf: "test3" + tenant: "ansible_test3" + ip: 1.1.1.2 + register: leak_sub_delete_check_mode + + - name: delete leak internal subnet + cisco.aci.aci_vrf_leak_internal_subnet: + <<: *aci_delete + register: leak_sub_delete + + - name: delete leak internal subnet again + cisco.aci.aci_vrf_leak_internal_subnet: &aci_delete_again + <<: *aci_vrf_present + vrf: test + leak_to: + - vrf: "test2" + tenant: "ansible_test3" + ip: 1.1.1.2 + register: leak_sub_delete_2 + + - name: delete leak internal subnet idempotency check + cisco.aci.aci_vrf_leak_internal_subnet: + <<: *aci_delete_again + register: leak_sub_delete_idempotency + + - name: delete asserts + assert: + that: + - leak_sub_delete_check_mode is changed + - leak_sub_delete_check_mode.current.0.leakInternalSubnet.children.0.leakTo.attributes.ctxName == 'test3' + - leak_sub_delete_check_mode.current.0.leakInternalSubnet.children.0.leakTo.attributes.tenantName == 'ansible_test3' + - leak_sub_delete.previous != [] + - leak_sub_delete.current.0.leakInternalSubnet.children | length == 1 + - leak_sub_delete.current.0.leakInternalSubnet.children.0.leakTo.attributes.ctxName == 'test3' + - leak_sub_delete.current.0.leakInternalSubnet.children.0.leakTo.attributes.tenantName == 'ansible_test3' + - leak_sub_delete_2 is changed + - leak_sub_delete_2.current.0.leakInternalSubnet.children | length == 1 + - leak_sub_delete_2.current.0.leakInternalSubnet.children.0.leakTo.attributes.ctxName == 'test2' + - leak_sub_delete_2.current.0.leakInternalSubnet.children.0.leakTo.attributes.tenantName == 'ansible_test3' + - leak_sub_delete_idempotency is not changed + - leak_sub_delete_idempotency.current.0.leakInternalSubnet.children.0.leakTo.attributes.ctxName == 'test2' + - leak_sub_delete_idempotency.current.0.leakInternalSubnet.children.0.leakTo.attributes.tenantName == 'ansible_test3'
\ No newline at end of file |