diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:04:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:04:41 +0000 |
commit | 975f66f2eebe9dadba04f275774d4ab83f74cf25 (patch) | |
tree | 89bd26a93aaae6a25749145b7e4bca4a1e75b2be /ansible_collections/cisco/aci/tests/integration | |
parent | Initial commit. (diff) | |
download | ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.tar.xz ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.zip |
Adding upstream version 7.7.0+dfsg.upstream/7.7.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/cisco/aci/tests/integration')
325 files changed, 39095 insertions, 0 deletions
diff --git a/ansible_collections/cisco/aci/tests/integration/inventory.networking b/ansible_collections/cisco/aci/tests/integration/inventory.networking new file mode 100644 index 000000000..16e3d1ee1 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/inventory.networking @@ -0,0 +1,13 @@ +[aci] +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 + +[aci:vars] +aci_username=ansible_github_ci +aci_password="sJ94G92#8dq2hx*K4qh" +ansible_connection=local +ansible_python_interpreter=/usr/bin/python3.9 diff --git a/ansible_collections/cisco/aci/tests/integration/network-integration.requirements.txt b/ansible_collections/cisco/aci/tests/integration/network-integration.requirements.txt new file mode 100644 index 000000000..7e23f90da --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/network-integration.requirements.txt @@ -0,0 +1,12 @@ +lxml +cryptography +pyOpenSSL +netaddr +ipaddress + +# requirement for aci_rest module +xmljson +lxml + +# requirement for aci_aaa_user module +python-dateutil
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/target-prefixes.network b/ansible_collections/cisco/aci/tests/integration/target-prefixes.network new file mode 100644 index 000000000..dc092c888 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/target-prefixes.network @@ -0,0 +1 @@ +aci diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_custom_privilege/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_custom_privilege/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_custom_privilege/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_custom_privilege/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_custom_privilege/tasks/main.yml new file mode 100644 index 000000000..04b7070e2 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_custom_privilege/tasks/main.yml @@ -0,0 +1,237 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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: Execute tasks only for ACI v5+ + when: version.current.0.topSystem.attributes.version is version('5', '>=') + block: # block specifies execution of tasks within, based on conditions + - name: Ensure fabricPod custom privilege does not exists + cisco.aci.aci_aaa_custom_privilege: &fabric_pod_absent + <<: *aci_info + name: fabricPod + state: absent + + - name: Add a custom privilege with check mode + cisco.aci.aci_aaa_custom_privilege: &cm_cp_present + <<: *fabric_pod_absent + description: My Custom Privilege + write_privilege: custom-privilege-1 + read_privilege: custom-privilege-1 + state: present + check_mode: true + register: cm_cp_present + + - name: Assertions check for add a custom privilege with check mode + assert: + that: + - cm_cp_present is changed + - cm_cp_present.current | length == 0 + - cm_cp_present.previous | length == 0 + - cm_cp_present.sent.aaaRbacClassPriv.attributes.name == 'fabricPod' + - cm_cp_present.sent.aaaRbacClassPriv.attributes.descr == 'My Custom Privilege' + - cm_cp_present.sent.aaaRbacClassPriv.attributes.wPriv == 'custom-privilege-1' + - cm_cp_present.sent.aaaRbacClassPriv.attributes.rPriv == 'custom-privilege-1' + + - name: Add a custom privilege with normal mode + cisco.aci.aci_aaa_custom_privilege: &nm_cp_present + <<: *cm_cp_present + register: nm_cp_present + + - name: Assertions check for add a custom privilege with normal mode + assert: + that: + - nm_cp_present is changed + - nm_cp_present.current | length == 1 + - nm_cp_present.previous | length == 0 + - nm_cp_present.current.0.aaaRbacClassPriv.attributes.name == 'fabricPod' + - nm_cp_present.current.0.aaaRbacClassPriv.attributes.descr == 'My Custom Privilege' + - nm_cp_present.current.0.aaaRbacClassPriv.attributes.wPriv == 'custom-privilege-1' + - nm_cp_present.current.0.aaaRbacClassPriv.attributes.rPriv == 'custom-privilege-1' + + - name: Add a custom privilege with normal mode - idempotency works + cisco.aci.aci_aaa_custom_privilege: + <<: *nm_cp_present + register: idempotency_cp_present + + - name: Idempotency assertions check for add a custom privilege with normal mode + assert: + that: + - idempotency_cp_present is not changed + - idempotency_cp_present.current | length == 1 + - idempotency_cp_present.previous | length == 1 + - idempotency_cp_present.current.0.aaaRbacClassPriv.attributes.name == 'fabricPod' + - idempotency_cp_present.current.0.aaaRbacClassPriv.attributes.descr == 'My Custom Privilege' + - idempotency_cp_present.current.0.aaaRbacClassPriv.attributes.wPriv == 'custom-privilege-1' + - idempotency_cp_present.current.0.aaaRbacClassPriv.attributes.rPriv == 'custom-privilege-1' + - idempotency_cp_present.previous.0.aaaRbacClassPriv.attributes.name == 'fabricPod' + - idempotency_cp_present.previous.0.aaaRbacClassPriv.attributes.descr == 'My Custom Privilege' + - idempotency_cp_present.previous.0.aaaRbacClassPriv.attributes.wPriv == 'custom-privilege-1' + - idempotency_cp_present.previous.0.aaaRbacClassPriv.attributes.rPriv == 'custom-privilege-1' + + - name: Ensure fvTenant custom privilege does not exists + cisco.aci.aci_aaa_custom_privilege: &fv_tenant_absent + <<: *aci_info + name: fvTenant + state: absent + + - name: Add a custom privilege with none privileges + cisco.aci.aci_aaa_custom_privilege: &fv_tenant_present + <<: *fv_tenant_absent + state: present + register: cp_with_none_priv + + - name: Assertions check for add a custom privilege with none privileges + assert: + that: + - cp_with_none_priv is changed + - cp_with_none_priv.current | length == 1 + - cp_with_none_priv.previous | length == 0 + - cp_with_none_priv.current.0.aaaRbacClassPriv.attributes.name == 'fvTenant' + - cp_with_none_priv.current.0.aaaRbacClassPriv.attributes.wPriv == '' + - cp_with_none_priv.current.0.aaaRbacClassPriv.attributes.rPriv == '' + + - name: Update fv_tenant_present custom privilege with 'custom-privilege-2' privilege + cisco.aci.aci_aaa_custom_privilege: + <<: *fv_tenant_present + write_privilege: custom-privilege-2 + read_privilege: custom-privilege-2 + register: update_cp_with_priv + + - name: Assertions check for update fv_tenant_present custom privilege with 'custom-privilege-2' privilege + assert: + that: + - update_cp_with_priv is changed + - update_cp_with_priv.current | length == 1 + - update_cp_with_priv.previous | length == 1 + - update_cp_with_priv.current.0.aaaRbacClassPriv.attributes.name == 'fvTenant' + - update_cp_with_priv.current.0.aaaRbacClassPriv.attributes.wPriv == 'custom-privilege-2' + - update_cp_with_priv.current.0.aaaRbacClassPriv.attributes.rPriv == 'custom-privilege-2' + - update_cp_with_priv.previous.0.aaaRbacClassPriv.attributes.wPriv == '' + - update_cp_with_priv.previous.0.aaaRbacClassPriv.attributes.rPriv == '' + + - name: Update fv_tenant_present - write_privilege to 'custom-privilege-3' privilege + cisco.aci.aci_aaa_custom_privilege: + <<: *fv_tenant_present + write_privilege: custom-privilege-3 + register: update_cp_w_priv_check + + - name: Assertions check for update fv_tenant_present - write_privilege to 'custom-privilege-3' privilege + assert: + that: + - update_cp_w_priv_check is changed + - update_cp_w_priv_check.current | length == 1 + - update_cp_w_priv_check.previous | length == 1 + - update_cp_w_priv_check.current.0.aaaRbacClassPriv.attributes.name == 'fvTenant' + - update_cp_w_priv_check.current.0.aaaRbacClassPriv.attributes.wPriv == 'custom-privilege-3' + - update_cp_w_priv_check.current.0.aaaRbacClassPriv.attributes.rPriv == 'custom-privilege-2' + - update_cp_w_priv_check.previous.0.aaaRbacClassPriv.attributes.name == 'fvTenant' + - update_cp_w_priv_check.previous.0.aaaRbacClassPriv.attributes.wPriv == 'custom-privilege-2' + - update_cp_w_priv_check.previous.0.aaaRbacClassPriv.attributes.rPriv == 'custom-privilege-2' + + - name: Query a custom privilege with name + cisco.aci.aci_aaa_custom_privilege: + <<: *aci_info + name: fabricPod + state: query + register: query_a_cp_with_name + + - name: Assertions check for query a custom privilege with name + assert: + that: + - query_a_cp_with_name is not changed + - query_a_cp_with_name.current | length == 1 + - query_a_cp_with_name.current.0.aaaRbacClassPriv.attributes.name == 'fabricPod' + - query_a_cp_with_name.current.0.aaaRbacClassPriv.attributes.wPriv == 'custom-privilege-1' + - query_a_cp_with_name.current.0.aaaRbacClassPriv.attributes.rPriv == 'custom-privilege-1' + + - name: Query all custom privileges + cisco.aci.aci_aaa_custom_privilege: + <<: *aci_info + state: query + register: query_all_cp + + - name: Assertions check for query all custom privileges + assert: + that: + - query_all_cp is not changed + - query_all_cp.current | length >= 2 + + - name: Remove a custom privilege with check mode + cisco.aci.aci_aaa_custom_privilege: &cm_cp_absent + <<: *aci_info + name: fabricPod + state: absent + check_mode: true + register: cm_cp_absent + + - name: Assertions check for remove a custom privilege with check mode + assert: + that: + - cm_cp_absent is changed + - cm_cp_absent.current | length == 1 + - cm_cp_absent.previous | length == 1 + - cm_cp_absent.current.0.aaaRbacClassPriv.attributes.name == 'fabricPod' + - cm_cp_absent.previous.0.aaaRbacClassPriv.attributes.name == 'fabricPod' + + - name: Remove a custom privilege with normal mode + cisco.aci.aci_aaa_custom_privilege: &nm_cp_absent + <<: *cm_cp_absent + register: nm_cp_absent + + - name: Assertions check for remove a custom privilege with normal mode + assert: + that: + - nm_cp_absent is changed + - nm_cp_absent.current == [] + - nm_cp_absent.previous | length == 1 + - nm_cp_absent.previous.0.aaaRbacClassPriv.attributes.name == 'fabricPod' + + - name: Remove a custom privilege with normal mode - idempotency works + cisco.aci.aci_aaa_custom_privilege: + <<: *nm_cp_absent + register: idempotency_cp_absent + + - name: Idempotency assertions check for remove a custom privilege with normal mode + assert: + that: + - idempotency_cp_absent is not changed + - idempotency_cp_absent.current == [] + - idempotency_cp_absent.previous == [] + + - name: Query a Removed custom privilege with name + cisco.aci.aci_aaa_custom_privilege: + <<: *aci_info + name: fabricPod + state: query + register: removed_cp_query_result + + - name: Assertions check for Removed custom privilege with name + assert: + that: + - removed_cp_query_result is not changed + - removed_cp_query_result.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_domain/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_domain/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_domain/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_domain/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_domain/tasks/main.yml new file mode 100644 index 000000000..55eaaff79 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_domain/tasks/main.yml @@ -0,0 +1,227 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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 anstest_sec_domain does not exists + cisco.aci.aci_aaa_domain: &sec_domain_absent + <<: *aci_info + name: anstest_sec_domain + description: "Anstest Sec Domain Descr" + state: absent + +- name: Add anstest_sec_domain security domain with check mode + cisco.aci.aci_aaa_domain: &cm_sec_domain_present + <<: *sec_domain_absent + state: present + check_mode: true + register: cm_sec_domain_present + +- name: Assertions check for add anstest_sec_domain security domain with check mode + assert: + that: + - cm_sec_domain_present is changed + - cm_sec_domain_present.current | length == 0 + - cm_sec_domain_present.previous | length == 0 + - cm_sec_domain_present.sent.aaaDomain.attributes.name == 'anstest_sec_domain' + +- name: Add anstest_sec_domain security domain with normal mode + cisco.aci.aci_aaa_domain: &nm_sec_domain_present + <<: *cm_sec_domain_present + register: nm_sec_domain_present + +- name: Assertions check for add anstest_sec_domain security domain with normal mode + assert: + that: + - nm_sec_domain_present is changed + - nm_sec_domain_present.current | length == 1 + - nm_sec_domain_present.previous | length == 0 + - nm_sec_domain_present.current.0.aaaDomain.attributes.name == 'anstest_sec_domain' + +- name: Assertions check for nm_sec_domain_present in v5.0+ + assert: + that: + - nm_sec_domain_present.current.0.aaaDomain.attributes.restrictedRbacDomain == 'no' + when: version.current.0.topSystem.attributes.version is version('5', '>=') + +- name: Add anstest_sec_domain security domain with normal mode - idempotency works + cisco.aci.aci_aaa_domain: + <<: *nm_sec_domain_present + register: idempotency_sec_domain_present + +- name: Idempotency assertions check for add anstest_sec_domain security domain with normal mode + assert: + that: + - idempotency_sec_domain_present is not changed + - idempotency_sec_domain_present.current | length == 1 + - idempotency_sec_domain_present.previous | length == 1 + - idempotency_sec_domain_present.current.0.aaaDomain.attributes.name == 'anstest_sec_domain' + - idempotency_sec_domain_present.previous.0.aaaDomain.attributes.name == 'anstest_sec_domain' + +- name: Assertions check for idempotency_sec_domain_present in v5.0+ + assert: + that: + - idempotency_sec_domain_present.current.0.aaaDomain.attributes.restrictedRbacDomain == 'no' + - idempotency_sec_domain_present.previous.0.aaaDomain.attributes.restrictedRbacDomain == 'no' + when: version.current.0.topSystem.attributes.version is version('5', '>=') + +- name: Execute tasks only for ACI v5+ + when: version.current.0.topSystem.attributes.version is version('5', '>=') + block: # block specifies execution of tasks within, based on conditions + - name: Update anstest_sec_domain security domain restricted_rbac_domain state to true + cisco.aci.aci_aaa_domain: + <<: *nm_sec_domain_present + restricted_rbac_domain: true + register: update_sec_domain_present_true + + - name: Assertions check for update anstest_sec_domain security domain restricted_rbac_domain state to true + assert: + that: + - update_sec_domain_present_true is changed + - update_sec_domain_present_true.current | length == 1 + - update_sec_domain_present_true.previous | length == 1 + - update_sec_domain_present_true.current.0.aaaDomain.attributes.name == 'anstest_sec_domain' + - update_sec_domain_present_true.current.0.aaaDomain.attributes.restrictedRbacDomain == 'yes' + - update_sec_domain_present_true.sent.aaaDomain.attributes.restrictedRbacDomain == 'yes' + - update_sec_domain_present_true.previous.0.aaaDomain.attributes.restrictedRbacDomain == 'no' + + - name: Update anstest_sec_domain security domain restricted_rbac_domain state to false + cisco.aci.aci_aaa_domain: + <<: *nm_sec_domain_present + restricted_rbac_domain: false + register: update_sec_domain_present_false + + - name: Assertions check for update anstest_sec_domain security domain restricted_rbac_domain state to false + assert: + that: + - update_sec_domain_present_false is changed + - update_sec_domain_present_false.current | length == 1 + - update_sec_domain_present_false.previous | length == 1 + - update_sec_domain_present_false.current.0.aaaDomain.attributes.name == 'anstest_sec_domain' + - update_sec_domain_present_false.current.0.aaaDomain.attributes.restrictedRbacDomain == 'no' + - update_sec_domain_present_false.sent.aaaDomain.attributes.restrictedRbacDomain == 'no' + - update_sec_domain_present_false.previous.0.aaaDomain.attributes.restrictedRbacDomain == 'yes' + +- name: Query a security domain with name + cisco.aci.aci_aaa_domain: + <<: *aci_info + name: anstest_sec_domain + state: query + register: query_sec_domain_with_name + +- name: Assertions check for query a security domain with name + assert: + that: + - query_sec_domain_with_name is not changed + - query_sec_domain_with_name.current | length == 1 + - query_sec_domain_with_name.current.0.aaaDomain.attributes.name == 'anstest_sec_domain' + - query_sec_domain_with_name.current.0.aaaDomain.attributes.descr == 'Anstest Sec Domain Descr' + +- name: Assertions check for query_sec_domain_with_name in v5.0+ + assert: + that: + - query_sec_domain_with_name.current.0.aaaDomain.attributes.restrictedRbacDomain == 'no' + when: version.current.0.topSystem.attributes.version is version('5', '>=') + +- name: Query all security domains + cisco.aci.aci_aaa_domain: + <<: *aci_info + state: query + register: query_all_sec_domains + +- name: Assertions check for query all security domains + assert: + that: + - query_all_sec_domains is not changed + - query_all_sec_domains.current | length >= 1 + +- name: Remove anstest_sec_domain security domain with check mode + cisco.aci.aci_aaa_domain: &cm_sec_domain_absent + <<: *nm_sec_domain_present + state: absent + check_mode: true + register: cm_sec_domain_absent + +- name: Assertions check for remove anstest_sec_domain security domain with check mode + assert: + that: + - cm_sec_domain_absent is changed + - cm_sec_domain_absent.current | length == 1 + - cm_sec_domain_absent.previous | length == 1 + - cm_sec_domain_absent.current.0.aaaDomain.attributes.name == 'anstest_sec_domain' + - cm_sec_domain_absent.previous.0.aaaDomain.attributes.name == 'anstest_sec_domain' + +- name: Assertions check for cm_sec_domain_absent in v5.0+ + assert: + that: + - cm_sec_domain_absent.current.0.aaaDomain.attributes.restrictedRbacDomain == 'no' + - cm_sec_domain_absent.previous.0.aaaDomain.attributes.restrictedRbacDomain == 'no' + when: version.current.0.topSystem.attributes.version is version('5', '>=') + +- name: Remove anstest_sec_domain security domain with normal mode + cisco.aci.aci_aaa_domain: &nm_sec_domain_absent + <<: *cm_sec_domain_absent + register: nm_sec_domain_absent + +- name: Assertions check for remove anstest_sec_domain security domain with normal mode + assert: + that: + - nm_sec_domain_absent is changed + - nm_sec_domain_absent.current | length == 0 + - nm_sec_domain_absent.previous | length == 1 + - nm_sec_domain_absent.previous.0.aaaDomain.attributes.name == 'anstest_sec_domain' + +- name: Assertions check for nm_sec_domain_absent in v5.0+ + assert: + that: + - nm_sec_domain_absent.previous.0.aaaDomain.attributes.restrictedRbacDomain == 'no' + when: version.current.0.topSystem.attributes.version is version('5', '>=') + +- name: Remove anstest_sec_domain security domain with normal mode - idempotency works + cisco.aci.aci_aaa_domain: + <<: *nm_sec_domain_absent + register: idempotency_sec_domain_absent + +- name: Idempotency assertions check for remove anstest_sec_domain security domain with normal mode + assert: + that: + - idempotency_sec_domain_absent is not changed + - idempotency_sec_domain_absent.current | length == 0 + - idempotency_sec_domain_absent.previous | length == 0 + +- name: Query a removed security domain with name + cisco.aci.aci_aaa_domain: + <<: *aci_info + name: anstest_sec_domain + state: query + register: removed_sec_domain_with_name + +- name: Assertions check for query a removed security domain with name + assert: + that: + - removed_sec_domain_with_name is not changed + - removed_sec_domain_with_name.current | length == 0 diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_role/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_role/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_role/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_role/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_role/tasks/main.yml new file mode 100644 index 000000000..dce0fd4c6 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_role/tasks/main.yml @@ -0,0 +1,229 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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 an anstest_role aaa role does not exists + cisco.aci.aci_aaa_role: &anstest_role_absent + <<: *aci_info + name: anstest_role + state: absent + +- name: Add an anstest_role aaa role with check mode + cisco.aci.aci_aaa_role: &cm_anstest_role_present + <<: *anstest_role_absent + priv: aaa + state: present + check_mode: true + register: cm_anstest_role_present + +- name: Assertions check for add an anstest_role aaa role with check mode + assert: + that: + - cm_anstest_role_present is changed + - cm_anstest_role_present.current | length == 0 + - cm_anstest_role_present.previous | length == 0 + - cm_anstest_role_present.sent.aaaRole.attributes.name == 'anstest_role' + - cm_anstest_role_present.sent.aaaRole.attributes.priv == 'aaa' + +- name: Add an anstest_role aaa role with normal mode + cisco.aci.aci_aaa_role: &nm_anstest_role_present + <<: *cm_anstest_role_present + register: nm_anstest_role_present + +- name: Assertions check for add an anstest_role aaa role with normal mode + assert: + that: + - nm_anstest_role_present is changed + - nm_anstest_role_present.current | length == 1 + - nm_anstest_role_present.previous | length == 0 + - nm_anstest_role_present.current.0.aaaRole.attributes.name == 'anstest_role' + - nm_anstest_role_present.current.0.aaaRole.attributes.priv == 'aaa' + +- name: Add an anstest_role aaa role with normal mode - idempotency works + cisco.aci.aci_aaa_role: + <<: *nm_anstest_role_present + register: idempotency_anstest_role_present + +- name: Idempotency assertions check for add an anstest_role aaa role with normal mode + assert: + that: + - idempotency_anstest_role_present is not changed + - idempotency_anstest_role_present.current | length == 1 + - idempotency_anstest_role_present.previous | length == 1 + - idempotency_anstest_role_present.current.0.aaaRole.attributes.name == 'anstest_role' + - idempotency_anstest_role_present.previous.0.aaaRole.attributes.name == 'anstest_role' + - idempotency_anstest_role_present.current.0.aaaRole.attributes.priv == 'aaa' + - idempotency_anstest_role_present.previous.0.aaaRole.attributes.priv == 'aaa' + +- name: Update an anstest_role with list of privileges + cisco.aci.aci_aaa_role: + <<: *nm_anstest_role_present + priv: [ "admin", "aaa", "tenant-connectivity"] + register: anstest_role_with_list_priv + +- name: Assertions check for update an anstest_role with list of privileges + assert: + that: + - anstest_role_with_list_priv is changed + - anstest_role_with_list_priv.current | length == 1 + - anstest_role_with_list_priv.previous | length == 1 + - anstest_role_with_list_priv.current.0.aaaRole.attributes.name == 'anstest_role' + - anstest_role_with_list_priv.previous.0.aaaRole.attributes.name == 'anstest_role' + - anstest_role_with_list_priv.previous.0.aaaRole.attributes.priv == 'aaa' + +- name: Assertions check for anstest_role_with_list_priv on v4.2 or earlier + assert: + that: + - anstest_role_with_list_priv.current.0.aaaRole.attributes.priv == 'aaa,admin' + when: version.current.0.topSystem.attributes.version is version('5', '<') + +- name: Assertions check for anstest_role_with_list_priv on v5+ + assert: + that: + - anstest_role_with_list_priv.current.0.aaaRole.attributes.priv == 'aaa,admin,tenant-connectivity' + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + +- name: Update an anstest_role with admin privilege + cisco.aci.aci_aaa_role: + <<: *nm_anstest_role_present + priv: "admin" + register: anstest_role_with_valid_priv + +- name: Assertions check for update an anstest_role with admin privilege + assert: + that: + - anstest_role_with_valid_priv is changed + - anstest_role_with_valid_priv.current | length == 1 + - anstest_role_with_valid_priv.previous | length == 1 + - anstest_role_with_valid_priv.current.0.aaaRole.attributes.name == 'anstest_role' + - anstest_role_with_valid_priv.previous.0.aaaRole.attributes.name == 'anstest_role' + - anstest_role_with_valid_priv.current.0.aaaRole.attributes.priv == 'admin' + +- name: Assertions check for anstest_role_with_valid_priv on v4.2 or earlier + assert: + that: + - anstest_role_with_valid_priv.previous.0.aaaRole.attributes.priv == 'aaa,admin' + when: version.current.0.topSystem.attributes.version is version('5', '<') + +- name: Assertions check for anstest_role_with_valid_priv on v5+ + assert: + that: + - anstest_role_with_valid_priv.previous.0.aaaRole.attributes.priv == 'aaa,admin,tenant-connectivity' + when: version.current.0.topSystem.attributes.version is version('5', '>=') + +- name: Update an anstest_role with invalid list of privileges + cisco.aci.aci_aaa_role: + <<: *nm_anstest_role_present + priv: [ "admin", "aaa", "tenant-connectivity123"] + register: anstest_role_with_invalid_list_priv + ignore_errors: true + +- name: Update an anstest_role with invalid privilege + cisco.aci.aci_aaa_role: + <<: *nm_anstest_role_present + priv: "admin123" + register: anstest_role_with_invalid_priv + ignore_errors: true + +- name: Assertions check for query a aaa role with name + assert: + that: + - anstest_role_with_invalid_list_priv.msg.startswith("value of privileges must be one or more of") + - anstest_role_with_invalid_priv.msg.startswith("value of privileges must be one or more of") + +- name: Query an aaa role with name + cisco.aci.aci_aaa_role: + <<: *aci_info + name: anstest_role + state: query + register: anstest_role_query_result + +- name: Assertions check for query a aaa role with name + assert: + that: + - anstest_role_query_result is not changed + - anstest_role_query_result.current | length == 1 + - anstest_role_query_result.current.0.aaaRole.attributes.name == 'anstest_role' + - anstest_role_query_result.current.0.aaaRole.attributes.priv == 'admin' + +- name: Query all aaa roles + cisco.aci.aci_aaa_role: + <<: *aci_info + state: query + register: query_all_roles + +- name: Assertions check for query all aaa roles + assert: + that: + - query_all_roles is not changed + - query_all_roles.current | length >= 1 + +- name: Remove an anstest_role aaa role with check mode + cisco.aci.aci_aaa_role: &cm_anstest_role_absent + <<: *nm_anstest_role_present + state: absent + check_mode: true + register: cm_anstest_role_absent + +- name: Assertions check for remove an anstest_role aaa role with check mode + assert: + that: + - cm_anstest_role_absent is changed + - cm_anstest_role_absent.current | length == 1 + - cm_anstest_role_absent.previous | length == 1 + - cm_anstest_role_absent.current.0.aaaRole.attributes.name == 'anstest_role' + - cm_anstest_role_absent.previous.0.aaaRole.attributes.name == 'anstest_role' + - cm_anstest_role_absent.current.0.aaaRole.attributes.priv == 'admin' + - cm_anstest_role_absent.previous.0.aaaRole.attributes.priv == 'admin' + +- name: Remove an anstest_role aaa role with normal mode + cisco.aci.aci_aaa_role: &nm_anstest_role_absent + <<: *cm_anstest_role_absent + register: nm_anstest_role_absent + +- name: Assertions check for remove an anstest_role aaa role with normal mode + assert: + that: + - nm_anstest_role_absent is changed + - nm_anstest_role_absent.current | length == 0 + - nm_anstest_role_absent.previous | length == 1 + - nm_anstest_role_absent.previous.0.aaaRole.attributes.name == 'anstest_role' + - nm_anstest_role_absent.previous.0.aaaRole.attributes.priv == 'admin' + +- name: Remove an anstest_role aaa role with normal mode - idempotency works + cisco.aci.aci_aaa_role: + <<: *nm_anstest_role_absent + register: idempotency_anstest_role_absent + +- name: Idempotency assertions check for remove an anstest_role aaa role with normal mode + assert: + that: + - idempotency_anstest_role_absent is not changed + - idempotency_anstest_role_absent.current | length == 0 + - idempotency_anstest_role_absent.previous | length == 0 diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_ssh_auth/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_ssh_auth/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_ssh_auth/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_ssh_auth/pki/sshkey.pub b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_ssh_auth/pki/sshkey.pub new file mode 100644 index 000000000..3602ccd7e --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_ssh_auth/pki/sshkey.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHL9VwXtwdyTC8lC0FAT4Ss8g0TnYJQf+zJiFlzUBiioqyblvr3w6xwgm5B5oghWag/IwK8c43rxvrW9Yn45xhU= ansible@example
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_ssh_auth/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_ssh_auth/tasks/main.yml new file mode 100644 index 000000000..46113c0f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_ssh_auth/tasks/main.yml @@ -0,0 +1,164 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, Tim Cragg (timcragg) <tcragg@cisco.com> +# Copyright: (c) 2017, Dag Wieers (dagwieers) <dag@wieers.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: '{{ aci_output_level | default("info") }}' + +# CLEAN ENVIRONMENT +- name: Remove any pre-existing user + cisco.aci.aci_aaa_user: + <<: *aci_info + aaa_user: ansible + state: absent + +# ADD USER +- name: Create AAA user + cisco.aci.aci_aaa_user: + <<: *aci_info + aaa_user: ansible + aaa_password: 12!Ab:cD!34 + state: present + + +# ADD SSH AUTH +- name: Add a new SSH Key (Check Mode) + cisco.aci.aci_aaa_ssh_auth: &ssh_key_present + <<: *aci_info + aaa_user: ansible + auth_name: ansible_key + data: "{{ lookup('file', 'pki/sshkey.pub') }}" + state: present + check_mode: true + register: cm_add_ssh_key + +- name: Add a new SSH Key (Normal Mode) + cisco.aci.aci_aaa_ssh_auth: + <<: *ssh_key_present + register: nm_add_ssh_key + +- name: Add SSH key again (Check Mode) + cisco.aci.aci_aaa_ssh_auth: + <<: *ssh_key_present + check_mode: true + register: cm_add_ssh_key_again + +- name: Add SSH key again (Normal Mode) + cisco.aci.aci_aaa_ssh_auth: + <<: *ssh_key_present + register: nm_add_ssh_key_again + +- name: Verify add SSH key + assert: + that: + - cm_add_ssh_key is changed + - nm_add_ssh_key is changed + - nm_add_ssh_key.current.0.aaaSshAuth.attributes.dn == 'uni/userext/user-ansible/sshauth-ansible_key' + - nm_add_ssh_key.current.0.aaaSshAuth.attributes.name == 'ansible_key' + - nm_add_ssh_key.current.0.aaaSshAuth.attributes.data == lookup('file', 'pki/sshkey.pub') + - cm_add_ssh_key_again is not changed + - nm_add_ssh_key_again is not changed + - nm_add_ssh_key_again.current.0.aaaSshAuth.attributes.dn == 'uni/userext/user-ansible/sshauth-ansible_key' + - nm_add_ssh_key_again.current.0.aaaSshAuth.attributes.name == 'ansible_key' + - nm_add_ssh_key_again.current.0.aaaSshAuth.attributes.data == lookup('file', 'pki/sshkey.pub') + +# QUERY ALL SSH KEYS +- name: Query all SSH keys (check mode) + cisco.aci.aci_aaa_ssh_auth: &ssh_key_query_all + <<: *aci_info + aaa_user: ansible + state: query + check_mode: true + register: cm_query_all_ssh_keys + +- name: Query all SSH keys (normal mode) + cisco.aci.aci_aaa_ssh_auth: + <<: *ssh_key_query_all + register: nm_query_all_ssh_keys + +- name: Verify query_all_ssh_keys + assert: + that: + - cm_query_all_ssh_keys is not changed + - nm_query_all_ssh_keys is not changed + +# QUERY OUR SSH KEY +- name: Query our SSH key (check mode) + cisco.aci.aci_aaa_ssh_auth: &ssh_key_query + <<: *ssh_key_query_all + auth_name: ansible_key + check_mode: true + register: cm_query_ssh_key + +- name: Query our SSH key (normal mode) + cisco.aci.aci_aaa_ssh_auth: + <<: *ssh_key_query + register: nm_query_ssh_key + +- name: Verify query_ssh_key + assert: + that: + - cm_query_ssh_key is not changed + - nm_query_ssh_key is not changed + - nm_query_ssh_key.current.0.aaaSshAuth.attributes.dn == 'uni/userext/user-ansible/sshauth-ansible_key' + - nm_query_ssh_key.current.0.aaaSshAuth.attributes.name == 'ansible_key' + - nm_query_ssh_key.current.0.aaaSshAuth.attributes.data == lookup('file', 'pki/sshkey.pub') + - cm_query_ssh_key == nm_query_ssh_key + +# REMOVE SSH KEY +- name: Remove SSH key (check mode) + cisco.aci.aci_aaa_ssh_auth: &ssh_key_absent + <<: *aci_info + aaa_user: ansible + auth_name: ansible_key + data: "{{ lookup('file', 'pki/sshkey.pub') }}" + state: absent + check_mode: true + register: cm_remove_ssh_key + +- name: Remove SSH key (normal mode) + cisco.aci.aci_aaa_ssh_auth: + <<: *ssh_key_absent + register: nm_remove_ssh_key + +- name: Remove SSH key again (check mode) + cisco.aci.aci_aaa_ssh_auth: + <<: *ssh_key_absent + check_mode: true + register: cm_remove_ssh_key_again + +- name: Remove SSH key again (normal mode) + cisco.aci.aci_aaa_ssh_auth: + <<: *ssh_key_absent + register: nm_remove_ssh_key_again + +- name: Verify remove_user + assert: + that: + - cm_remove_ssh_key is changed + - nm_remove_ssh_key is changed + - nm_remove_ssh_key.current == [] + - cm_remove_ssh_key_again is not changed + - nm_remove_ssh_key_again is not changed + +# CLEAN UP +- name: Remove user + cisco.aci.aci_aaa_user: + <<: *aci_info + aaa_user: ansible + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..56de63830 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user/tasks/main.yml @@ -0,0 +1,236 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Dag Wieers (dagwieers) <dag@wieers.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 + + +# 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 + 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 + description: Ansible test user + email: ansible@ansible.lan + enabled: true + expiration: never + expires: false + first_name: Test + last_name: User + phone: 1-234-555-678 + check_mode: true + register: cm_add_user + +# NOTE: Setting password is not idempotent, see #35544 +- name: Add user (normal mode) + cisco.aci.aci_aaa_user: + <<: *user_present + aaa_password: 12!Ab:cD!34 + register: nm_add_user + +- name: Add user again (check mode) + cisco.aci.aci_aaa_user: *user_present + check_mode: true + register: cm_add_user_again + +- name: Add user again (normal mode) + cisco.aci.aci_aaa_user: *user_present + register: nm_add_user_again + +- name: Verify add user + assert: + that: + - cm_add_user is changed + - nm_add_user is changed + - nm_add_user.current.0.aaaUser.attributes.annotation == 'orchestrator:ansible' + - nm_add_user.current.0.aaaUser.attributes.descr == 'Ansible test user' + - cm_add_user_again is not changed + - 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 + 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 + description: Ansible test user for integration tests + email: aci-ansible@ansible.lan + expiration: '2123-12-12' + expires: true + phone: 2-345-555-678 + check_mode: true + register: cm_modify_user + +- name: Modify user (normal mode) + cisco.aci.aci_aaa_user: *user_changed + register: nm_modify_user + +- name: Modify user again (check mode) + cisco.aci.aci_aaa_user: *user_changed + check_mode: true + register: cm_modify_user_again + +- name: Modify user again (normal mode) + cisco.aci.aci_aaa_user: *user_changed + register: nm_modify_user_again + +- name: Verify modify user + assert: + that: + - cm_modify_user is changed + - 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 + - nm_modify_user_again is not changed + - nm_modify_user_again.current.0.aaaUser.attributes.descr == 'Ansible test user for integration tests' + + +# CLEAR PASSWORD HISTORY +- name: Clear password history (check_mode) + cisco.aci.aci_aaa_user: &clear_password_history + 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 + clear_password_history: true + check_mode: true + register: cm_clear_password_history + +- name: Clear password history (normal mode) + cisco.aci.aci_aaa_user: *clear_password_history + register: nm_clear_password_history + +- name: Clear password history (check mode) + cisco.aci.aci_aaa_user: *clear_password_history + check_mode: true + register: cm_clear_password_history_again + +- name: Clear password history (normal mode) + cisco.aci.aci_aaa_user: *clear_password_history + register: nm_clear_password_history_again + +- name: Verify clear password history + assert: + that: + # NOTE: Clearing password history is a changing action, everytime + - cm_clear_password_history is changed + - nm_clear_password_history is changed + - cm_clear_password_history_again is changed + - nm_clear_password_history_again is changed + + +# QUERY ALL USERS +- name: Query all users (check_mode) + cisco.aci.aci_aaa_user: &user_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") }}' + aaa_user: ansible + state: query + check_mode: true + register: cm_query_all_users + +- name: Query all users (normal mode) + cisco.aci.aci_aaa_user: *user_query + register: nm_query_all_users + +- name: Verify query_all_users + assert: + that: + - cm_query_all_users is not changed + - nm_query_all_users is not changed + # NOTE: Order of users is not stable between calls + #- cm_query_all_users == nm_query_all_users + + +# QUERY OUR USER +- name: Query our user (check_mode) + cisco.aci.aci_aaa_user: + <<: *user_query + check_mode: true + register: cm_query_user + +- name: Query our user (normal mode) + cisco.aci.aci_aaa_user: + <<: *user_query + register: nm_query_user + +- name: Verify query_user + assert: + that: + - cm_query_user is not changed + - nm_query_user is not changed + - cm_query_user == nm_query_user + - nm_query_user.current.0.aaaUser.attributes.accountStatus == 'active' + - nm_query_user.current.0.aaaUser.attributes.descr == 'Ansible test user for integration tests' + - nm_query_user.current.0.aaaUser.attributes.email == 'aci-ansible@ansible.lan' + - nm_query_user.current.0.aaaUser.attributes.expiration == '2123-12-12T00:00:00.000+00:00' + - nm_query_user.current.0.aaaUser.attributes.expires == 'yes' + - nm_query_user.current.0.aaaUser.attributes.phone == '2-345-555-678' + + +# REMOVE USER +- name: Remove user (check_mode) + cisco.aci.aci_aaa_user: *user_absent + check_mode: true + register: cm_remove_user + +- name: Remove user (normal mode) + cisco.aci.aci_aaa_user: *user_absent + register: nm_remove_user + +- name: Remove user again (check_mode) + cisco.aci.aci_aaa_user: *user_absent + check_mode: true + register: cm_remove_user_again + +- name: Remove user again (normal mode) + cisco.aci.aci_aaa_user: *user_absent + register: nm_remove_user_again + +- name: Verify remove_user + assert: + that: + - cm_remove_user is changed + - nm_remove_user is changed + - cm_remove_user_again is not changed + - nm_remove_user_again is not changed diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/pki/admin.crt b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/pki/admin.crt new file mode 100644 index 000000000..cfac5531e --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/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_aaa_user_certificate/pki/admin.key b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/pki/admin.key new file mode 100644 index 000000000..63bb00cc0 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/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_aaa_user_certificate/pki/admin_invalid.key b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/pki/admin_invalid.key new file mode 100644 index 000000000..22f5fae45 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/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_aaa_user_certificate/pki/openssh_rsa.key b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/pki/openssh_rsa.key new file mode 100644 index 000000000..0c18da5c5 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/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_aaa_user_certificate/pki/rsa_ansible.key b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/pki/rsa_ansible.key new file mode 100644 index 000000000..ac63a0055 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/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_aaa_user_certificate/pki/rsa_user.crt b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/pki/rsa_user.crt new file mode 100644 index 000000000..de2223500 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/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_aaa_user_certificate/pki/rsa_user.key b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/pki/rsa_user.key new file mode 100644 index 000000000..354dbbdbb --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/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_aaa_user_certificate/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/tasks/main.yml new file mode 100644 index 000000000..9d300e4d7 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_certificate/tasks/main.yml @@ -0,0 +1,346 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Dag Wieers (dagwieers) <dag@wieers.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: Making sure current user has correct cert + cisco.aci.aci_aaa_user_certificate: + 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: '{{ aci_username }}' + name: admin + certificate: "{{ lookup('file', 'pki/admin.crt') }}" + state: present + +- name: Remove any pre-existing certificate + cisco.aci.aci_aaa_user_certificate: &cert_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: '{{ aci_username }}' + name: "{{ item }}" + state: absent + loop: + - admin + - user + - rsa_user + +# ADD USER CERTIFICATE +- name: Add user certificate (check_mode) + cisco.aci.aci_aaa_user_certificate: &cert_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") }}' + aaa_user: '{{ aci_username }}' + name: admin + certificate: "{{ lookup('file', 'pki/admin.crt') }}" + state: present + check_mode: true + register: cm_add_cert + +- name: Add user certificate (normal mode) + cisco.aci.aci_aaa_user_certificate: *cert_present + register: nm_add_cert + +- name: Add user certificate again (check mode) + cisco.aci.aci_aaa_user_certificate: *cert_present + check_mode: true + register: cm_add_cert_again + +- name: Add user certificate again (normal mode) + cisco.aci.aci_aaa_user_certificate: *cert_present + register: nm_add_cert_again + +- name: Verify add_cert + assert: + that: + - cm_add_cert is changed + - nm_add_cert is change + - nm_add_cert.current.0.aaaUserCert.attributes.annotation == 'orchestrator:ansible' + - cm_add_cert_again is not changed + - nm_add_cert_again is not changed + +- name: Add rsa_user certificates + cisco.aci.aci_aaa_user_certificate: + <<: *cert_present + name: "{{ item }}" + certificate: "{{ lookup('file', 'pki/rsa_user.crt') }}" + state: present + loop: + - user + - rsa_user + +- name: Add admin certificate with user name + cisco.aci.aci_aaa_user_certificate: + <<: *cert_present + name: '{{ aci_username }}' + state: present + +# QUERY ALL USER CERTIFICATES +- name: Query all user certificates using signature-based authentication (check_mode) + cisco.aci.aci_aaa_user_certificate: &cert_query + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + certificate_name: admin + private_key: '{{ role_path }}/pki/admin.key' + 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: '{{ aci_username }}' + state: query + check_mode: true + register: cm_query_all_certs + +- name: Query all user certificates using signature-based authentication (normal mode) + cisco.aci.aci_aaa_user_certificate: *cert_query + register: nm_query_all_certs + +- name: Verify query_all_certs + assert: + that: + - cm_query_all_certs is not changed + - nm_query_all_certs is not changed + # NOTE: Order of certs is not stable between calls + #- cm_query_all_certs == nm_query_all_certs + +- name: Query all user certificates using signature-based authentication (valid rsa private key) + cisco.aci.aci_aaa_user_certificate: + <<: *cert_query + private_key: '{{ role_path }}/pki/rsa_user.key' + certificate_name: rsa_user + register: nm_query_all_rsa + +- name: Verify nm_query_all_rsa + assert: + that: + - nm_query_all_rsa is not changed + - nm_query_all_rsa.current.0.aaaUser.children | length >= 4 + +- name: Query all certificates using signature-based authentication (private key content for admin certificate) + cisco.aci.aci_aaa_user_certificate: + <<: *cert_query + 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----- + register: nm_query_all_key_content + +# QUERY OUR USER CERTIFICATE +- name: Query our certificate using signature-based authentication (check_mode) + cisco.aci.aci_aaa_user_certificate: + <<: *cert_query + name: admin + check_mode: true + register: cm_query_cert + +- name: Query our certificate using signature-based authentication (normal mode) + cisco.aci.aci_aaa_user_certificate: + <<: *cert_query + name: admin + register: nm_query_cert + +- name: Verify query_cert + assert: + that: + - cm_query_cert is not changed + - nm_query_cert is not changed + - cm_query_cert == nm_query_cert + +- name: Query our certificate using signature-based authentication (invalid private key file) + cisco.aci.aci_aaa_user_certificate: + <<: *cert_query + private_key: '{{ role_path }}/pki/admin_invalid.key' + name: admin + register: query_cert_invalid_key + ignore_errors: true + +- name: Query our certificate using signature-based authentication (certificate file) + cisco.aci.aci_aaa_user_certificate: + <<: *cert_query + private_key: '{{ role_path }}/pki/admin.crt' + name: admin + register: query_cert_valid_key + ignore_errors: true + +- name: Query our certificate using signature-based authentication (ansible rsa private key file) + cisco.aci.aci_aaa_user_certificate: + <<: *cert_query + private_key: '{{ role_path }}/pki/rsa_ansible.key' + certificate_name: rsa_user + name: rsa_user + register: query_cert_openssh_rsa_key + ignore_errors: true + +- name: Query our certificate using signature-based authentication (valid rsa private key file) + cisco.aci.aci_aaa_user_certificate: + <<: *cert_query + private_key: '{{ role_path }}/pki/rsa_user.key' + certificate_name: rsa_user + name: "{{ item }}" + register: query_cert_ansible_rsa_key + loop: + - "rsa_user" + - "user" + +- name: Query our certificate using signature-based authentication (private key content for rsa_user certificate) + cisco.aci.aci_aaa_user_certificate: + <<: *cert_query + private_key: | + -----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----- + certificate_name: rsa_user + name: "{{ item }}" + register: query_cert_key_content + loop: + - "rsa_user" + - "user" + +# REMOVE CERTIFICATE +- name: Remove certificate (check_mode) + cisco.aci.aci_aaa_user_certificate: &cert_delete + 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: '{{ aci_username }}' + name: admin + state: absent + check_mode: true + register: cm_remove_cert + +- name: Remove certificate (normal mode) + cisco.aci.aci_aaa_user_certificate: *cert_delete + register: nm_remove_cert + +- name: Remove certificate again (check_mode) + cisco.aci.aci_aaa_user_certificate: *cert_delete + check_mode: true + register: cm_remove_cert_again + +- name: Remove certificate again (normal mode) + cisco.aci.aci_aaa_user_certificate: *cert_delete + register: nm_remove_cert_again + +- name: Verify remove_cert + assert: + that: + - cm_remove_cert is changed + - nm_remove_cert is changed + - cm_remove_cert_again is not changed + - nm_remove_cert_again is not changed + +# Checking if changing certification_name to name throws an error. (#82) +- name: Making sure current user has correct cert + aci_aaa_user_certificate: + <<: *aci_info + aaa_user: '{{ aci_username }}' + name: admin + certificate: "{{ lookup('file', 'pki/admin.crt') }}" + state: present + +- name: Remove user ansible_test + aci_aaa_user: + <<: *aci_info + aaa_user: ansible_test + state: absent + +- name: Add user ansible_test + aci_aaa_user: + <<: *aci_info + aaa_user: ansible_test + aaa_password: ansible_5351 + expiration: never + expires: false + state: present + +- name: Add user certificate + aci_aaa_user_certificate: + <<: *aci_info + aaa_user: ansible_test + name: test + certificate: "{{ lookup('file', 'pki/admin.crt') }}" + state: present + +- name: Query test certificate + aci_aaa_user_certificate: + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + certificate_name: admin + private_key: '{{ role_path }}/pki/admin.key' + aaa_user: ansible_test + name: test + state: query + register: query_test + +- name: Verify query_test + assert: + that: + - query_test is not changed + +- name: Remove user to clean environment for next test on ci + aci_aaa_user: + <<: *aci_info + aaa_user: ansible_test + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_domain/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_domain/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_domain/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_domain/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_domain/tasks/main.yml new file mode 100644 index 000000000..ac0d1d0f2 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_domain/tasks/main.yml @@ -0,0 +1,224 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, Tim Cragg (timcragg) <tcragg@cisco.com> +# Copyright: (c) 2022, Sabari Jaganathan (@sajagana) +# Copyright: (c) 2017, Dag Wieers (dagwieers) <dag@wieers.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") }}' + +# CLEAN ENVIRONMENT +- name: Remove user domain from a aaa_user + cisco.aci.aci_aaa_user_domain: + <<: *aci_info + name: anstest-security-domain + aaa_user: ansible + state: absent + +- name: Remove user domain from a aaa_user + cisco.aci.aci_aaa_user_domain: + <<: *aci_info + name: anstest-security-domain-1 + aaa_user: ansible + state: absent + +- name: Remove any pre-existing user + cisco.aci.aci_aaa_user: + <<: *aci_info + aaa_user: ansible + state: absent + +# ADD USER +- name: Add a aaa_user + cisco.aci.aci_aaa_user: &user_present + <<: *aci_info + aaa_user: ansible + aaa_password: 12!Ab:cD!34 + description: Ansible test user + email: ansible@ansible.lan + enabled: true + expiration: never + expires: false + first_name: Ansible + last_name: User + phone: 1-234-555-678 + register: add_user + +# ADD AAA USER DOMAIN +- name: Add user domain to aaa_user with check mode + cisco.aci.aci_aaa_user_domain: &cm_sec_domain_present + <<: *aci_info + name: anstest-security-domain + aaa_user: ansible + state: present + check_mode: true + register: cm_sec_domain_present + +- name: Assertions check for add user domain to aaa_user with check mode + assert: + that: + - cm_sec_domain_present is changed + - cm_sec_domain_present.current | length == 0 + - cm_sec_domain_present.previous | length == 0 + - cm_sec_domain_present.sent.aaaUserDomain.attributes.name == 'anstest-security-domain' + +- name: Add user domain to aaa_user with normal mode + cisco.aci.aci_aaa_user_domain: &nm_sec_domain_present + <<: *cm_sec_domain_present + register: nm_sec_domain_present + +- name: Assertions check for add user domain to aaa_user with normal mode + assert: + that: + - nm_sec_domain_present is changed + - nm_sec_domain_present.current | length == 1 + - nm_sec_domain_present.previous | length == 0 + - nm_sec_domain_present.current.0.aaaUserDomain.attributes.name == 'anstest-security-domain' + +- name: Add user domain to aaa_user with check mode - idempotency works + cisco.aci.aci_aaa_user_domain: + <<: *cm_sec_domain_present + check_mode: true + register: cm_idempotency_sec_domain_present + +- name: Idempotency assertions check for add user domain to aaa_user with check mode + assert: + that: + - cm_idempotency_sec_domain_present is not changed + - cm_idempotency_sec_domain_present.current | length == 1 + - cm_idempotency_sec_domain_present.previous | length == 1 + - cm_idempotency_sec_domain_present.current.0.aaaUserDomain.attributes.name == 'anstest-security-domain' + - cm_idempotency_sec_domain_present.previous.0.aaaUserDomain.attributes.name == 'anstest-security-domain' + +- name: Add user domain to aaa_user with normal mode - idempotency works + cisco.aci.aci_aaa_user_domain: + <<: *nm_sec_domain_present + register: idempotency_sec_domain_present + +- name: Idempotency assertions check for add user domain to aaa_user with normal mode + assert: + that: + - idempotency_sec_domain_present is not changed + - idempotency_sec_domain_present.current | length == 1 + - idempotency_sec_domain_present.previous | length == 1 + - idempotency_sec_domain_present.current.0.aaaUserDomain.attributes.name == 'anstest-security-domain' + - idempotency_sec_domain_present.previous.0.aaaUserDomain.attributes.name == 'anstest-security-domain' + +- name: Add list of user domains to a aaa_user + cisco.aci.aci_aaa_user_domain: + <<: *aci_info + name: "{{ item.name }}" + aaa_user: ansible + state: present + with_items: + - name: all + - name: mgmt + +# QUERY A USER DOMAIN +- name: Query a user domain from a aaa_user + cisco.aci.aci_aaa_user_domain: + <<: *aci_info + name: anstest-security-domain + aaa_user: ansible + state: query + register: query_anstest_sec_domain + +- name: Assertions check for query a user domain from a aaa_user + assert: + that: + - query_anstest_sec_domain is not changed + - query_anstest_sec_domain.current | length == 1 + - query_anstest_sec_domain.current.0.aaaUserDomain.attributes.name == 'anstest-security-domain' + +# QUERY ALL USER DOMAINS +- name: Query all user domains from a aaa_user + cisco.aci.aci_aaa_user_domain: + <<: *aci_info + aaa_user: ansible + state: query + register: query_aaa_user_domains + +- name: Assertions check for query all user domains from a aaa_user + assert: + that: + - query_aaa_user_domains is not changed + - query_aaa_user_domains.current | length == 1 + - query_aaa_user_domains.current.0.aaaUser.children | length == 4 + +- name: Query all user domains + cisco.aci.aci_aaa_user_domain: + <<: *aci_info + state: query + register: query_all_aaa_user_domains + +- name: Assertions check for query all user domains + assert: + that: + - query_all_aaa_user_domains is not changed + - query_all_aaa_user_domains.current | length >= 3 + +# REMOVE USER DOMAIN +- name: Remove user domain from a aaa_user with check mode + cisco.aci.aci_aaa_user_domain: &cm_sec_domain_absent + <<: *nm_sec_domain_present + state: absent + check_mode: true + register: cm_sec_domain_absent + +- name: Assertions check for removing user domain from a aaa_user with check mode + assert: + that: + - cm_sec_domain_absent is changed + - cm_sec_domain_absent.current | length == 1 + - cm_sec_domain_absent.current.0.aaaUserDomain.attributes.name == 'anstest-security-domain' + - cm_sec_domain_absent.previous | length == 1 + - cm_sec_domain_absent.previous.0.aaaUserDomain.attributes.name == 'anstest-security-domain' + +- name: Remove user domain from a aaa_user with normal mode + cisco.aci.aci_aaa_user_domain: &nm_sec_domain_absent + <<: *cm_sec_domain_absent + state: absent + register: nm_sec_domain_absent + +- name: Assertions check for removing user domain from a aaa_user with normal mode + assert: + that: + - nm_sec_domain_absent is changed + - nm_sec_domain_absent.current == [] + - nm_sec_domain_absent.previous | length == 1 + - nm_sec_domain_absent.previous.0.aaaUserDomain.attributes.name == 'anstest-security-domain' + +- name: Remove user domain from a aaa_user with normal mode - idempotency works + cisco.aci.aci_aaa_user_domain: + <<: *nm_sec_domain_absent + state: absent + check_mode: true + register: idempotency_sec_domain_absent + +- name: Idempotency assertions check for removing user domain + assert: + that: + - idempotency_sec_domain_absent is not changed + - idempotency_sec_domain_absent.current == [] + - idempotency_sec_domain_absent.previous == [] + +# Cleanup part +- name: Remove a aaa_user + cisco.aci.aci_aaa_user: + <<: *user_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_role/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_role/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_role/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_role/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_role/tasks/main.yml new file mode 100644 index 000000000..4a4d34017 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aaa_user_role/tasks/main.yml @@ -0,0 +1,336 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, Tim Cragg (timcragg) <tcragg@cisco.com> +# Copyright: (c) 2022, Sabari Jaganathan (@sajagana) +# Copyright: (c) 2017, Dag Wieers (dagwieers) <dag@wieers.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") }}' + +# CLEAN ENVIRONMENT +- name: Remove any pre-existing user + cisco.aci.aci_aaa_user: + <<: *aci_info + aaa_user: ansible + state: absent + +# ADD USER +- name: Add a aaa_user + cisco.aci.aci_aaa_user: &user_present + <<: *aci_info + aaa_user: ansible + aaa_password: 12!Ab:cD!34 + description: Ansible test user + email: ansible@ansible.lan + enabled: true + expiration: never + expires: false + first_name: Ansible + last_name: User + phone: 1-234-555-678 + register: add_user + +# ADD SECURITY DOMAINS +- name: Ensure anstest-security-domain exists + cisco.aci.aci_aaa_domain: + <<: *aci_info + name: anstest-security-domain + state: present + +- name: Ensure anstest-security-domain-1 exists + cisco.aci.aci_aaa_domain: + <<: *aci_info + name: anstest-security-domain-1 + state: present + +# ADD USER DOMAIN +- name: Add "anstest-security-domain" user domain to aaa_user + cisco.aci.aci_aaa_user_domain: &sec_domain_present + <<: *aci_info + name: anstest-security-domain + aaa_user: ansible + state: present + +- name: Add "anstest-security-domain-1" user domain to aaa_user + cisco.aci.aci_aaa_user_domain: &sec_domain1_present + <<: *aci_info + name: anstest-security-domain-1 + aaa_user: ansible + state: present + +# Test Part +# ADD USER ROLE +- name: Add user role to "anstest-security-domain" user domain with check mode + cisco.aci.aci_aaa_user_role: &cm_user_role_present + <<: *aci_info + aaa_user: ansible + user_domain: anstest-security-domain + name: admin + privilege_type: write + state: present + check_mode: true + register: cm_user_role_present + +- name: Assertions check for add user role to "anstest-security-domain" with check mode + assert: + that: + - cm_user_role_present is changed + - cm_user_role_present.current | length == 0 + - cm_user_role_present.previous | length == 0 + - cm_user_role_present.sent.aaaUserRole.attributes.name == 'admin' + - cm_user_role_present.sent.aaaUserRole.attributes.privType == 'writePriv' + +- name: Add user role to "anstest-security-domain" user domain with normal mode + cisco.aci.aci_aaa_user_role: &nm_user_role_present + <<: *cm_user_role_present + register: nm_user_role_present + +- name: Assertions check for add user role to "anstest-security-domain" with normal mode + assert: + that: + - nm_user_role_present is changed + - nm_user_role_present.current | length == 1 + - nm_user_role_present.previous | length == 0 + - nm_user_role_present.current.0.aaaUserRole.attributes.name == 'admin' + - nm_user_role_present.current.0.aaaUserRole.attributes.privType == 'writePriv' + +- name: Add user role to "anstest-security-domain" user domain with check mode - idempotency works + cisco.aci.aci_aaa_user_role: + <<: *nm_user_role_present + check_mode: true + register: cm_idempotency_user_role_present + +- name: Idempotency assertions check for add user role to "anstest-security-domain" check mode + assert: + that: + - cm_idempotency_user_role_present is not changed + - cm_idempotency_user_role_present.previous | length == 1 + - cm_idempotency_user_role_present.current | length == 1 + - cm_idempotency_user_role_present.current.0.aaaUserRole.attributes.name == 'admin' + - cm_idempotency_user_role_present.current.0.aaaUserRole.attributes.privType == 'writePriv' + - cm_idempotency_user_role_present.previous.0.aaaUserRole.attributes.name == 'admin' + - cm_idempotency_user_role_present.previous.0.aaaUserRole.attributes.privType == 'writePriv' + +- name: Add user role to "anstest-security-domain" user domain with normal mode - idempotency works + cisco.aci.aci_aaa_user_role: + <<: *nm_user_role_present + register: idempotency_user_role_present + +- name: Idempotency assertions check for add user role to "anstest-security-domain" + assert: + that: + - idempotency_user_role_present is not changed + - idempotency_user_role_present.previous | length == 1 + - idempotency_user_role_present.current | length == 1 + - idempotency_user_role_present.current.0.aaaUserRole.attributes.name == 'admin' + - idempotency_user_role_present.current.0.aaaUserRole.attributes.privType == 'writePriv' + - idempotency_user_role_present.previous.0.aaaUserRole.attributes.name == 'admin' + - idempotency_user_role_present.previous.0.aaaUserRole.attributes.privType == 'writePriv' + +- name: Add user role to "anstest-security-domain-1" user domain + cisco.aci.aci_aaa_user_role: + <<: *aci_info + aaa_user: ansible + user_domain: anstest-security-domain-1 + name: admin + state: present + register: user_role_present_sec_domain1 + +- name: Assertions check for add a user role to "anstest-security-domain-1" + assert: + that: + - user_role_present_sec_domain1 is changed + - user_role_present_sec_domain1.current | length == 1 + - user_role_present_sec_domain1.previous | length == 0 + - user_role_present_sec_domain1.current.0.aaaUserRole.attributes.name == 'admin' + - user_role_present_sec_domain1.current.0.aaaUserRole.attributes.privType == 'readPriv' + +# UPDATE USER ROLE +- name: Update user role to "anstest-security-domain" user domain with check mode + cisco.aci.aci_aaa_user_role: + <<: *nm_user_role_present + privilege_type: read + check_mode: true + register: cm_update_user_role_present + +- name: Assertions check for update user role to "anstest-security-domain" with check mode + assert: + that: + - cm_update_user_role_present is changed + - cm_update_user_role_present.current | length == 1 + - cm_update_user_role_present.previous | length == 1 + - cm_update_user_role_present.sent.aaaUserRole.attributes.privType == 'readPriv' + +- name: Update user role to "anstest-security-domain" user domain with normal mode + cisco.aci.aci_aaa_user_role: + <<: *nm_user_role_present + privilege_type: read + register: update_user_role_present + +- name: Assertions check for update user role to "anstest-security-domain" with normal mode + assert: + that: + - update_user_role_present is changed + - update_user_role_present.current | length == 1 + - update_user_role_present.previous | length == 1 + - update_user_role_present.current.0.aaaUserRole.attributes.name == 'admin' + - update_user_role_present.current.0.aaaUserRole.attributes.privType == 'readPriv' + +- name: Add list of user roles to a user domain + cisco.aci.aci_aaa_user_role: + <<: *aci_info + aaa_user: ansible + user_domain: anstest-security-domain + name: "{{ item.name }}" + privilege_type: "{{ item.privilege_type }}" + state: present + with_items: + - name: aaa + privilege_type: write + - name: access-admin + privilege_type: write + - name: ops + privilege_type: write + +# QUERY USER ROLE +- name: Query a user role from "anstest-security-domain-1" user domain + cisco.aci.aci_aaa_user_role: + <<: *aci_info + user_domain: anstest-security-domain-1 + name: admin + state: query + register: query_user_role_from_sec_domain + +- name: Assertions check for query a user role from "anstest-security-domain-1" user domain + assert: + that: + - query_user_role_from_sec_domain is not changed + - query_user_role_from_sec_domain.current | length == 1 + - query_user_role_from_sec_domain.current.0.aaaUserDomain.children | length == 1 + - query_user_role_from_sec_domain.current.0.aaaUserDomain.children.0.aaaUserRole.attributes.name == 'admin' + - query_user_role_from_sec_domain.current.0.aaaUserDomain.children.0.aaaUserRole.attributes.privType == 'readPriv' + +# QUERY ALL USER ROLES +- name: Query all user roles from "anstest-security-domain" user domain + cisco.aci.aci_aaa_user_role: + <<: *aci_info + aaa_user: ansible + user_domain: anstest-security-domain + state: query + register: query_all_user_roles_of_sec_domain + +- name: Assertions check for query all user roles from "anstest-security-domain" user domain + assert: + that: + - query_all_user_roles_of_sec_domain is not changed + - query_all_user_roles_of_sec_domain.current | length == 1 + - query_all_user_roles_of_sec_domain.current.0.aaaUserDomain.attributes.name == 'anstest-security-domain' + - query_all_user_roles_of_sec_domain.current.0.aaaUserDomain.children | length == 4 + +- name: Query all user roles from a user + cisco.aci.aci_aaa_user_role: + <<: *aci_info + aaa_user: ansible + state: query + register: query_all_user_roles_from_a_user + +- name: Assertions check for query all user roles from a user + assert: + that: + - query_all_user_roles_from_a_user is not changed + - query_all_user_roles_from_a_user.current | length == 1 + - query_all_user_roles_from_a_user.current.0.aaaUser.attributes.name == 'ansible' + - query_all_user_roles_from_a_user.current.0.aaaUser.children | length == 3 # count of user domains including common + +- name: Query all user roles + cisco.aci.aci_aaa_user_role: + <<: *aci_info + state: query + register: query_all_user_roles + +- name: Assertions check for query all user roles + assert: + that: + - query_all_user_roles is not changed + - query_all_user_roles.current | length >= 6 # count of user roles including common sec domain user role + +# REMOVE USER ROLE +- name: Remove user role from a user domain with check mode + cisco.aci.aci_aaa_user_role: &cm_user_role_absent + <<: *aci_info + aaa_user: ansible + user_domain: anstest-security-domain-1 + name: admin + state: absent + check_mode: true + register: cm_user_role_absent + +- name: Assertions check for removing a user role from "anstest-security-domain-1" with check mode + assert: + that: + - cm_user_role_absent is changed + - cm_user_role_absent.current | length == 1 + - cm_user_role_absent.current.0.aaaUserRole.attributes.name == 'admin' + - cm_user_role_absent.current.0.aaaUserRole.attributes.privType == 'readPriv' + - cm_user_role_absent.previous | length == 1 + - cm_user_role_absent.previous.0.aaaUserRole.attributes.name == 'admin' + - cm_user_role_absent.previous.0.aaaUserRole.attributes.privType == 'readPriv' + +- name: Remove user role from a user domain with normal mode + cisco.aci.aci_aaa_user_role: &nm_user_role_absent + <<: *cm_user_role_absent + register: nm_user_role_absent + +- name: Assertions check for removing a user role from "anstest-security-domain-1" with normal mode + assert: + that: + - nm_user_role_absent is changed + - nm_user_role_absent.current == [] + - nm_user_role_absent.previous | length == 1 + - nm_user_role_absent.previous.0.aaaUserRole.attributes.name == 'admin' + - nm_user_role_absent.previous.0.aaaUserRole.attributes.privType == 'readPriv' + +- name: Remove user role from a user domain with normal mode - idempotency works + cisco.aci.aci_aaa_user_role: + <<: *nm_user_role_absent + register: idempotency_user_role_absent + +- name: Idempotency assertions check for removing a user role from "anstest-security-domain-1" + assert: + that: + - idempotency_user_role_absent is not changed + - idempotency_user_role_absent.current == [] + - idempotency_user_role_absent.previous == [] + +# Cleanup part +- name: Remove aaa_user "ansible" + cisco.aci.aci_aaa_user: + <<: *user_present + state: absent + +- name: Remove anstest-security-domain domain + cisco.aci.aci_aaa_domain: + <<: *aci_info + name: anstest-security-domain + state: absent + +- name: Remove anstest-security-domain-1 domain + cisco.aci.aci_aaa_domain: + <<: *aci_info + name: anstest-security-domain-1 + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_access_port_block_to_access_port/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_port_block_to_access_port/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_port_block_to_access_port/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_port_block_to_access_port/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_port_block_to_access_port/tasks/main.yml new file mode 100644 index 000000000..38bda95c8 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_port_block_to_access_port/tasks/main.yml @@ -0,0 +1,261 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Shreyas Srish <ssrish@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) + +- 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 + block: # block specifies execution of tasks within, based on conditions + - name: Ensuring Interface Policy Leaf profile does not exist + cisco.aci.aci_interface_policy_leaf_profile: &aci_interface_policy_leaf_profile_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 + state: absent + leaf_interface_profile: leafintprftest + register: leaf_profile_present + + - name: Ensuring Interface Policy Leaf profile does not exist on fex + cisco.aci.aci_interface_policy_leaf_profile: + <<: *aci_interface_policy_leaf_profile_absent + type: fex + leaf_interface_profile: leafintprftest_fex + + - name: Ensuring Interface Policy Leaf profile exists for kick off + cisco.aci.aci_interface_policy_leaf_profile: + <<: *aci_interface_policy_leaf_profile_absent + leaf_interface_profile: leafintprftest + state: present + + - name: Ensuring Interface Policy Leaf profile exists for kick off + cisco.aci.aci_interface_policy_leaf_profile: + <<: *aci_interface_policy_leaf_profile_absent + type: fex + leaf_interface_profile: leafintprftest_fex + state: present + + - name: Ensure Interface Access Port Selector exists for kick of + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: &aci_access_port_to_interface_policy_leaf_profile_present + <<: *aci_interface_policy_leaf_profile_absent + access_port_selector: anstest_accessportselector + state: present + + - name: Ensure Interface Access Port Selector exists for kick of + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_access_port_to_interface_policy_leaf_profile_present + type: fex + leaf_interface_profile: leafintprftest_fex + access_port_selector: anstest_accessportselector_fex + + # TODO: Ensure that leaf Policy Group Exists (module missing) (infra:AccPortGrp) + # Ensure block does not exist. + - name: Bind an Access Port Block to an Interface Access Port Selector - check mode works + cisco.aci.aci_access_port_block_to_access_port: + <<: *aci_access_port_to_interface_policy_leaf_profile_present + leaf_port_blk: anstest_leafportblkname + state: absent + + - name: Bind an Access Port Block to an Interface Access Port Selector - check mode works + cisco.aci.aci_access_port_block_to_access_port: &aci_access_port_block_to_access_port_present + <<: *aci_access_port_to_interface_policy_leaf_profile_present + leaf_port_blk: anstest_leafportblkname + leaf_port_blk_description: anstest_leafportblkdesc + fromPort: 13 + toPort: 16 + check_mode: true + register: accessportblock_to_accessport_check_mode_present + + - name: Bind an Access Port Block to an Interface Access Port Selector - creation works + cisco.aci.aci_access_port_block_to_access_port: + <<: *aci_access_port_block_to_access_port_present + register: accessportblock_to_accessport_present + + - name: Bind an Access Port Block to an Interface Access Port Selector - 2 + cisco.aci.aci_access_port_block_to_access_port: + <<: *aci_access_port_block_to_access_port_present + leaf_port_blk: anstest_leafportblkname_2 + leaf_port_blk_description: anstest_leafportblkdesc + fromPort: 25 + toPort: 26 + register: accessportblock_to_accessport_check_mode_present_2 + + - name: Bind an Access Port Block to an Interface Access Port Selector - idempotency works + cisco.aci.aci_access_port_block_to_access_port: + <<: *aci_access_port_block_to_access_port_present + register: accessportblock_to_accessport_idempotent + + - name: Bind an Access Port Block to an Interface Access Port Selector - update works + cisco.aci.aci_access_port_block_to_access_port: + <<: *aci_access_port_block_to_access_port_present + toPort: 15 + register: accessportblock_to_accessport_update + + - name: Associate an access port block (single port) to an interface selector on a fex - creation works + cisco.aci.aci_access_port_block_to_access_port: + <<: *aci_access_port_block_to_access_port_present + type: fex + leaf_interface_profile: leafintprftest_fex + access_port_selector: anstest_accessportselector_fex + leaf_port_blk_description: anstest_leafportblkdesc_fex + leaf_port_blk: fex_blk + fromPort: 14 + toPort: 17 + register: accessportblock_to_accessport_present_fex + + - name: Associate an access port block (single port) to an interface selector on a fex - creation works 2 + cisco.aci.aci_access_port_block_to_access_port: + <<: *aci_access_port_block_to_access_port_present + type: fex + leaf_interface_profile: leafintprftest_fex + access_port_selector: anstest_accessportselector_fex + leaf_port_blk_description: anstest_leafportblkdesc_fex_2 + leaf_port_blk: fex_blk_2 + fromPort: 20 + toPort: 21 + register: accessportblock_to_accessport_present_fex_2 + + + - name: Associate an access port block (single port) to an interface selector on a fex - idempotency works + cisco.aci.aci_access_port_block_to_access_port: + <<: *aci_access_port_block_to_access_port_present + type: fex + leaf_interface_profile: leafintprftest_fex + access_port_selector: anstest_accessportselector_fex + leaf_port_blk_description: anstest_leafportblkdesc_fex + leaf_port_blk: fex_blk + fromPort: 14 + toPort: 17 + register: accessportblock_to_accessport_present_fex_idemp + + - name: Associate an access port block (single port) to an interface selector on a fex - update works + cisco.aci.aci_access_port_block_to_access_port: + <<: *aci_access_port_block_to_access_port_present + type: fex + leaf_interface_profile: leafintprftest_fex + access_port_selector: anstest_accessportselector_fex + leaf_port_blk_description: anstest_leafportblkdesc_fex + leaf_port_blk: fex_blk + fromPort: 23 + toPort: 24 + register: accessportblock_to_accessport_present_fex_update + + # TODO: also test for errors + - name: present assertions - create / indempotency / update works + assert: + that: + - accessportblock_to_accessport_check_mode_present is changed + - accessportblock_to_accessport_present is changed + - accessportblock_to_accessport_present.current.0.infraPortBlk.attributes.annotation == 'orchestrator:ansible' + - accessportblock_to_accessport_present.previous == [] + - accessportblock_to_accessport_present.sent.infraPortBlk.attributes.descr == 'anstest_leafportblkdesc' + - accessportblock_to_accessport_present.sent.infraPortBlk.attributes.name == 'anstest_leafportblkname' + - accessportblock_to_accessport_present.sent.infraPortBlk.attributes.fromPort == '13' + - accessportblock_to_accessport_present.sent.infraPortBlk.attributes.toPort == '16' + - accessportblock_to_accessport_idempotent is not changed + - accessportblock_to_accessport_idempotent.sent == {} + - accessportblock_to_accessport_update is changed + - accessportblock_to_accessport_update.sent.infraPortBlk.attributes.toPort == '15' + - accessportblock_to_accessport_present_fex is changed + - accessportblock_to_accessport_present_fex_idemp is not changed + - accessportblock_to_accessport_present_fex.sent.infraPortBlk.attributes.descr == 'anstest_leafportblkdesc_fex' + - accessportblock_to_accessport_present_fex.sent.infraPortBlk.attributes.fromPort == '14' + - accessportblock_to_accessport_present_fex.sent.infraPortBlk.attributes.toPort == '17' + - accessportblock_to_accessport_present_fex_update.sent.infraPortBlk.attributes.toPort == '24' + + - name: Query Specific port block and access_port_selector binding + cisco.aci.aci_access_port_block_to_access_port: + <<: *aci_access_port_block_to_access_port_present + state: query + register: binding_query + + - name: Query Specific port block and access_port_selector binding fex + cisco.aci.aci_access_port_block_to_access_port: + <<: *aci_access_port_block_to_access_port_present + type: fex + leaf_interface_profile: leafintprftest_fex + access_port_selector: anstest_accessportselector_fex + leaf_port_blk: fex_blk + state: query + register: binding_query_fex + + - name: query assertions + assert: + that: + - binding_query is not changed + - binding_query_fex is not changed + - binding_query_fex.current | length >= 1 + - binding_query.current | length >= 1 + - '"api/mo/uni/infra/accportprof-leafintprftest/hports-anstest_accessportselector-typ-range/portblk-anstest_leafportblkname.json" in binding_query.url' + + - name: Remove binding of Access Port Block and Interface Access Port Selector - check mode + cisco.aci.aci_access_port_block_to_access_port: &aci_access_port_block_to_access_port_absent + <<: *aci_access_port_block_to_access_port_present + state: absent + check_mode: true + register: accessportblock_to_accessport_check_mode_absent + + - name: Remove binding of Access Port Block and Interface Access Port Selector - delete works + cisco.aci.aci_access_port_block_to_access_port: + <<: *aci_access_port_block_to_access_port_absent + register: accessportblock_to_accessport_absent + + - name: Remove binding of Access Port Block and Interface Access Port Selector - idempotency works + cisco.aci.aci_access_port_block_to_access_port: + <<: *aci_access_port_block_to_access_port_absent + register: accessportblock_to_accessport_absent_idempotent + + - name: Remove binding of Access Port Block and Interface Access Port Selector - check mode + cisco.aci.aci_access_port_block_to_access_port: + <<: *aci_access_port_to_interface_policy_leaf_profile_present + #leaf_port_blk: anstest_leafportblkname + state: absent + ignore_errors: true + register: accessportblock_to_accessport_absent_missing_param + + - name: Remove binding of Access Port Block and Interface Access Port Selector - delete works + cisco.aci.aci_access_port_block_to_access_port: + <<: *aci_access_port_block_to_access_port_absent + type: fex + leaf_interface_profile: leafintprftest_fex + access_port_selector: anstest_accessportselector_fex + leaf_port_blk: fex_blk + state: absent + register: accessportblock_to_accessport_absent_fex + + + - name: absent assertions + assert: + that: + - accessportblock_to_accessport_check_mode_absent is changed + - accessportblock_to_accessport_check_mode_absent.previous != [] + - accessportblock_to_accessport_absent is changed + - accessportblock_to_accessport_absent.previous == accessportblock_to_accessport_check_mode_absent.previous + - accessportblock_to_accessport_absent_idempotent is not changed + - accessportblock_to_accessport_absent_idempotent.previous == [] + - accessportblock_to_accessport_absent_missing_param is failed + - 'accessportblock_to_accessport_absent_missing_param.msg == "state is absent but all of the following are missing: port_blk"' + - accessportblock_to_accessport_absent_fex is changed + + - name: Ensuring Interface Policy Leaf profile does not exist + cisco.aci.aci_interface_policy_leaf_profile: + <<: *aci_interface_policy_leaf_profile_absent + leaf_interface_profile: leafintprftest + + - name: Ensuring Interface Policy Leaf profile does not exist on fex + cisco.aci.aci_interface_policy_leaf_profile: + <<: *aci_interface_policy_leaf_profile_absent + type: fex + leaf_interface_profile: leafintprftest_fex
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_access_port_to_interface_policy_leaf_profile/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_port_to_interface_policy_leaf_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_port_to_interface_policy_leaf_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_access_port_to_interface_policy_leaf_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_port_to_interface_policy_leaf_profile/tasks/main.yml new file mode 100644 index 000000000..2244e0b16 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_port_to_interface_policy_leaf_profile/tasks/main.yml @@ -0,0 +1,728 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Shreyas Srish <ssrish@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) + +- 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 execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Remove Interface policy leaf profile - Cleanup + cisco.aci.aci_interface_policy_leaf_profile: + &aci_interface_policy_leaf_profile_absent + <<: *aci_info + leaf_interface_profile: leafintprftest + state: absent + + - name: Remove Interface policy fex profile - Cleanup + cisco.aci.aci_interface_policy_leaf_profile: + <<: *aci_interface_policy_leaf_profile_absent + type: fex + leaf_interface_profile: fexintprftest + state: absent + + - name: Ensuring bindings do not already exist + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + &aci_access_port_to_interface_policy_leaf_profile_absent + <<: *aci_info + leaf_interface_profile: leafintprftest + access_port_selector: anstest_accessportselector + state: absent + + - name: Ensuring bindings do not already exist + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_access_port_to_interface_policy_leaf_profile_absent + leaf_interface_profile: leafintprftest_fex + access_port_selector: anstest_accessportselector_fex + state: absent + + - name: Ensuring Interface Policy Leaf profile exists for kick off + cisco.aci.aci_interface_policy_leaf_profile: + &aci_interface_policy_leaf_profile_present + <<: *aci_info + state: present + leaf_interface_profile: leafintprftest + register: leaf_profile_present + + - name: Ensuring Interface Policy Fex profile exists for kick off + cisco.aci.aci_interface_policy_leaf_profile: + <<: *aci_interface_policy_leaf_profile_present + type: fex + leaf_interface_profile: fexintprftest + + - name: Add a new fex policy group to the fexintprftest fex profile + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + &fexintprftest_policy_group_present + <<: *aci_info + policy_group: fexintprftest + fex_profile: fexintprftest + state: present + register: fexintprftest_policy_group_present + + - name: Assertions check for remove fex policy group from the fexintprftest fex profile + assert: + that: + - fexintprftest_policy_group_present is changed + - fexintprftest_policy_group_present.current | length == 1 + - fexintprftest_policy_group_present.previous | length == 0 + - fexintprftest_policy_group_present.current.0.infraFexBndlGrp.attributes.name == "fexintprftest" + - fexintprftest_policy_group_present.current.0.infraFexBndlGrp.attributes.dn == "uni/infra/fexprof-fexintprftest/fexbundle-fexintprftest" + + # TODO: Ensure that leaf Policy Group Exists (module missing) (infra:AccPortGrp) + + - name: Bind an Interface Access Port Selector to an Interface Policy Leaf Profile with a Policy Group - check mode works + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + &aci_access_port_to_interface_policy_leaf_profile_present + <<: *aci_interface_policy_leaf_profile_present + access_port_selector: anstest_accessportselector + check_mode: true + register: accessport_to_intf_check_mode_present + + - name: Bind an Interface Access Port Selector to an Interface Policy Leaf Profile with a Policy Group - creation works + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_access_port_to_interface_policy_leaf_profile_present + register: accessport_to_intf_present + + - name: Bind an Interface Access Port Selector to an Interface Policy Leaf Profile with a Policy Group - idempotency works + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_access_port_to_interface_policy_leaf_profile_present + register: accessport_to_intf_idempotent + + - name: Bind an Interface Access Port Selector to an Interface Policy Profile with a Policy Group - update works + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_access_port_to_interface_policy_leaf_profile_present + policy_group: anstest_policygroupname + register: accessport_to_intf_update + + - name: Bind an Interface Access Port Selector to an Interface Policy Fex Profile with a Policy Group - creation works + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_access_port_to_interface_policy_leaf_profile_present + type: fex + access_port_selector: anstest_fex_accessportselector + leaf_interface_profile: fexintprftest + register: accessport_to_intf_present_fex + + - name: Bind an Interface Access Port Selector to an Interface Policy Fex Profile with a Policy Group - idempotency works + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_access_port_to_interface_policy_leaf_profile_present + type: fex + access_port_selector: anstest_fex_accessportselector + leaf_interface_profile: fexintprftest + register: accessport_to_intf_idempotent_fex + + - name: Bind an Interface Access Port Selector to an Interface Policy Fex Profile with a Policy Group - update works + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_access_port_to_interface_policy_leaf_profile_present + policy_group: anstest_fex_policygroupname + access_port_selector: anstest_fex_accessportselector + type: fex + leaf_interface_profile: fexintprftest + register: accessport_to_intf_update_fex + + # TODO: also test for errors + - name: present assertions + assert: + that: + - accessport_to_intf_check_mode_present is changed + - accessport_to_intf_present is changed + - accessport_to_intf_present.current.0.infraHPortS.attributes.annotation == 'orchestrator:ansible' + - accessport_to_intf_present.previous == [] + - accessport_to_intf_present.sent.infraHPortS.attributes.name == 'anstest_accessportselector' + - accessport_to_intf_idempotent is not changed + - accessport_to_intf_idempotent.sent == {} + - accessport_to_intf_update is changed + - accessport_to_intf_update.sent.infraHPortS.attributes == {} + - accessport_to_intf_update.sent.infraHPortS.children[0].infraRsAccBaseGrp.attributes.tDn == 'uni/infra/funcprof/accportgrp-anstest_policygroupname' + - accessport_to_intf_present_fex is changed + - accessport_to_intf_present_fex.previous == [] + - accessport_to_intf_present_fex.sent.infraHPortS.attributes.name == 'anstest_fex_accessportselector' + - accessport_to_intf_idempotent_fex is not changed + - accessport_to_intf_idempotent_fex.sent == {} + - accessport_to_intf_update_fex is changed + - accessport_to_intf_update_fex.sent.infraHPortS.children[0].infraRsAccBaseGrp.attributes.tDn == 'uni/infra/funcprof/accportgrp-anstest_fex_policygroupname' + + - name: Query Specific access_port_selector and leaf_interface_profile binding + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_interface_policy_leaf_profile_present + access_port_selector: anstest_accessportselector # "{{ fake_var | default(omit) }}" ? + state: query + output_level: debug + register: binding_query + + - name: Query Specific access_port_selector and fex_interface_profile binding + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_interface_policy_leaf_profile_present + type: fex + access_port_selector: anstest_fex_accessportselector + leaf_interface_profile: fexintprftest + state: query + output_level: debug + register: binding_query_fex + + - name: present assertions + assert: + that: + - binding_query is not changed + - binding_query_fex is not changed + - binding_query.current | length >= 1 + - '"api/mo/uni/infra/accportprof-leafintprftest/hports-anstest_accessportselector-typ-range.json" in binding_query.url' + + - name: Bind anstest_fex_accessportselector with fexintprftest - Fex Profile Policy Group + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_info + state: present + leaf_interface_profile: leafintprftest + fex_profile: fexintprftest + policy_group: fexintprftest + access_port_selector_name: anstest_fex_accessportselector + interface_type: fex_profile + from_port: 13 + to_port: 13 + port_blk: block2 + fex_id: 105 + register: bind_fexintprftest_policy_group + + - name: Assertions check for bind anstest_fex_accessportselector with fexintprftest - Fex Profile Policy Group + assert: + that: + - bind_fexintprftest_policy_group is changed + - bind_fexintprftest_policy_group.previous | length == 0 + - bind_fexintprftest_policy_group.current.0.infraHPortS.attributes.name == "anstest_fex_accessportselector" + - bind_fexintprftest_policy_group.current.0.infraHPortS.children.1.infraRsAccBaseGrp.attributes.fexId == "105" + - bind_fexintprftest_policy_group.current.0.infraHPortS.children.1.infraRsAccBaseGrp.attributes.tDn == "uni/infra/fexprof-fexintprftest/fexbundle-fexintprftest" + + - name: Bind anstest_fex_accessportselector_2 without fex_profile + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_info + state: present + leaf_interface_profile: leafintprftest + policy_group: fexintprftest + access_port_selector_name: anstest_fex_accessportselector_2 + interface_type: fex_profile + from_port: 14 + to_port: 14 + port_blk: block2 + fex_id: 106 + register: bind_fexintprftest_policy_group_2 + + - name: Assertions check for bind anstest_fex_accessportselector with fexintprftest - Fex Profile Policy Group + assert: + that: + - bind_fexintprftest_policy_group_2 is changed + - bind_fexintprftest_policy_group_2.previous | length == 0 + - bind_fexintprftest_policy_group_2.current.0.infraHPortS.attributes.name == "anstest_fex_accessportselector_2" + - bind_fexintprftest_policy_group_2.current.0.infraHPortS.children.1.infraRsAccBaseGrp.attributes.fexId == "106" + - bind_fexintprftest_policy_group_2.current.0.infraHPortS.children.1.infraRsAccBaseGrp.attributes.tDn == "uni/infra/fexprof-fexintprftest/fexbundle-fexintprftest" + + - name: Remove fex policy group from the fexintprftest fex profile + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + <<: *fexintprftest_policy_group_present + state: absent + register: fexintprftest_policy_group_absent + + - name: Assertions check for remove fex policy group from the fexintprftest fex profile + assert: + that: + - fexintprftest_policy_group_absent is changed + - fexintprftest_policy_group_absent.current | length == 0 + - fexintprftest_policy_group_absent.previous | length == 1 + - fexintprftest_policy_group_absent.previous.0.infraFexBndlGrp.attributes.name == "fexintprftest" + - fexintprftest_policy_group_absent.previous.0.infraFexBndlGrp.attributes.dn == "uni/infra/fexprof-fexintprftest/fexbundle-fexintprftest" + + - name: Remove binding of interface access port selector and Interface Policy Leaf Profile - check mode + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_access_port_to_interface_policy_leaf_profile_absent + check_mode: true + register: accessport_to_intf_check_mode_absent + + - name: Remove binding of interface access port selector and Interface Policy Leaf Profile - delete works + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_access_port_to_interface_policy_leaf_profile_absent + register: accessport_to_intf_absent + + - name: Remove binding of interface access port selector and Interface Policy Leaf Profile - idempotency works + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_access_port_to_interface_policy_leaf_profile_absent + register: accessport_to_intf_absent_idempotent + + - name: Remove binding of interface access port selector and Interface Policy Fex Profile + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_access_port_to_interface_policy_leaf_profile_absent + type: fex + access_port_selector: anstest_fex_accessportselector + leaf_interface_profile: fexintprftest + state: absent + register: accessport_to_intf_absent_fex + + - name: absent assertions + assert: + that: + - accessport_to_intf_check_mode_absent is changed + - accessport_to_intf_absent_fex is changed + - accessport_to_intf_absent is changed + - accessport_to_intf_absent_idempotent is not changed + + - name: Remove Interface policy fex profile - Cleanup + cisco.aci.aci_interface_policy_leaf_profile: + <<: *aci_interface_policy_leaf_profile_absent + + - name: Remove Interface policy fex profile - Cleanup + cisco.aci.aci_interface_policy_leaf_profile: + <<: *aci_interface_policy_leaf_profile_absent + type: fex + leaf_interface_profile: fexintprftest + state: absent + + - name: Add anstest_fex_port_channel - Interface Policy Leaf Profile with type Fex + cisco.aci.aci_interface_policy_leaf_profile: &anstest_fex_port_channel_present + <<: *aci_interface_policy_leaf_profile_present + type: fex + leaf_interface_profile: anstest_fex_port_channel + + - name: Add policygroupname_link_fpc - Policy Group with lag type link + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_info + policy_group: policygroupname_link_fpc + lag_type: link + link_level_policy: link_level_policy + fibre_channel_interface_policy: fiber_channel_policy + state: present + + - name: Bind anstest_fex_port_channel Access Port Selector with policygroupname_link_fpc Policy Group - check mode + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: &cm_fpc_present + <<: *anstest_fex_port_channel_present + interface_type: fex_port_channel + access_port_selector: anstest_fex_port_channel + policy_group: policygroupname_link_fpc + check_mode: true + register: cm_fpc_present + + - name: Assertion check for bind anstest_fex_port_channel Access Port Selector with policygroupname_link_fpc Policy Group - check mode + assert: + that: + - cm_fpc_present.current | length == 0 + - cm_fpc_present.previous | length == 0 + - cm_fpc_present.sent.infraHPortS.attributes.name == "anstest_fex_port_channel" + - cm_fpc_present.sent.infraHPortS.children.0.infraRsAccBaseGrp.attributes.tDn == "uni/infra/funcprof/accbundle-policygroupname_link_fpc" + + - name: Bind anstest_fex_port_channel Access Port Selector with policygroupname_link_fpc Policy Group - normal mode + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: &nm_fpc_present + <<: *cm_fpc_present + register: nm_fpc_present + + - name: Assertion check for bind anstest_fex_port_channel Access Port Selector with policygroupname_link_fpc Policy Group - normal mode + assert: + that: + - nm_fpc_present.current | length == 1 + - nm_fpc_present.previous | length == 0 + - nm_fpc_present.current.0.infraHPortS.attributes.name == "anstest_fex_port_channel" + - nm_fpc_present.current.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.tDn == "uni/infra/funcprof/accbundle-policygroupname_link_fpc" + - nm_fpc_present.current.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.fexId == "101" + + - name: Remove anstest_fex_port_channel Access Port Selector with policygroupname_link_fpc Policy Group - check mode + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: &cm_fpc_absent + <<: *nm_fpc_present + state: absent + check_mode: true + register: cm_fpc_absent + + - name: Assertion check for remove anstest_fex_port_channel Access Port Selector with policygroupname_link_fpc Policy Group - check mode + assert: + that: + - cm_fpc_absent.current | length == 1 + - cm_fpc_absent.previous | length == 1 + - cm_fpc_absent.current.0.infraHPortS.attributes.name == "anstest_fex_port_channel" + - cm_fpc_absent.previous.0.infraHPortS.attributes.name == "anstest_fex_port_channel" + - cm_fpc_absent.current.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.tDn == "uni/infra/funcprof/accbundle-policygroupname_link_fpc" + - cm_fpc_absent.previous.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.tDn == "uni/infra/funcprof/accbundle-policygroupname_link_fpc" + - cm_fpc_absent.current.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.fexId == "101" + - cm_fpc_absent.previous.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.fexId == "101" + + - name: Remove anstest_fex_port_channel Access Port Selector with policygroupname_link_fpc Policy Group - normal mode + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *cm_fpc_absent + register: nm_fpc_absent + + - name: Assertion check for remove anstest_fex_port_channel Access Port Selector with policygroupname_link_fpc Policy Group - normal mode + assert: + that: + - nm_fpc_absent.current | length == 0 + - nm_fpc_absent.previous | length == 1 + - nm_fpc_absent.previous.0.infraHPortS.attributes.name == "anstest_fex_port_channel" + - nm_fpc_absent.previous.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.tDn == "uni/infra/funcprof/accbundle-policygroupname_link_fpc" + - nm_fpc_absent.previous.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.fexId == "101" + + - name: Add anstest_fex_vpc - Interface Policy Leaf Profile with type Fex + cisco.aci.aci_interface_policy_leaf_profile: &anstest_fex_vpc + <<: *aci_interface_policy_leaf_profile_present + type: fex + leaf_interface_profile: anstest_fex_vpc + register: anstest_fex_vpc_present + + - name: Assertion check for add anstest_fex_vpc - Interface Policy Leaf Profile with type Fex + assert: + that: + - anstest_fex_vpc_present.current | length == 1 + - anstest_fex_vpc_present.current.0.infraFexP.attributes.name == "anstest_fex_vpc" + - anstest_fex_vpc_present.current.0.infraFexP.attributes.dn == "uni/infra/fexprof-anstest_fex_vpc" + + - name: Add policygroupname_node_fvpc - Policy Group with lag type node + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_info + policy_group: policygroupname_node_fvpc + lag_type: node + link_level_policy: link_level_policy + fibre_channel_interface_policy: fiber_channel_policy + state: present + register: policygroupname_node_fvpc_present + + - name: Assertion check for add policygroupname_node_fvpc - Policy Group with lag type node + assert: + that: + - policygroupname_node_fvpc_present.current | length == 1 + - policygroupname_node_fvpc_present.current.0.infraAccBndlGrp.attributes.name == "policygroupname_node_fvpc" + - policygroupname_node_fvpc_present.current.0.infraAccBndlGrp.attributes.lagT == "node" + + - name: Bind anstest_fex_vpc Access Port Selector with policygroupname_node_fvpc Policy Group - check mode + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + &cm_fex_vpc_present + <<: *anstest_fex_vpc + interface_type: fex_vpc + access_port_selector: anstest_fex_vpc + policy_group: policygroupname_node_fvpc + check_mode: true + register: cm_fex_vpc_present + + - name: Assertion check for bind anstest_fex_vpc Access Port Selector with policygroupname_node_fvpc Policy Group - check mode + assert: + that: + - cm_fex_vpc_present.current | length == 0 + - cm_fex_vpc_present.previous | length == 0 + - cm_fex_vpc_present.sent.infraHPortS.attributes.name == "anstest_fex_vpc" + - cm_fex_vpc_present.sent.infraHPortS.children.0.infraRsAccBaseGrp.attributes.tDn == "uni/infra/funcprof/accbundle-policygroupname_node_fvpc" + + - name: Bind anstest_fex_vpc Access Port Selector with policygroupname_node_fvpc Policy Group - normal mode + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *cm_fex_vpc_present + register: nm_fex_vpc_present + + - name: Assertion check for bind anstest_fex_vpc Access Port Selector with policygroupname_node_fvpc Policy Group - normal mode + assert: + that: + - nm_fex_vpc_present.current | length == 1 + - nm_fex_vpc_present.previous | length == 0 + - nm_fex_vpc_present.current.0.infraHPortS.attributes.name == "anstest_fex_vpc" + - nm_fex_vpc_present.current.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.fexId == "101" + - nm_fex_vpc_present.current.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.tDn == "uni/infra/funcprof/accbundle-policygroupname_node_fvpc" + + - name: Remove anstest_fex_vpc Access Port Selector with policygroupname_node_fvpc Policy Group - check mode + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: &cm_fex_vpc_absent + <<: *cm_fex_vpc_present + state: absent + check_mode: true + register: cm_fex_vpc_absent + + - name: Assertion check for remove anstest_fex_vpc Access Port Selector with policygroupname_node_fvpc Policy Group - check mode + assert: + that: + - cm_fex_vpc_absent.current | length == 1 + - cm_fex_vpc_absent.previous | length == 1 + - cm_fex_vpc_absent.current.0.infraHPortS.attributes.name == "anstest_fex_vpc" + - cm_fex_vpc_absent.previous.0.infraHPortS.attributes.name == "anstest_fex_vpc" + - cm_fex_vpc_absent.current.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.fexId == "101" + - cm_fex_vpc_absent.previous.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.fexId == "101" + - cm_fex_vpc_absent.current.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.tDn == "uni/infra/funcprof/accbundle-policygroupname_node_fvpc" + - cm_fex_vpc_absent.previous.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.tDn == "uni/infra/funcprof/accbundle-policygroupname_node_fvpc" + + - name: Remove anstest_fex_vpc Access Port Selector with policygroupname_node_fvpc Policy Group - normal mode + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *cm_fex_vpc_absent + register: nm_fex_vpc_absent + + - name: Assertion check for remove anstest_fex_vpc Access Port Selector with policygroupname_node_fvpc Policy Group - normal mode + assert: + that: + - nm_fex_vpc_absent.current | length == 0 + - nm_fex_vpc_absent.previous | length == 1 + - nm_fex_vpc_absent.previous.0.infraHPortS.attributes.name == "anstest_fex_vpc" + - nm_fex_vpc_absent.previous.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.fexId == "101" + - nm_fex_vpc_absent.previous.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.tDn == "uni/infra/funcprof/accbundle-policygroupname_node_fvpc" + + # Removing profiles + - name: Remove anstest_fex_vpc - Interface Policy Leaf Profile with type Fex + cisco.aci.aci_interface_policy_leaf_profile: + <<: *anstest_fex_vpc + state: absent + register: anstest_fex_vpc_absent + + - name: Assertion check for remove anstest_fex_vpc - Interface Policy Leaf Profile with type Fex + assert: + that: + - anstest_fex_vpc_absent.current | length == 0 + - anstest_fex_vpc_absent.previous | length == 1 + - anstest_fex_vpc_absent.previous.0.infraFexP.attributes.name == "anstest_fex_vpc" + + - name: Remove anstest_fex_port_channel - Interface Policy Leaf Profile with type Fex + cisco.aci.aci_interface_policy_leaf_profile: + <<: *anstest_fex_port_channel_present + state: absent + register: anstest_fex_port_channel_absent + + - name: Assertion check for remove anstest_fex_port_channel - Interface Policy Leaf Profile with type Fex + assert: + that: + - anstest_fex_port_channel_absent.current | length == 0 + - anstest_fex_port_channel_absent.previous | length == 1 + - anstest_fex_port_channel_absent.previous.0.infraFexP.attributes.name == "anstest_fex_port_channel" + + - name: Ensure anstest_leaf_profile interface does not exists + cisco.aci.aci_interface_policy_leaf_profile: &anstest_leaf_profile_absent + <<: *aci_info + type: leaf + leaf_interface_profile: anstest_leaf_profile + state: absent + register: anstest_leaf_profile_absent + + - name: Assertion check for ensure anstest_leaf_profile interface does not exists + assert: + that: + - anstest_leaf_profile_absent.current | length == 0 + + - name: Ensure anstest_fex_profile interface does not exists + cisco.aci.aci_interface_policy_leaf_profile: &anstest_fex_profile_absent + <<: *aci_info + type: fex + leaf_interface_profile: anstest_fex_profile + state: absent + register: anstest_fex_profile_absent + + - name: Assertion check for ensure anstest_fex_profile interface does not exists + assert: + that: + - anstest_fex_profile_absent.current | length == 0 + + - name: Ensure temp_anstest_fex_profile interface does not exists + cisco.aci.aci_interface_policy_leaf_profile: &temp_anstest_fex_profile_absent + <<: *aci_info + type: fex + leaf_interface_profile: temp_anstest_fex_profile + state: absent + register: temp_anstest_fex_profile_absent + + - name: Assertion check for ensure temp_anstest_fex_profile interface does not exists + assert: + that: + - temp_anstest_fex_profile_absent.current | length == 0 + + - name: Add a new anstest_leaf_profile with profile type leaf + cisco.aci.aci_interface_policy_leaf_profile: &anstest_leaf_profile_present + <<: *anstest_leaf_profile_absent + state: present + register: anstest_leaf_profile_present + + - name: Assertion check for add a new anstest_leaf_profile with profile type leaf + assert: + that: + - anstest_leaf_profile_present is changed + - anstest_leaf_profile_present.current | length == 1 + - anstest_leaf_profile_present.previous | length == 0 + - anstest_leaf_profile_present.current.0.infraAccPortP.attributes.name == "anstest_leaf_profile" + - anstest_leaf_profile_present.current.0.infraAccPortP.attributes.dn == "uni/infra/accportprof-anstest_leaf_profile" + + - name: Add a new anstest_fex_profile with profile type fex + cisco.aci.aci_interface_policy_leaf_profile: &anstest_fex_profile_present + <<: *anstest_fex_profile_absent + state: present + register: anstest_fex_profile_present + + - name: Assertion check for add a new anstest_fex_profile with profile type fex + assert: + that: + - anstest_fex_profile_present is changed + - anstest_fex_profile_present.current | length == 1 + - anstest_fex_profile_present.previous | length == 0 + - anstest_fex_profile_present.current.0.infraFexP.attributes.name == "anstest_fex_profile" + - anstest_fex_profile_present.current.0.infraFexP.attributes.dn == "uni/infra/fexprof-anstest_fex_profile" + + - name: Add a new temp_anstest_fex_profile with profile type fex + cisco.aci.aci_interface_policy_leaf_profile: &temp_anstest_fex_profile_present + <<: *temp_anstest_fex_profile_absent + state: present + register: temp_anstest_fex_profile_present + + - name: Assertion check for add a new temp_anstest_fex_profile with profile type fex + assert: + that: + - temp_anstest_fex_profile_present is changed + - temp_anstest_fex_profile_present.current | length == 1 + - temp_anstest_fex_profile_present.previous | length == 0 + - temp_anstest_fex_profile_present.current.0.infraFexP.attributes.name == "temp_anstest_fex_profile" + - temp_anstest_fex_profile_present.current.0.infraFexP.attributes.dn == "uni/infra/fexprof-temp_anstest_fex_profile" + + - name: Add a new policy_group with the same name of interface profile - temp_anstest_fex_profile + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + &temp_anstest_fex_profile_policy_group_present + <<: *aci_info + policy_group: temp_anstest_fex_profile + fex_profile: temp_anstest_fex_profile + state: present + register: temp_anstest_fex_profile_policy_group_present + + - name: Assertion check for add a new policy_group with the same name of interface profile - temp_anstest_fex_profile + assert: + that: + - temp_anstest_fex_profile_policy_group_present is changed + - temp_anstest_fex_profile_policy_group_present.current | length == 1 + - temp_anstest_fex_profile_policy_group_present.previous | length == 0 + - temp_anstest_fex_profile_policy_group_present.current.0.infraFexBndlGrp.attributes.name == "temp_anstest_fex_profile" + - temp_anstest_fex_profile_policy_group_present.current.0.infraFexBndlGrp.attributes.dn == "uni/infra/fexprof-temp_anstest_fex_profile/fexbundle-temp_anstest_fex_profile" + + - name: Bind temp_anstest_fex_profile with anstest_fex_profile - Fex Profile Policy Group + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_info + leaf_interface_profile: anstest_fex_profile + policy_group: temp_anstest_fex_profile + access_port_selector_name: temp_anstest_fex_profile_access_port + interface_type: fex_profile + fex_id: 105 + type: fex + state: present + register: temp_anstest_fex_profile_access_port_present + ignore_errors: true + + - name: Assertion check for bind temp_anstest_fex_profile with anstest_fex_profile - Fex Profile Policy Group + assert: + that: + - temp_anstest_fex_profile_access_port_present.msg == "Invalid Configuration - interface_type fex_profile can not be configured with a profile of type fex" + + - name: Remove temp_anstest_fex_profile + cisco.aci.aci_interface_policy_leaf_profile: + <<: *temp_anstest_fex_profile_absent + register: remove_anstest_fex_profile_absent + + - name: Assertion check for remove temp_anstest_fex_profile + assert: + that: + - remove_anstest_fex_profile_absent is changed + - remove_anstest_fex_profile_absent.current | length == 0 + - remove_anstest_fex_profile_absent.previous | length == 1 + + - name: Add a new policy_group with the same name of interface profile - anstest_fex_profile + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + &anstest_fex_profile_policy_group_present + <<: *aci_info + policy_group: anstest_fex_profile + fex_profile: anstest_fex_profile + state: present + register: anstest_fex_profile_policy_group_present + + - name: Assertion check for add a new policy_group with the same name of interface profile - anstest_fex_profile + assert: + that: + - anstest_fex_profile_policy_group_present is changed + - anstest_fex_profile_policy_group_present.current | length == 1 + - anstest_fex_profile_policy_group_present.previous | length == 0 + - anstest_fex_profile_policy_group_present.current.0.infraFexBndlGrp.attributes.name == "anstest_fex_profile" + - anstest_fex_profile_policy_group_present.current.0.infraFexBndlGrp.attributes.dn == "uni/infra/fexprof-anstest_fex_profile/fexbundle-anstest_fex_profile" + + - name: Bind anstest_leaf_profile with anstest_fex_profile - Fex Profile Policy Group + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + &anstest_leaf_profile_access_port_present + <<: *aci_info + leaf_interface_profile: anstest_leaf_profile + policy_group: anstest_fex_profile + access_port_selector_name: anstest_leaf_profile_access_port + interface_type: fex_profile + fex_id: 105 + type: leaf + state: present + register: anstest_leaf_profile_access_port_present + + - name: Assertion check for bind anstest_leaf_profile with anstest_fex_profile - Fex Profile Policy Group + assert: + that: + - anstest_leaf_profile_access_port_present is changed + - anstest_leaf_profile_access_port_present.current | length == 1 + - anstest_leaf_profile_access_port_present.previous | length == 0 + - anstest_leaf_profile_access_port_present.current.0.infraHPortS.attributes.name == "anstest_leaf_profile_access_port" + - anstest_leaf_profile_access_port_present.current.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.tDn == "uni/infra/fexprof-anstest_fex_profile/fexbundle-anstest_fex_profile" + - anstest_leaf_profile_access_port_present.current.0.infraHPortS.children.0.infraRsAccBaseGrp.attributes.fexId == "105" + + - name: Bind anstest_leaf_profile with anstest_fex_profile with wrong fex_id + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_info + leaf_interface_profile: anstest_leaf_profile + policy_group: anstest_fex_profile + access_port_selector_name: anstest_leaf_profile_access_port + interface_type: fex_profile + fex_id: 999 + type: leaf + state: present + ignore_errors: true + register: anstest_leaf_profile_access_port_wrong_fex_id + + - name: Assertion check for bind anstest_leaf_profile with wrong fex_id + assert: + that: + - anstest_leaf_profile_access_port_wrong_fex_id.msg == "A valid FEX ID is between 101 to 199" + + - name: Bind anstest_leaf_profile with anstest_fex_profile with no fex_id + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_info + leaf_interface_profile: anstest_leaf_profile + policy_group: anstest_fex_profile + access_port_selector_name: anstest_leaf_profile_access_port + interface_type: fex_profile + type: leaf + state: present + ignore_errors: true + register: anstest_leaf_profile_access_port_no_fex_id + + - name: Assertion check for bind anstest_leaf_profile with no fex_id + assert: + that: + - anstest_leaf_profile_access_port_no_fex_id.msg == "The fex_id must not be None, when interface_type is fex_profile" + + - name: Remove anstest_leaf_profile + cisco.aci.aci_interface_policy_leaf_profile: + <<: *anstest_leaf_profile_absent + register: anstest_leaf_profile_cleanup + + - name: Assertion check for remove anstest_leaf_profile + assert: + that: + - anstest_leaf_profile_cleanup is changed + - anstest_leaf_profile_cleanup.previous | length == 1 + - anstest_leaf_profile_cleanup.current | length == 0 + + - name: Remove anstest_fex_profile + cisco.aci.aci_interface_policy_leaf_profile: + <<: *anstest_fex_profile_absent + register: anstest_fex_profile_cleanup + + - name: Assertion check for remove anstest_fex_profile + assert: + that: + - anstest_fex_profile_cleanup is changed + - anstest_fex_profile_cleanup.previous | length == 1 + - anstest_fex_profile_cleanup.current | length == 0 diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_dst_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_dst_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_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_access_span_dst_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_dst_group/tasks/main.yml new file mode 100644 index 000000000..03c2e92c2 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_dst_group/tasks/main.yml @@ -0,0 +1,347 @@ +# 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 + +- name: Query all access span destination groups + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + state: query + register: query_for_clean + +- name: Clean access span destination groups + cisco.aci.aci_access_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 access span destination group type epg ( check mode ) + cisco.aci.aci_access_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 access span destination group type epg + cisco.aci.aci_access_span_dst_group: + <<: *add_ansible_group_1 + register: nm_add_ansible_group_1 + +- name: Add access span destination group type epg again + cisco.aci.aci_access_span_dst_group: + <<: *add_ansible_group_1 + register: nm_add_ansible_group_1_again + +- name: Verify add access span destination group type epg + 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 access span destination group type epg + cisco.aci.aci_access_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 access span destination group type epg + cisco.aci.aci_access_span_dst_group: + <<: *change_ansible_group_1 + register: change_ansible_group_1_again + +- name: Verify change access span destination group type epg + 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: Change access span destination group type epg path information (error) + cisco.aci.aci_access_span_dst_group: + <<: *add_ansible_group_1 + destination_epg: + destination_ip: 10.0.0.2 + source_ip: 10.0.2.2 + tenant: ansible_test_2 + ap: ansible_test_2 + epg: ansible_test_2 + register: error_on_path_change_ansible_group_1 + ignore_errors: true + +- name: Verify change access span destination group type epg path information (error) + ansible.builtin.assert: + that: + - error_on_path_change_ansible_group_1.msg == "APIC Error 105{{':'}} Span source or destination relation target configuration cannot be dynamically modified" + +- name: Add access span destination group type access interface port + cisco.aci.aci_access_span_dst_group: &add_ansible_group_2 + <<: *aci_info + destination_group: ansible_group_2 + description: test span access interface port + access_interface: + pod: 1 + node: 101 + path: eth1/1 + mtu: 1500 + state: present + register: add_ansible_group_2 + +- name: Add access span destination group type access interface direct port channel + cisco.aci.aci_access_span_dst_group: &add_ansible_group_3 + <<: *aci_info + destination_group: ansible_group_3 + description: test span access interface port channel + access_interface: + pod: 1 + node: 101 + path: test-PolGrp + state: present + register: add_ansible_group_3 + +- name: Verify add access span destination groups type access interface port and direct port channel + ansible.builtin.assert: + that: + - add_ansible_group_2 is changed + - add_ansible_group_2.current.0.spanDestGrp.attributes.name == "ansible_group_2" + - add_ansible_group_2.current.0.spanDestGrp.attributes.descr == "test span access interface port" + - add_ansible_group_2.current.0.spanDestGrp.children.0.spanDest.attributes.name == "ansible_group_2" + - add_ansible_group_2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestPathEp.attributes.mtu == "1500" + - add_ansible_group_2.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[eth1/1]" + - add_ansible_group_3 is changed + - add_ansible_group_3.current.0.spanDestGrp.attributes.name == "ansible_group_3" + - add_ansible_group_3.current.0.spanDestGrp.attributes.descr == "test span access interface port channel" + - add_ansible_group_3.current.0.spanDestGrp.children.0.spanDest.attributes.name == "ansible_group_3" + - add_ansible_group_3.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestPathEp.attributes.mtu == "1518" + - add_ansible_group_3.current.0.spanDestGrp.children.0.spanDest.children.0.spanRsDestPathEp.attributes.tDn == "topology/pod-1/paths-101/pathep-[test-PolGrp]" + +# TEST QUERY DESTINATION GROUPS + +- name: Query one access span destination group + cisco.aci.aci_access_span_dst_group: + <<: *add_ansible_group_1 + state: query + register: query_one + +- name: Query all access span destination group + cisco.aci.aci_access_span_dst_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.spanDestGrp.attributes.name == "ansible_group_1" + - query_all is not changed + - query_all.current | length >= 3 # greater or equal because there could be configuration present that is not access span but is returned in ( class based ) query all + +# TEST REMOVAL DESTINATION GROUPS + +- name: Remove access span destination group type epg ( check mode ) + cisco.aci.aci_access_span_dst_group: &remove_ansible_group_1 + <<: *add_ansible_group_1 + state: absent + check_mode: true + register: cm_remove_ansible_group_1 + +- name: Remove access span destination group type epg + cisco.aci.aci_access_span_dst_group: + <<: *remove_ansible_group_1 + register: nm_remove_ansible_group_1 + +- name: Remove access span destination group type epg again + cisco.aci.aci_access_span_dst_group: + <<: *remove_ansible_group_1 + register: nm_remove_ansible_group_1_again + +- name: Remove access span destination group type access interface port + cisco.aci.aci_access_span_dst_group: + <<: *add_ansible_group_2 + state: absent + register: nm_remove_ansible_group_2 + +- name: Remove access span destination group type access interface direct port channel + cisco.aci.aci_access_span_dst_group: + <<: *add_ansible_group_3 + state: absent + register: nm_remove_ansible_group_3 + +- name: Verify remove access span destination groups + 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 == [] + - nm_remove_ansible_group_2 is changed + - nm_remove_ansible_group_2.current == [] + - nm_remove_ansible_group_2.previous | length == 1 + - nm_remove_ansible_group_3 is changed + - nm_remove_ansible_group_3.current == [] + - nm_remove_ansible_group_3.previous | length == 1 + +# TEST INCORRECT MODULE INPUT + +- name: Mutually exclusive parameters provided together (error) + cisco.aci.aci_access_span_dst_group: + <<: *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 + access_interface: + pod: 1 + node: 101 + path: test-PolGrp + state: present + register: incorrect_input_both_types + ignore_errors: true + +- name: Missing input parameters for state is present (error) + cisco.aci.aci_access_span_dst_group: + <<: *aci_info + destination_group: ansible_group_1 + description: test span epg + register: incorrect_input_no_types + ignore_errors: true + +- name: Verify incorrect module input + ansible.builtin.assert: + that: + - incorrect_input_both_types.msg == "parameters are mutually exclusive{{':'}} access_interface|destination_epg" + - incorrect_input_no_types.msg == "state is present but any of the following are missing{{':'}} access_interface, destination_epg"
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_filter_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_filter_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_filter_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_filter_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_filter_group/tasks/main.yml new file mode 100644 index 000000000..c071f747a --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_filter_group/tasks/main.yml @@ -0,0 +1,154 @@ +# 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") }}' + +- 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 == [] + block: + + # CLEAN TEST ENVIRONMENT + + - name: Query all access span filter groups + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + state: query + register: query_for_clean + + - name: Clean access span filter groups + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + filter_group: "{{ item.spanFilterGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + + # TEST CREATE FILTER GROUPS + + - name: Add access span filter group ( check mode ) + cisco.aci.aci_access_span_filter_group: &add_ansible_filter_group_1 + <<: *aci_info + filter_group: ansible_group_1 + state: present + check_mode: true + register: cm_add_ansible_group_1 + + - name: Add access span filter group + cisco.aci.aci_access_span_filter_group: + <<: *add_ansible_filter_group_1 + register: nm_add_ansible_group_1 + + - name: Add access span filter group again + cisco.aci.aci_access_span_filter_group: + <<: *add_ansible_filter_group_1 + register: nm_add_ansible_group_1_again + + - name: Verify add access span filter group + 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.spanFilterGrp.attributes.name == "ansible_group_1" + - nm_add_ansible_group_1 is changed + - nm_add_ansible_group_1.previous == [] + - nm_add_ansible_group_1.current.0.spanFilterGrp.attributes.name == "ansible_group_1" + - nm_add_ansible_group_1_again is not changed + - nm_add_ansible_group_1_again.previous.0.spanFilterGrp.attributes.name == "ansible_group_1" + - nm_add_ansible_group_1_again.current.0.spanFilterGrp.attributes.name == "ansible_group_1" + + - name: Add two more access span filter groups + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + filter_group: "{{ item }}" + state: present + loop: + - ansible_group_2 + - ansible_group_3 + + # TEST QUERY FILTER GROUPS + + - name: Query access span filter group + cisco.aci.aci_access_span_filter_group: + <<: *add_ansible_filter_group_1 + state: query + register: query_one + + - name: Query all access span filter group ( class query ) + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + state: query + register: query_all + + - name: Verify access span filter group queries + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current | length == 1 + - query_one.current.0.spanFilterGrp.attributes.name == "ansible_group_1" + - query_all is not changed + - query_all.current | length == 3 + - query_all.current.0.spanFilterGrp.attributes.name == "ansible_group_1" + - query_all.current.1.spanFilterGrp.attributes.name == "ansible_group_2" + - query_all.current.2.spanFilterGrp.attributes.name == "ansible_group_3" + + # TEST REMOVAL FILTER GROUPS + + - name: Remove access span filter group ( check mode ) + cisco.aci.aci_access_span_filter_group: &remove_ansible_filter_group_1 + <<: *add_ansible_filter_group_1 + state: absent + check_mode: true + register: cm_remove_ansible_filter_group_1 + + - name: Remove access span filter group + cisco.aci.aci_access_span_filter_group: + <<: *remove_ansible_filter_group_1 + register: nm_remove_ansible_filter_group_1 + + - name: Remove access span filter group again + cisco.aci.aci_access_span_filter_group: + <<: *remove_ansible_filter_group_1 + register: nm_remove_ansible_filter_group_1_again + + - name: Verify access span filter group removal + ansible.builtin.assert: + that: + - cm_remove_ansible_filter_group_1 is changed + - cm_remove_ansible_filter_group_1.proposed == {} + - nm_remove_ansible_filter_group_1 is changed + - nm_remove_ansible_filter_group_1.previous.0.spanFilterGrp.attributes.name == "ansible_group_1" + - nm_remove_ansible_filter_group_1.current == [] + - nm_remove_ansible_filter_group_1_again is not changed + - nm_remove_ansible_filter_group_1_again.previous == [] + - nm_remove_ansible_filter_group_1_again.current == [] + + # CLEAN TEST ENVIRONMENT + + - name: Clean created access span filter groups + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + filter_group: "{{ item }}" + state: absent + loop: + - ansible_group_2 + - ansible_group_3
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_filter_group_entry/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_filter_group_entry/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_filter_group_entry/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_filter_group_entry/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_filter_group_entry/tasks/main.yml new file mode 100644 index 000000000..788658f13 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_span_filter_group_entry/tasks/main.yml @@ -0,0 +1,274 @@ +# 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") }}' + +- 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 == [] + block: + + # CLEAN TEST ENVIRONMENT + + - name: Query all access span filter groups + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + state: query + register: query_for_clean + + - name: Clean access span filter groups + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + filter_group: "{{ item.spanFilterGrp.attributes.name }}" + state: absent + loop: "{{ query_for_clean.current }}" + + - name: Add access span filter group 1 + cisco.aci.aci_access_span_filter_group: &add_ansible_filter_group_1 + <<: *aci_info + filter_group: ansible_group_1 + state: present + + - name: Add access span filter group 2 + cisco.aci.aci_access_span_filter_group: &add_ansible_filter_group_2 + <<: *aci_info + filter_group: ansible_group_2 + state: present + + # TEST CREATE FILTER GROUP ENTRIES + + - name: Add access span filter group entry 1 to ansible_group_1 ( checkmode ) + cisco.aci.aci_access_span_filter_group_entry: &add_ansible_filter_group_entry_1 + <<: *add_ansible_filter_group_1 + source_ip: 1.1.1.1 + destination_ip: 2.2.2.2 + first_src_port: http + last_src_port: https + check_mode: true + register: cm_add_ansible_filter_group_entry_1 + + - name: Add access span filter group entry 1 to ansible_group_1 + cisco.aci.aci_access_span_filter_group_entry: + <<: *add_ansible_filter_group_entry_1 + register: nm_add_ansible_filter_group_entry_1 + + - name: Add access span filter group entry 1 to ansible_group_1 again + cisco.aci.aci_access_span_filter_group_entry: + <<: *add_ansible_filter_group_entry_1 + register: nm_add_ansible_filter_group_entry_1_again + + - name: Add access span filter group entry 2 to ansible_group_1 with ports as digits + cisco.aci.aci_access_span_filter_group_entry: + <<: *add_ansible_filter_group_1 + source_ip: 1.1.1.1 + destination_ip: 3.3.3.3 + first_src_port: http + last_src_port: https + first_dest_port: 80 + last_dest_port: 443 + ip_protocol: tcp + register: nm_add_ansible_filter_group_entry_2 + + - name: Add access span filter group entry 3 to ansible_group_1 + cisco.aci.aci_access_span_filter_group_entry: + <<: *add_ansible_filter_group_1 + source_ip: 2.2.2.2 + destination_ip: 5.5.5.5 + register: nm_add_ansible_filter_group_entry_3 + + - name: Add access span filter group entry 4 to ansible_group_2 + cisco.aci.aci_access_span_filter_group_entry: + <<: *add_ansible_filter_group_2 + source_ip: 2.2.2.2 + destination_ip: 5.5.5.5 + register: nm_add_ansible_filter_group_entry_4 + + - name: Verify add access span filter group entires + ansible.builtin.assert: + that: + - cm_add_ansible_filter_group_entry_1 is changed + - cm_add_ansible_filter_group_entry_1.previous == [] + - cm_add_ansible_filter_group_entry_1.current == [] + - cm_add_ansible_filter_group_entry_1.proposed.spanFilterEntry.attributes.dn == "uni/infra/filtergrp-ansible_group_1/proto-unspecified-src-[1.1.1.1]-dst-[2.2.2.2]-srcPortFrom-http-srcPortTo-https-dstPortFrom-unspecified-dstPortTo-unspecified" + - cm_add_ansible_filter_group_entry_1.proposed.spanFilterEntry.attributes.dstAddr == "2.2.2.2" + - cm_add_ansible_filter_group_entry_1.proposed.spanFilterEntry.attributes.srcAddr == "1.1.1.1" + - cm_add_ansible_filter_group_entry_1.proposed.spanFilterEntry.attributes.srcPortFrom == "http" + - cm_add_ansible_filter_group_entry_1.proposed.spanFilterEntry.attributes.srcPortTo == "https" + - nm_add_ansible_filter_group_entry_1 is changed + - nm_add_ansible_filter_group_entry_1.previous == [] + - nm_add_ansible_filter_group_entry_1.current.0.spanFilterEntry.attributes.dn == "uni/infra/filtergrp-ansible_group_1/proto-unspecified-src-[1.1.1.1]-dst-[2.2.2.2]-srcPortFrom-http-srcPortTo-https-dstPortFrom-unspecified-dstPortTo-unspecified" + - nm_add_ansible_filter_group_entry_1.current.0.spanFilterEntry.attributes.dstAddr == "2.2.2.2" + - nm_add_ansible_filter_group_entry_1.current.0.spanFilterEntry.attributes.srcAddr == "1.1.1.1" + - nm_add_ansible_filter_group_entry_1.current.0.spanFilterEntry.attributes.srcPortFrom == "http" + - nm_add_ansible_filter_group_entry_1.current.0.spanFilterEntry.attributes.srcPortTo == "https" + - nm_add_ansible_filter_group_entry_1.current.0.spanFilterEntry.attributes.dstPortFrom == "unspecified" + - nm_add_ansible_filter_group_entry_1.current.0.spanFilterEntry.attributes.dstPortTo == "unspecified" + - nm_add_ansible_filter_group_entry_1.current.0.spanFilterEntry.attributes.ipProto == "unspecified" + - nm_add_ansible_filter_group_entry_1_again is not changed + - nm_add_ansible_filter_group_entry_1_again.previous.0.spanFilterEntry.attributes.dn == "uni/infra/filtergrp-ansible_group_1/proto-unspecified-src-[1.1.1.1]-dst-[2.2.2.2]-srcPortFrom-http-srcPortTo-https-dstPortFrom-unspecified-dstPortTo-unspecified" + - nm_add_ansible_filter_group_entry_1_again.previous.0.spanFilterEntry.attributes.dstAddr == "2.2.2.2" + - nm_add_ansible_filter_group_entry_1_again.previous.0.spanFilterEntry.attributes.srcAddr == "1.1.1.1" + - nm_add_ansible_filter_group_entry_1_again.previous.0.spanFilterEntry.attributes.srcPortFrom == "http" + - nm_add_ansible_filter_group_entry_1_again.previous.0.spanFilterEntry.attributes.srcPortTo == "https" + - nm_add_ansible_filter_group_entry_1_again.previous.0.spanFilterEntry.attributes.dstPortFrom == "unspecified" + - nm_add_ansible_filter_group_entry_1_again.previous.0.spanFilterEntry.attributes.dstPortTo == "unspecified" + - nm_add_ansible_filter_group_entry_1_again.previous.0.spanFilterEntry.attributes.ipProto == "unspecified" + - nm_add_ansible_filter_group_entry_1_again.current.0.spanFilterEntry.attributes.dn == "uni/infra/filtergrp-ansible_group_1/proto-unspecified-src-[1.1.1.1]-dst-[2.2.2.2]-srcPortFrom-http-srcPortTo-https-dstPortFrom-unspecified-dstPortTo-unspecified" + - nm_add_ansible_filter_group_entry_1_again.current.0.spanFilterEntry.attributes.dstAddr == "2.2.2.2" + - nm_add_ansible_filter_group_entry_1_again.current.0.spanFilterEntry.attributes.srcAddr == "1.1.1.1" + - nm_add_ansible_filter_group_entry_1_again.current.0.spanFilterEntry.attributes.srcPortFrom == "http" + - nm_add_ansible_filter_group_entry_1_again.current.0.spanFilterEntry.attributes.srcPortTo == "https" + - nm_add_ansible_filter_group_entry_1_again.current.0.spanFilterEntry.attributes.dstPortFrom == "unspecified" + - nm_add_ansible_filter_group_entry_1_again.current.0.spanFilterEntry.attributes.dstPortTo == "unspecified" + - nm_add_ansible_filter_group_entry_1_again.current.0.spanFilterEntry.attributes.ipProto == "unspecified" + - nm_add_ansible_filter_group_entry_2 is changed + - nm_add_ansible_filter_group_entry_2.previous == [] + - nm_add_ansible_filter_group_entry_2.current.0.spanFilterEntry.attributes.dn == "uni/infra/filtergrp-ansible_group_1/proto-tcp-src-[1.1.1.1]-dst-[3.3.3.3]-srcPortFrom-http-srcPortTo-https-dstPortFrom-http-dstPortTo-https" + - nm_add_ansible_filter_group_entry_2.current.0.spanFilterEntry.attributes.dstAddr == "3.3.3.3" + - nm_add_ansible_filter_group_entry_2.current.0.spanFilterEntry.attributes.srcAddr == "1.1.1.1" + - nm_add_ansible_filter_group_entry_2.current.0.spanFilterEntry.attributes.srcPortFrom == "http" + - nm_add_ansible_filter_group_entry_2.current.0.spanFilterEntry.attributes.srcPortTo == "https" + - nm_add_ansible_filter_group_entry_2.current.0.spanFilterEntry.attributes.dstPortFrom == "http" + - nm_add_ansible_filter_group_entry_2.current.0.spanFilterEntry.attributes.dstPortTo == "https" + - nm_add_ansible_filter_group_entry_2.current.0.spanFilterEntry.attributes.ipProto == "tcp" + - nm_add_ansible_filter_group_entry_3 is changed + - nm_add_ansible_filter_group_entry_3.previous == [] + - nm_add_ansible_filter_group_entry_3.current.0.spanFilterEntry.attributes.dn == "uni/infra/filtergrp-ansible_group_1/proto-unspecified-src-[2.2.2.2]-dst-[5.5.5.5]-srcPortFrom-unspecified-srcPortTo-unspecified-dstPortFrom-unspecified-dstPortTo-unspecified" + - nm_add_ansible_filter_group_entry_3.current.0.spanFilterEntry.attributes.dstAddr == "5.5.5.5" + - nm_add_ansible_filter_group_entry_3.current.0.spanFilterEntry.attributes.srcAddr == "2.2.2.2" + - nm_add_ansible_filter_group_entry_3.current.0.spanFilterEntry.attributes.srcPortFrom == "unspecified" + - nm_add_ansible_filter_group_entry_3.current.0.spanFilterEntry.attributes.srcPortTo == "unspecified" + - nm_add_ansible_filter_group_entry_3.current.0.spanFilterEntry.attributes.dstPortFrom == "unspecified" + - nm_add_ansible_filter_group_entry_3.current.0.spanFilterEntry.attributes.dstPortTo == "unspecified" + - nm_add_ansible_filter_group_entry_3.current.0.spanFilterEntry.attributes.ipProto == "unspecified" + - nm_add_ansible_filter_group_entry_4 is changed + - nm_add_ansible_filter_group_entry_4.previous == [] + - nm_add_ansible_filter_group_entry_4.current.0.spanFilterEntry.attributes.dn == "uni/infra/filtergrp-ansible_group_2/proto-unspecified-src-[2.2.2.2]-dst-[5.5.5.5]-srcPortFrom-unspecified-srcPortTo-unspecified-dstPortFrom-unspecified-dstPortTo-unspecified" + - nm_add_ansible_filter_group_entry_4.current.0.spanFilterEntry.attributes.dstAddr == "5.5.5.5" + - nm_add_ansible_filter_group_entry_4.current.0.spanFilterEntry.attributes.srcAddr == "2.2.2.2" + - nm_add_ansible_filter_group_entry_4.current.0.spanFilterEntry.attributes.srcPortFrom == "unspecified" + - nm_add_ansible_filter_group_entry_4.current.0.spanFilterEntry.attributes.srcPortTo == "unspecified" + - nm_add_ansible_filter_group_entry_4.current.0.spanFilterEntry.attributes.dstPortFrom == "unspecified" + - nm_add_ansible_filter_group_entry_4.current.0.spanFilterEntry.attributes.dstPortTo == "unspecified" + - nm_add_ansible_filter_group_entry_4.current.0.spanFilterEntry.attributes.ipProto == "unspecified" + + # TEST QUERY FILTER GROUP ENTRIES + + - name: Query one specific access span filter group entry + cisco.aci.aci_access_span_filter_group_entry: + <<: *aci_info + source_ip: 1.1.1.1 + destination_ip: 2.2.2.2 + first_src_port: http + last_src_port: https + state: query + register: query_one + + - name: Query all access span filter group entries of one entire group + cisco.aci.aci_access_span_filter_group_entry: + <<: *add_ansible_filter_group_1 + state: query + register: query_one_group + + - name: Query all access span filter group entries ( class query ) + cisco.aci.aci_access_span_filter_group_entry: + <<: *aci_info + state: query + register: query_all + + - name: Query access span filter group entries that match source_ip and first_dest_port + cisco.aci.aci_access_span_filter_group_entry: + <<: *aci_info + source_ip: 1.1.1.1 + first_src_port: http + state: query + register: query_match + + - name: Query access span filter group entries that match source_ip and first_dest_port with ports as digits + cisco.aci.aci_access_span_filter_group_entry: + <<: *aci_info + source_ip: 1.1.1.1 + first_src_port: 80 + last_src_port: 443 + state: query + register: query_match_port_number + + - name: Verify access span filter group queries + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current | length == 1 + - query_one.current.0.spanFilterEntry.attributes.dn == "uni/infra/filtergrp-ansible_group_1/proto-unspecified-src-[1.1.1.1]-dst-[2.2.2.2]-srcPortFrom-http-srcPortTo-https-dstPortFrom-unspecified-dstPortTo-unspecified" + - query_one_group is not changed + - query_one_group.current.0.spanFilterGrp.children | length == 3 + - query_all is not changed + - query_all.current | length == 4 + - query_match is not changed + - query_match.current | length == 2 + - query_match.current.0.spanFilterEntry.attributes.dn == "uni/infra/filtergrp-ansible_group_1/proto-unspecified-src-[1.1.1.1]-dst-[2.2.2.2]-srcPortFrom-http-srcPortTo-https-dstPortFrom-unspecified-dstPortTo-unspecified" + - query_match.current.1.spanFilterEntry.attributes.dn == "uni/infra/filtergrp-ansible_group_1/proto-tcp-src-[1.1.1.1]-dst-[3.3.3.3]-srcPortFrom-http-srcPortTo-https-dstPortFrom-http-dstPortTo-https" + - query_match_port_number is not changed + - query_match_port_number.current | length == 2 + - query_match_port_number.current.0.spanFilterEntry.attributes.dn == "uni/infra/filtergrp-ansible_group_1/proto-unspecified-src-[1.1.1.1]-dst-[2.2.2.2]-srcPortFrom-http-srcPortTo-https-dstPortFrom-unspecified-dstPortTo-unspecified" + - query_match_port_number.current.1.spanFilterEntry.attributes.dn == "uni/infra/filtergrp-ansible_group_1/proto-tcp-src-[1.1.1.1]-dst-[3.3.3.3]-srcPortFrom-http-srcPortTo-https-dstPortFrom-http-dstPortTo-https" + + # TEST REMOVAL FILTER GROUP ENTRIES + + - name: Remove access span filter group ( checkmode ) + cisco.aci.aci_access_span_filter_group_entry: &remove_ansible_filter_group_entry_1 + <<: *add_ansible_filter_group_entry_1 + state: absent + check_mode: true + register: cm_remove_ansible_filter_group_1_entry + + - name: Remove access span filter group + cisco.aci.aci_access_span_filter_group_entry: + <<: *remove_ansible_filter_group_entry_1 + register: nm_remove_ansible_filter_group_1_entry + + - name: Remove access span filter group again + cisco.aci.aci_access_span_filter_group_entry: + <<: *remove_ansible_filter_group_entry_1 + register: nm_remove_ansible_filter_group_1_entry_again + + - name: Verify access span filter group entries removal + ansible.builtin.assert: + that: + - cm_remove_ansible_filter_group_1_entry is changed + - cm_remove_ansible_filter_group_1_entry.proposed == {} + - nm_remove_ansible_filter_group_1_entry is changed + - nm_remove_ansible_filter_group_1_entry.current == [] + - nm_remove_ansible_filter_group_1_entry.previous.0.spanFilterEntry.attributes.dn == "uni/infra/filtergrp-ansible_group_1/proto-unspecified-src-[1.1.1.1]-dst-[2.2.2.2]-srcPortFrom-http-srcPortTo-https-dstPortFrom-unspecified-dstPortTo-unspecified" + - nm_remove_ansible_filter_group_1_entry_again is not changed + - nm_remove_ansible_filter_group_1_entry_again.current == [] + - nm_remove_ansible_filter_group_1_entry_again.previous == [] + + # CLEAN TEST ENVIRONMENT + + - name: Clean created access span filter groups + cisco.aci.aci_access_span_filter_group: + <<: *aci_info + filter_group: "{{ item }}" + state: absent + loop: + - ansible_group_1 + - ansible_group_2 diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_access_sub_port_block_to_access_port/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_sub_port_block_to_access_port/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_sub_port_block_to_access_port/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_sub_port_block_to_access_port/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_sub_port_block_to_access_port/tasks/main.yml new file mode 100644 index 000000000..b986f5762 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_access_sub_port_block_to_access_port/tasks/main.yml @@ -0,0 +1,148 @@ +# Test code for the ACI modules +# 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) + +- 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 + block: # block specifies execution of tasks within, based on conditions + - name: Ensuring Interface Policy Leaf profile exists for kick off + cisco.aci.aci_interface_policy_leaf_profile: &aci_interface_policy_leaf_profile_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 + leaf_interface_profile: leafintprftest + register: leaf_profile_present + + - name: Ensure Interface Access Port Selector exists for kick of + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: &aci_access_port_to_interface_policy_leaf_profile_present + <<: *aci_interface_policy_leaf_profile_present + access_port_selector: anstest_accessportselector + + # TODO: Ensure that leaf Policy Group Exists (module missing) (infra:AccPortGrp) + + - name: Bind an Access Sub Port Block to an Interface Access Port Selector - check mode works + cisco.aci.aci_access_sub_port_block_to_access_port: &aci_access_sub_port_block_to_access_port_present + <<: *aci_access_port_to_interface_policy_leaf_profile_present + leaf_port_blk: anstest_leafportblkname + leaf_port_blk_description: anstest_leafportblkdesc + fromPort: 13 + toPort: 13 + fromSubPort: 1 + toSubPort: 3 + check_mode: true + register: accesssubportblock_to_accessport_check_mode_present + + - name: Bind an Access Sub Port Block to an Interface Access Port Selector - creation works + cisco.aci.aci_access_sub_port_block_to_access_port: + <<: *aci_access_sub_port_block_to_access_port_present + register: accesssubportblock_to_accessport_present + + - name: Bind an Access Sub Port Block to an Interface Access Port Selector - idempotency works + cisco.aci.aci_access_sub_port_block_to_access_port: + <<: *aci_access_sub_port_block_to_access_port_present + register: accesssubportblock_to_accessport_idempotent + + - name: Bind an Access Sub Port Block to an Interface Access Port Selector - update works + cisco.aci.aci_access_sub_port_block_to_access_port: + <<: *aci_access_sub_port_block_to_access_port_present + toSubPort: 2 + register: accesssubportblock_to_accessport_update + + # TODO: also test for errors + - name: present assertions + assert: + that: + - accesssubportblock_to_accessport_check_mode_present is changed + - accesssubportblock_to_accessport_present is changed + - accesssubportblock_to_accessport_present.current.0.infraSubPortBlk.attributes.annotation == 'orchestrator:ansible' + - accesssubportblock_to_accessport_present.previous == [] + - accesssubportblock_to_accessport_present.sent.infraSubPortBlk.attributes.descr == 'anstest_leafportblkdesc' + - accesssubportblock_to_accessport_present.sent.infraSubPortBlk.attributes.name == 'anstest_leafportblkname' + - accesssubportblock_to_accessport_present.sent.infraSubPortBlk.attributes.fromPort == accesssubportblock_to_accessport_present.sent.infraSubPortBlk.attributes.toPort == '13' + - accesssubportblock_to_accessport_present.sent.infraSubPortBlk.attributes.fromSubPort == '1' + - accesssubportblock_to_accessport_present.sent.infraSubPortBlk.attributes.toSubPort == '3' + - accesssubportblock_to_accessport_idempotent is not changed + - accesssubportblock_to_accessport_idempotent.sent == {} + - accesssubportblock_to_accessport_update is changed + - accesssubportblock_to_accessport_update.sent.infraSubPortBlk.attributes.toSubPort == '2' + + + - name: Query Specific sub port block and access_port_selector binding + cisco.aci.aci_access_sub_port_block_to_access_port: + <<: *aci_access_sub_port_block_to_access_port_present + state: query + register: binding_query + + - name: present assertions + assert: + that: + - binding_query is not changed + - binding_query.current | length >= 1 + - '"api/mo/uni/infra/accportprof-leafintprftest/hports-anstest_accessportselector-typ-range/subportblk-anstest_leafportblkname.json" in binding_query.url' + + - name: Remove binding of Access Sub Port Block and Interface Access Port Selector - check mode + cisco.aci.aci_access_sub_port_block_to_access_port: &aci_access_sub_port_block_to_access_port_absent + <<: *aci_access_sub_port_block_to_access_port_present + state: absent + check_mode: true + register: accesssubportblock_to_accessport_check_mode_absent + + - name: Remove binding of Access Sub Port Block and Interface Access Port Selector - delete works + cisco.aci.aci_access_sub_port_block_to_access_port: + <<: *aci_access_sub_port_block_to_access_port_absent + register: accesssubportblock_to_accessport_absent + + - name: Remove binding of Access Sub Port Block and Interface Access Port Selector - idempotency works + cisco.aci.aci_access_sub_port_block_to_access_port: + <<: *aci_access_sub_port_block_to_access_port_absent + register: accesssubportblock_to_accessport_absent_idempotent + + - name: Remove binding of Access Sub Port Block and Interface Access Port Selector - check mode + cisco.aci.aci_access_sub_port_block_to_access_port: + <<: *aci_access_port_to_interface_policy_leaf_profile_present + #leaf_port_blk: anstest_leafportblkname + state: absent + ignore_errors: true + register: accesssubportblock_to_accessport_absent_missing_param + + - name: absent assertions + assert: + that: + - accesssubportblock_to_accessport_check_mode_absent is changed + - accesssubportblock_to_accessport_check_mode_absent.previous != [] + - accesssubportblock_to_accessport_absent is changed + - accesssubportblock_to_accessport_absent.previous == accesssubportblock_to_accessport_check_mode_absent.previous + - accesssubportblock_to_accessport_absent_idempotent is not changed + - accesssubportblock_to_accessport_absent_idempotent.previous == [] + - accesssubportblock_to_accessport_absent_missing_param is failed + - 'accesssubportblock_to_accessport_absent_missing_param.msg == "state is absent but all of the following are missing: leaf_port_blk"' + + + - name: Remove binding of Access Sub Port Block and Interface Access Port Selector - Clean up + cisco.aci.aci_access_sub_port_block_to_access_port: + <<: *aci_access_sub_port_block_to_access_port_present + state: absent + + - name: Remove Interface Access Port Selector - Cleanup + cisco.aci.aci_access_port_to_interface_policy_leaf_profile: + <<: *aci_access_port_to_interface_policy_leaf_profile_present + state: absent + + - name: Remove Interface policy leaf profile - Cleanup + cisco.aci.aci_interface_policy_leaf_profile: + <<: *aci_interface_policy_leaf_profile_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aep/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_aep/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aep/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aep/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_aep/tasks/main.yml new file mode 100644 index 000000000..1a389a9fc --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aep/tasks/main.yml @@ -0,0 +1,338 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.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: 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: Remove AEP + cisco.aci.aci_aep: &aep_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") }}' + aep: '{{ item }}' + state: absent + loop: + - ansible_test + - ansible_test2 + - ansible_test3 + + # ADD AEP + - name: Add AEP (check_mode) + cisco.aci.aci_aep: &aep_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") }}' + aep: ansible_test + infra_vlan: true + state: present + check_mode: true + register: cm_add_aep + + - name: Add AEP (normal mode) + cisco.aci.aci_aep: *aep_present + register: nm_add_aep + + - name: Add another AEP (normal mode) + cisco.aci.aci_aep: + <<: *aep_present + aep: ansible_test2 + infra_vlan: true + register: nm_add_aep2 + + - name: Add another AEP (normal mode) + cisco.aci.aci_aep: + <<: *aep_present + aep: ansible_test3 + infra_vlan: false + register: nm_add_aep3 + + - name: Verify add_aep + assert: + that: + - cm_add_aep is changed + - nm_add_aep is changed + - nm_add_aep.current.0.infraAttEntityP.attributes.annotation == 'orchestrator:ansible' + - nm_add_aep2 is changed + - nm_add_aep3 is changed + - nm_add_aep.previous == nm_add_aep.previous == cm_add_aep.current == [] + - nm_add_aep.current[0].infraAttEntityP.attributes.dn == 'uni/infra/attentp-ansible_test' + - nm_add_aep.current[0].infraAttEntityP.attributes.name == 'ansible_test' + - cm_add_aep.proposed.infraAttEntityP.attributes.name == nm_add_aep.proposed.infraAttEntityP.attributes.name == cm_add_aep.sent.infraAttEntityP.attributes.name == nm_add_aep.sent.infraAttEntityP.attributes.name == 'ansible_test' + - nm_add_aep2.current[0].infraAttEntityP.children[0].infraProvAcc.attributes.name == 'provacc' + - nm_add_aep3.current[0].infraAttEntityP | length == 1 + + - name: Change AEP infra(normal mode) + cisco.aci.aci_aep: + <<: *aep_present + aep: ansible_test2 + infra_vlan: false + register: nm_add_aep_true_to_false + + - name: Change AEP infra again(normal mode) + cisco.aci.aci_aep: + <<: *aep_present + aep: ansible_test2 + infra_vlan: false + register: nm_add_aep_true_to_false_again + + - name: Add AEP again (check_mode) + cisco.aci.aci_aep: + <<: *aep_present + check_mode: true + register: cm_add_aep_again + + - name: Add AEP again (normal mode) + cisco.aci.aci_aep: + <<: *aep_present + register: nm_add_aep_again + + - name: Verify add_aep_again + assert: + that: + - cm_add_aep_again is not changed + - nm_add_aep_again is not changed + - nm_add_aep_again.previous[0].infraAttEntityP.attributes.dn == nm_add_aep_again.previous[0].infraAttEntityP.attributes.dn == cm_add_aep_again.current[0].infraAttEntityP.attributes.dn == nm_add_aep_again.current[0].infraAttEntityP.attributes.dn == 'uni/infra/attentp-ansible_test' + - nm_add_aep_again.previous[0].infraAttEntityP.attributes.name == nm_add_aep_again.previous[0].infraAttEntityP.attributes.name == cm_add_aep_again.current[0].infraAttEntityP.attributes.name == nm_add_aep_again.current[0].infraAttEntityP.attributes.name == 'ansible_test' + - cm_add_aep_again.proposed.infraAttEntityP.attributes.name == nm_add_aep_again.proposed.infraAttEntityP.attributes.name == 'ansible_test' + - cm_add_aep_again.sent == nm_add_aep_again.sent == {} + - nm_add_aep_true_to_false.current[0].infraAttEntityP | length == 1 + - nm_add_aep_true_to_false_again.current[0].infraAttEntityP | length == 1 + + # CHANGE AEP + - name: Change description of AEP (check_mode) + cisco.aci.aci_aep: + <<: *aep_present + description: Ansible test AEP + check_mode: true + register: cm_add_aep_descr + + - name: Change description of AEP (normal mode) + cisco.aci.aci_aep: + <<: *aep_present + description: Ansible test AEP + register: nm_add_aep_descr + + - name: Verify add_aep_descr + assert: + that: + - cm_add_aep_descr is changed + - nm_add_aep_descr is changed + - cm_add_aep_descr.proposed.infraAttEntityP.attributes.descr == nm_add_aep_descr.proposed.infraAttEntityP.attributes.descr == 'Ansible test AEP' + - cm_add_aep_descr.proposed.infraAttEntityP.attributes.name == nm_add_aep_descr.proposed.infraAttEntityP.attributes.name == 'ansible_test' + - cm_add_aep_descr.sent.infraAttEntityP.attributes.descr == nm_add_aep_descr.sent.infraAttEntityP.attributes.descr == 'Ansible test AEP' + - cm_add_aep_descr.previous.0.infraAttEntityP.attributes.dn == nm_add_aep_descr.previous.0.infraAttEntityP.attributes.dn == cm_add_aep_descr.current.0.infraAttEntityP.attributes.dn == 'uni/infra/attentp-ansible_test' + - cm_add_aep_descr.previous.0.infraAttEntityP.attributes.name == nm_add_aep_descr.previous.0.infraAttEntityP.attributes.name == cm_add_aep_descr.current.0.infraAttEntityP.attributes.name == 'ansible_test' + - nm_add_aep_descr.current.0.infraAttEntityP.attributes.descr == 'Ansible test AEP' + - nm_add_aep_descr.current.0.infraAttEntityP.attributes.dn == 'uni/infra/attentp-ansible_test' + - nm_add_aep_descr.current.0.infraAttEntityP.attributes.name == 'ansible_test' + + - name: Change description of AEP again (check_mode) + cisco.aci.aci_aep: + <<: *aep_present + description: Ansible test AEP + check_mode: true + register: cm_add_aep_descr_again + + - name: Change description of AEP again (normal mode) + cisco.aci.aci_aep: + <<: *aep_present + description: Ansible test AEP + register: nm_add_aep_descr_again + + - name: Verify add_aep_descr_again + assert: + that: + - cm_add_aep_descr_again is not changed + - nm_add_aep_descr_again is not changed + - cm_add_aep_descr_again.proposed.infraAttEntityP.attributes.descr == nm_add_aep_descr_again.proposed.infraAttEntityP.attributes.descr == 'Ansible test AEP' + - cm_add_aep_descr_again.proposed.infraAttEntityP.attributes.name == nm_add_aep_descr_again.proposed.infraAttEntityP.attributes.name == 'ansible_test' + - cm_add_aep_descr_again.sent == nm_add_aep_descr_again.sent == {} + - cm_add_aep_descr_again.previous[0].infraAttEntityP.attributes.descr == nm_add_aep_descr_again.previous[0].infraAttEntityP.attributes.descr == cm_add_aep_descr_again.current[0].infraAttEntityP.attributes.descr == nm_add_aep_descr_again.current[0].infraAttEntityP.attributes.descr == 'Ansible test AEP' + - cm_add_aep_descr_again.previous[0].infraAttEntityP.attributes.dn == nm_add_aep_descr_again.previous[0].infraAttEntityP.attributes.dn == cm_add_aep_descr_again.current[0].infraAttEntityP.attributes.dn == nm_add_aep_descr_again.current[0].infraAttEntityP.attributes.dn == 'uni/infra/attentp-ansible_test' + - cm_add_aep_descr_again.previous[0].infraAttEntityP.attributes.name == nm_add_aep_descr_again.previous[0].infraAttEntityP.attributes.name == cm_add_aep_descr_again.current[0].infraAttEntityP.attributes.name == nm_add_aep_descr_again.current[0].infraAttEntityP.attributes.name == 'ansible_test' + + + # ADD AEP AGAIN + - name: Add AEP again with no description (check_mode) + cisco.aci.aci_aep: *aep_present + check_mode: true + register: cm_add_aep_again_no_descr + + - name: Add AEP again with no description (normal mode) + cisco.aci.aci_aep: *aep_present + register: nm_add_aep_again_no_descr + + - name: Verify add_aep_again_no_descr + assert: + that: + - cm_add_aep_again_no_descr is not changed + - nm_add_aep_again_no_descr is not changed + - cm_add_aep_again_no_descr.proposed.infraAttEntityP.attributes.name == nm_add_aep_again_no_descr.proposed.infraAttEntityP.attributes.name == 'ansible_test' + - cm_add_aep_again_no_descr.sent == nm_add_aep_again_no_descr.sent == {} + - cm_add_aep_again_no_descr.previous[0].infraAttEntityP.attributes.descr == nm_add_aep_again_no_descr.previous[0].infraAttEntityP.attributes.descr == cm_add_aep_again_no_descr.current[0].infraAttEntityP.attributes.descr == nm_add_aep_again_no_descr.current[0].infraAttEntityP.attributes.descr == 'Ansible test AEP' + - cm_add_aep_again_no_descr.previous[0].infraAttEntityP.attributes.dn == nm_add_aep_again_no_descr.previous[0].infraAttEntityP.attributes.dn == cm_add_aep_again_no_descr.current[0].infraAttEntityP.attributes.dn == nm_add_aep_again_no_descr.current[0].infraAttEntityP.attributes.dn == 'uni/infra/attentp-ansible_test' + - cm_add_aep_again_no_descr.previous[0].infraAttEntityP.attributes.name == nm_add_aep_again_no_descr.previous[0].infraAttEntityP.attributes.name == cm_add_aep_again_no_descr.current[0].infraAttEntityP.attributes.name == nm_add_aep_again_no_descr.current[0].infraAttEntityP.attributes.name == 'ansible_test' + + + # QUERY ALL AEPS + - name: Query all AEPs (check_mode) + cisco.aci.aci_aep: &aep_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") }}' + state: query + check_mode: true + register: cm_query_all_aeps + + - name: Query all AEPs (normal mode) + cisco.aci.aci_aep: *aep_query + register: nm_query_all_aeps + + - name: Verify query_all_aeps + assert: + that: + - cm_query_all_aeps is not changed + - nm_query_all_aeps is not changed + - cm_query_all_aeps == nm_query_all_aeps + - nm_query_all_aeps.current|length >= 1 + + + # QUERY A AEP + - name: Query our AEP + cisco.aci.aci_aep: + <<: *aep_query + aep: ansible_test + check_mode: true + register: cm_query_aep + + - name: Query our AEP + cisco.aci.aci_aep: + <<: *aep_query + aep: ansible_test + register: nm_query_aep + + - name: Verify query_aep + assert: + that: + - cm_query_aep is not changed + - nm_query_aep is not changed + - cm_query_aep == nm_query_aep + - nm_query_aep.current.0.infraAttEntityP.attributes.descr == "Ansible test AEP" + - nm_query_aep.current.0.infraAttEntityP.attributes.dn == "uni/infra/attentp-ansible_test" + - nm_query_aep.current.0.infraAttEntityP.attributes.name == "ansible_test" + + + # REMOVE AEP + - name: Remove AEP (check_mode) + cisco.aci.aci_aep: + <<: *aep_absent + aep: ansible_test + check_mode: true + register: cm_remove_aep + + - name: Remove AEP (normal mode) + cisco.aci.aci_aep: + <<: *aep_absent + aep: ansible_test + register: nm_remove_aep + + - name: Verify remove_aep + assert: + that: + - cm_remove_aep is changed + - nm_remove_aep is changed + - cm_remove_aep.proposed == nm_remove_aep.proposed == {} + - cm_remove_aep.sent == nm_remove_aep.sent == {} + - cm_remove_aep.previous[0].infraAttEntityP.attributes.name == nm_remove_aep.previous[0].infraAttEntityP.attributes.name == cm_remove_aep.current[0].infraAttEntityP.attributes.name == 'ansible_test' + - cm_remove_aep.previous[0].infraAttEntityP.attributes.descr == nm_remove_aep.previous[0].infraAttEntityP.attributes.descr == cm_remove_aep.current[0].infraAttEntityP.attributes.descr == 'Ansible test AEP' + - cm_remove_aep.previous[0].infraAttEntityP.attributes.dn == nm_remove_aep.previous[0].infraAttEntityP.attributes.dn == cm_remove_aep.current[0].infraAttEntityP.attributes.dn == 'uni/infra/attentp-ansible_test' + - nm_remove_aep.current == [] + + - name: Remove AEP again (check_mode) + cisco.aci.aci_aep: + <<: *aep_absent + aep: ansible_test + check_mode: true + register: cm_remove_aep_again + + - name: Remove AEP again (normal mode) + cisco.aci.aci_aep: + <<: *aep_absent + aep: ansible_test + register: nm_remove_aep_again + + - name: Verify remove_aep_again + assert: + that: + - cm_remove_aep_again is not changed + - nm_remove_aep_again is not changed + - cm_remove_aep_again.proposed == nm_remove_aep_again.proposed == {} + - cm_remove_aep_again.sent == nm_remove_aep_again.sent == {} + - cm_remove_aep_again.previous == nm_remove_aep_again.previous == cm_remove_aep_again.current == nm_remove_aep_again.current == [] + + + # QUERY NON-EXISTING AEP + - name: Query non-existing AEP (check_mode) + cisco.aci.aci_aep: + <<: *aep_query + aep: ansible_test + check_mode: true + register: cm_query_non_aep + + - name: Query non-existing AEP (normal mode) + cisco.aci.aci_aep: + <<: *aep_query + aep: ansible_test + register: nm_query_non_aep + + - name: Verify query_non_aep + assert: + that: + - cm_query_non_aep is not changed + - nm_query_non_aep is not changed + - cm_query_non_aep == nm_query_non_aep + - cm_query_non_aep.current == nm_query_non_aep.current == [] + + + # PROVOKE ERRORS + - name: Error when required parameter is missing + 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") }}' + state: present + ignore_errors: true + register: error_on_missing_required_param + + - name: Verify error_on_missing_required_param + assert: + that: + - error_on_missing_required_param is failed + - 'error_on_missing_required_param.msg == "state is present but all of the following are missing: aep"' diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aep_to_domain/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_aep_to_domain/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aep_to_domain/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..a69d255ff --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aep_to_domain/tasks/main.yml @@ -0,0 +1,223 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.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: 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: 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") }}' + aep: test_aep + domain: phys_dom + domain_type: phys + 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") }}' + 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") }}' + domain: phys_dom + domain_type: phys + state: present + + + # 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") }}' + aep: test_aep + domain: phys_dom + domain_type: phys + state: present + check_mode: true + register: cm_add_binding + + - name: Add AEP to domain binding (normal mode) + cisco.aci.aci_aep_to_domain: *binding_present + register: nm_add_binding + + - name: Verify add_binding + assert: + that: + - cm_add_binding is changed + - nm_add_binding is changed + - nm_add_binding.current.0.infraRsDomP.attributes.annotation == 'orchestrator:ansible' + - cm_add_binding.sent.infraRsDomP.attributes.tDn == nm_add_binding.sent.infraRsDomP.attributes.tDn == 'uni/phys-phys_dom' + - cm_add_binding.proposed.infraRsDomP.attributes.tDn == nm_add_binding.proposed.infraRsDomP.attributes.tDn == 'uni/phys-phys_dom' + - cm_add_binding.current == cm_add_binding.previous == nm_add_binding.previous == [] + - nm_add_binding.current[0].infraRsDomP.attributes.dn == 'uni/infra/attentp-test_aep/rsdomP-[uni/phys-phys_dom]' + - nm_add_binding.current[0].infraRsDomP.attributes.tDn == 'uni/phys-phys_dom' + + - name: Add AEP to domain binding again (check_mode) + cisco.aci.aci_aep_to_domain: *binding_present + check_mode: true + register: cm_add_binding_again + + - name: Add AEP to domain binding again (normal mode) + cisco.aci.aci_aep_to_domain: *binding_present + register: nm_add_binding_again + + - name: Verify add_binding_again + assert: + that: + - cm_add_binding_again is not changed + - nm_add_binding_again is not changed + + + # 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") }}' + state: query + check_mode: true + register: cm_query_all_bindings + + - name: Query all AEP to domain bindings (normal mode) + cisco.aci.aci_aep_to_domain: *binding_query + register: nm_query_all_bindings + + - name: Verify query_all_bindings + assert: + that: + - cm_query_all_bindings is not changed + - nm_query_all_bindings is not changed + - cm_query_all_bindings == nm_query_all_bindings + - nm_query_all_bindings.current|length >= 1 + + + # QUERY A BINDING + - name: Query our AEP to domain binding (check_mode) + cisco.aci.aci_aep_to_domain: + <<: *binding_query + aep: test_aep + domain: phys_dom + domain_type: phys + check_mode: true + register: cm_query_binding + + - name: Query our AEP to domain binding (normal mode) + cisco.aci.aci_aep_to_domain: + <<: *binding_query + aep: test_aep + domain: phys_dom + domain_type: phys + register: nm_query_binding + + - name: Verify query_binding + assert: + that: + - cm_query_binding is not changed + - nm_query_binding is not changed + - cm_query_binding == nm_query_binding + - nm_query_binding.current.0.infraRsDomP.attributes.dn == 'uni/infra/attentp-test_aep/rsdomP-[uni/phys-phys_dom]' + - nm_query_binding.current.0.infraRsDomP.attributes.tCl == 'physDomP' + - nm_query_binding.current.0.infraRsDomP.attributes.tDn == 'uni/phys-phys_dom' + + + # REMOVE BINDING + - name: Remove AEP to domain binding (check_mode) + cisco.aci.aci_aep_to_domain: *binding_absent + check_mode: true + register: cm_remove_binding + + - name: Remove AEP to domain binding (normal mode) + cisco.aci.aci_aep_to_domain: *binding_absent + register: nm_remove_binding + + - name: Verify remove_binding + assert: + that: + - cm_remove_binding is changed + - nm_remove_binding is changed + - cm_remove_binding.current.0.infraRsDomP.attributes.dn == cm_remove_binding.previous.0.infraRsDomP.attributes.dn == nm_remove_binding.previous.0.infraRsDomP.attributes.dn == 'uni/infra/attentp-test_aep/rsdomP-[uni/phys-phys_dom]' + - cm_remove_binding.current.0.infraRsDomP.attributes.tDn == cm_remove_binding.previous.0.infraRsDomP.attributes.tDn == nm_remove_binding.previous.0.infraRsDomP.attributes.tDn == 'uni/phys-phys_dom' + - nm_remove_binding.current == [] + + - name: Remove AEP to domain binding again (check_mode) + cisco.aci.aci_aep_to_domain: *binding_absent + check_mode: true + register: cm_remove_binding_again + + - name: Remove AEP to domain binding again (normal mode) + cisco.aci.aci_aep_to_domain: *binding_absent + register: nm_remove_binding_again + + - name: Verify remove_binding_again + assert: + that: + - cm_remove_binding_again is not changed + - nm_remove_binding_again is not changed + + + # QUERY NON-EXISTING BINDING + - name: Query non-existing AEP to domain binding (check_mode) + cisco.aci.aci_aep_to_domain: + <<: *binding_query + aep: test_aep + domain: phys_dom + domain_type: phys + check_mode: true + register: cm_query_non_binding + + - name: Query non-existing AEP to domain binding (normal mode) + cisco.aci.aci_aep_to_domain: + <<: *binding_query + aep: test_aep + domain: phys_dom + domain_type: phys + register: nm_query_non_binding + + - name: Verify query_non_binding + assert: + that: + - cm_query_non_binding is not changed + - nm_query_non_binding is not changed + - cm_query_non_binding == nm_query_non_binding + - nm_query_non_binding.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aep_to_epg/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_aep_to_epg/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aep_to_epg/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_aep_to_epg/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_aep_to_epg/tasks/main.yml new file mode 100644 index 000000000..86ee212bd --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_aep_to_epg/tasks/main.yml @@ -0,0 +1,235 @@ +# Test code for the aep_to_epg ACI module +# Author: Marcel Zehnder (@maercu) +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# 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 execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # CLEAN ENVIRONMENT + - name: Remove test aep before we kickoff + cisco.aci.aci_aep: &aep_absent + <<: *aci_info + aep: epg2aep + state: absent + + # SETUP TEST AEP AND EPGS + - name: Create AEP + cisco.aci.aci_aep: &aep_present + <<: *aci_info + aep: epg2aep + state: present + + - name: Create Tenant + cisco.aci.aci_tenant: &tenant_present + <<: *aci_info + tenant: ansible_test + state: present + + - name: Configure VRF + cisco.aci.aci_vrf: + <<: *tenant_present + vrf: epg2aep + + - name: Configure BD + cisco.aci.aci_bd: + <<: *tenant_present + vrf: epg2aep + bd: epg2aep + + - name: Configure Ap + cisco.aci.aci_ap: + <<: *tenant_present + ap: ap + + - name: Configure EPG + cisco.aci.aci_epg: + <<: *tenant_present + ap: ap + epg: '{{ item }}' + bd: epg2aep + loop: + - epg1 + - epg2 + + # ADD ASSOCIATION + - name: Add EPG to AEP association (check_mode) + cisco.aci.aci_aep_to_epg: &assoc_present + <<: *aep_present + tenant: ansible_test + ap: ap + epg: epg1 + encap: 1984 + interface_mode: trunk + check_mode: true + register: cm_add_assoc + + - name: Add EPG to AEP association (normal mode) + cisco.aci.aci_aep_to_epg: + <<: *assoc_present + register: nm_add_assoc + + - name: Verify add_assoc + assert: + that: + - cm_add_assoc is changed + - nm_add_assoc is changed + - nm_add_assoc.current.0.infraGeneric.attributes.annotation == 'orchestrator:ansible' + - cm_add_assoc.previous == nm_add_assoc.previous == [] + - cm_add_assoc.sent.infraGeneric.children[0].infraRsFuncToEpg.attributes.encap == nm_add_assoc.sent.infraGeneric.children[0].infraRsFuncToEpg.attributes.encap == 'vlan-1984' + - cm_add_assoc.sent.infraGeneric.children[0].infraRsFuncToEpg.attributes.mode == nm_add_assoc.sent.infraGeneric.children[0].infraRsFuncToEpg.attributes.mode == 'regular' + - cm_add_assoc.sent.infraGeneric.children[0].infraRsFuncToEpg.attributes.tDn == nm_add_assoc.sent.infraGeneric.children[0].infraRsFuncToEpg.attributes.tDn == 'uni/tn-ansible_test/ap-ap/epg-epg1' + + - name: Add EPG to AEP association again, check if idempotency works (check_mode) + cisco.aci.aci_aep_to_epg: + <<: *assoc_present + check_mode: true + register: cm_add_assoc_again + + - name: Add EPG to AEP association again, check if idempotency works (normal_mode) + cisco.aci.aci_aep_to_epg: + <<: *assoc_present + register: nm_add_assoc_again + + - name: Verify add_assoc_again + assert: + that: + - cm_add_assoc_again is not changed + - nm_add_assoc_again is not changed + + # UPDATE ASSOCIATION + - name: Change encap (check_mode) + cisco.aci.aci_aep_to_epg: &assoc_update + <<: *assoc_present + encap: 1985 + primary_encap: 1986 + check_mode: true + register: cm_update_assoc + + - name: Change encap (normal_mode) + cisco.aci.aci_aep_to_epg: + <<: *assoc_update + register: nm_update_assoc + + - name: Verify update_assoc + assert: + that: + - cm_update_assoc is changed + - nm_update_assoc is changed + - cm_update_assoc.previous == nm_update_assoc.previous != [] + - cm_update_assoc.sent.infraGeneric.children[0].infraRsFuncToEpg.attributes.encap == nm_update_assoc.sent.infraGeneric.children[0].infraRsFuncToEpg.attributes.encap == 'vlan-1985' + - cm_update_assoc.sent.infraGeneric.children[0].infraRsFuncToEpg.attributes.primaryEncap == nm_update_assoc.sent.infraGeneric.children[0].infraRsFuncToEpg.attributes.primaryEncap == 'vlan-1986' + + # ADD ANOTHER ASSOCIATION + - name: Add another EPG to AEP association + cisco.aci.aci_aep_to_epg: + <<: *assoc_present + epg: epg2 + encap: 1990 + + # QUERY ALL ASSOCIATIONS + - name: Query all EPG to AEP association + cisco.aci.aci_aep_to_epg: + <<: *aci_info + state: query + register: query_all_assocs + + - name: Verify query_all_assocs + assert: + that: + - query_all_assocs is not changed + - query_all_assocs.current|length >= 1 + + # QUERY A SPECIFIC ASSOCIATION + - name: Query a specific EPG to AEP association + cisco.aci.aci_aep_to_epg: + <<: *assoc_update + state: query + register: query_spec_assoc + + - name: Verify query_spec_assoc + assert: + that: + - query_spec_assoc is not changed + - query_spec_assoc.current|length == 1 + + # REMOVE A SPECIFIC ASSOCIATION + - name: Remove EPG1 to AEP association (check_mode) + cisco.aci.aci_aep_to_epg: &assoc_remove + <<: *assoc_update + state: absent + check_mode: true + register: cm_remove_spec_assoc + + - name: Remove EPG1 to AEP association (normal mode) + cisco.aci.aci_aep_to_epg: + <<: *assoc_remove + register: nm_remove_spec_assoc + + - name: Verify remove_spec_assoc + assert: + that: + - cm_remove_spec_assoc is changed + - nm_remove_spec_assoc is changed + - nm_remove_spec_assoc.current == [] + + - name: Remove EPG1 to AEP association again (normal mode) + cisco.aci.aci_aep_to_epg: + <<: *assoc_remove + register: nm_remove_spec_assoc_again + + - name: Verify remove_spec_assoc_again + assert: + that: + - nm_remove_spec_assoc_again is not changed + + # QUERY A STILL EXISTING ASSOCIATION + - name: Query EPG2 to AEP association + cisco.aci.aci_aep_to_epg: + <<: *assoc_present + epg: epg2 + state: query + register: query_existing_assoc + + - name: Verify query_existing_assoc + assert: + that: + - query_existing_assoc is not changed + - query_existing_assoc.current|length == 1 + + # QUERY NON-EXISTING ASSOCIATION + - name: Query non-existing EPG to AEP association (normal mode) + cisco.aci.aci_aep_to_epg: + <<: *assoc_update + state: query + register: nm_query_non_exist + + - name: Verify nm_query_non_exist + assert: + that: + - nm_query_non_exist is not changed + - nm_query_non_exist.current == [] + + # CLEANUP + - name: Cleanup AEP + cisco.aci.aci_aep: + <<: *aep_absent + + - name: Delete Tenant + cisco.aci.aci_tenant: + <<: *tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_ap/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_ap/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_ap/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_ap/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_ap/tasks/main.yml new file mode 100644 index 000000000..c527a9059 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_ap/tasks/main.yml @@ -0,0 +1,202 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) +# Copyright: (c) 2020, Shreyas Srish (@shrsr) + +# 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: ensure tenant does not exists + cisco.aci.aci_tenant: &aci_tenant_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 + 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 + register: tenant_present + + - name: ensure monitoring policy exists + cisco.aci.aci_epg_monitoring_policy: + 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 + monitoring_policy: check + tenant: ansible_test + + - name: ensure ap does not exist initially + cisco.aci.aci_ap: + <<: *aci_tenant_present + ap: anstest + state: absent + + - name: create ap - check mode works + cisco.aci.aci_ap: &aci_ap_present + <<: *aci_tenant_present + ap: anstest + description: Ansible Test + monitoring_policy: check + check_mode: true + register: ap_present_check_mode + + - name: create ap - creation works + cisco.aci.aci_ap: + <<: *aci_ap_present + register: ap_present + + - name: create ap - extra for query + cisco.aci.aci_ap: + <<: *aci_tenant_present + ap: anstest2 + + - name: create ap - idempotency works + cisco.aci.aci_ap: + <<: *aci_ap_present + register: ap_present_idempotent + + - name: update ap - update works + cisco.aci.aci_ap: + <<: *aci_ap_present + description: Ansible Test Update + register: ap_present_update + + - name: create ap - creation works + cisco.aci.aci_ap: + <<: *aci_tenant_present + ignore_errors: true + register: ap_present_missing_param + + - name: present asserts + assert: + that: + - ap_present_check_mode is changed + - ap_present is changed + - ap_present.previous == [] + - ap_present.current.0.fvAp.children.0.fvRsApMonPol.attributes.tnMonEPGPolName == 'check' + - ap_present.current.0.fvAp.attributes.annotation == 'orchestrator:ansible' + - ap_present.sent == ap_present_check_mode.sent + - ap_present.sent.fvAp.attributes.descr == 'Ansible Test' + - ap_present.sent.fvAp.attributes.name == 'anstest' + - ap_present_idempotent is not changed + - ap_present_idempotent.previous != [] + - ap_present_idempotent.sent == {} + - ap_present_update is changed + - ap_present_update.sent.fvAp.attributes.descr == 'Ansible Test Update' + - ap_present_missing_param is failed + - 'ap_present_missing_param.msg == "state is present but all of the following are missing: ap"' + + - name: get ap - query specific ap + cisco.aci.aci_ap: &aci_ap_query + <<: *aci_ap_present + state: query + register: query_ap + + - name: get all ap for tenant - query tenant aps + cisco.aci.aci_ap: + <<: *aci_ap_query + ap: "{{ fakevar | default(omit) }}" + register: query_ap_tenant + + - name: get all ap by name - query ap name + cisco.aci.aci_ap: + <<: *aci_ap_query + tenant: "{{ fakevar | default(omit) }}" + register: query_ap_ap + + - name: get all aps - query general + cisco.aci.aci_ap: + <<: *aci_ap_query + tenant: "{{ fakevar | default(omit) }}" + ap: "{{ fakevar | default(omit) }}" + register: query_all + + - name: query assertions + assert: + that: + - query_ap is not changed + - query_ap.current | length == 1 + - query_ap.current.0.fvAp.attributes.name == "anstest" + - query_ap.current.0.fvAp.children.0.fvRsApMonPol.attributes.tnMonEPGPolName == 'check' + - '"tn-ansible_test/ap-anstest.json" in query_ap.url' + - query_ap_tenant is not changed + - query_ap_tenant.current | length == 1 + - query_ap_tenant.current.0.fvTenant.children | length == 2 + - '"rsp-subtree-class=fvAp" in query_ap_tenant.filter_string' + - '"tn-ansible_test.json" in query_ap_tenant.url' + - query_ap_ap is not changed + - query_ap_ap.current != [] + - query_ap_ap.current.0.fvAp is defined + - '"query-target-filter=eq(fvAp.name,\"anstest\")" in query_ap_ap.filter_string' + - '"class/fvAp.json" in query_ap_ap.url' + - query_all is not changed + - query_all.current | length > 1 + - '"class/fvAp.json" in query_all.url' + + - name: delete ap - check_mode works + cisco.aci.aci_ap: &aci_ap_absent + <<: *aci_ap_present + state: absent + check_mode: true + register: ap_delete_check_mode + + - name: delete ap - delete works + cisco.aci.aci_ap: + <<: *aci_ap_absent + register: ap_delete + + - name: delete ap - delete idempotency works + cisco.aci.aci_ap: + <<: *aci_ap_absent + register: ap_delete_idempotent + + - name: delete ap - missing param error + cisco.aci.aci_ap: + <<: *aci_ap_absent + tenant: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: ap_delete_missing_param + + - name: delete ap remove ap used for query + cisco.aci.aci_ap: + <<: *aci_ap_absent + ap: anstest2 + + - name: absent assertions + assert: + that: + - ap_delete_check_mode is changed + - ap_delete_check_mode.previous != [] + - '"tn-ansible_test/ap-anstest.json" in ap_delete_check_mode.url' + - ap_delete is changed + - ap_delete.previous == ap_delete_check_mode.previous + - ap_delete_idempotent is not changed + - ap_delete_idempotent.previous == [] + - ap_delete_missing_param is failed + - 'ap_delete_missing_param.msg == "state is absent but all of the following are missing: tenant"' + + - 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_bd/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd/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/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd/tasks/main.yml new file mode 100644 index 000000000..3af05fd0f --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd/tasks/main.yml @@ -0,0 +1,312 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) + +# 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 + register: tenant_present + + - name: ensure vrf exists for tests to kick off + cisco.aci.aci_vrf: &aci_vrf_present + <<: *aci_tenant_present + vrf: anstest + register: vrf_present + + - name: ensure bd anstest does not exist + cisco.aci.aci_bd: + <<: *aci_tenant_present + bd: anstest + state: absent + + - name: ensure bd anstest2 does not exist + cisco.aci.aci_bd: + <<: *aci_tenant_present + bd: anstest2 + state: absent + + - name: ensure L3out exists + cisco.aci.aci_l3out: &aci_l3_out_present + <<: *aci_tenant_present + tenant: ansible_test + l3out: ansible_l3out + domain: ansible_dom + route_control: export + vrf: anstest + l3protocol: ospf + state: present + + - name: create bd - check mode works + cisco.aci.aci_bd: &aci_bd_present + <<: *aci_tenant_present + bd: anstest + description: Ansible Test + check_mode: true + register: bd_present_check_mode + + - name: create bd - creation works + cisco.aci.aci_bd: + <<: *aci_bd_present + register: bd_present + + - name: create bd again - idempotency works + cisco.aci.aci_bd: + <<: *aci_bd_present + register: bd_present_idempotent + + - name: update bd - update works + cisco.aci.aci_bd: + <<: *aci_bd_present + vrf: anstest + description: Ansible Test Update + register: bd_update + + - name: create another bd - check more params + cisco.aci.aci_bd: + <<: *aci_bd_present + bd: anstest2 + bd_type: ethernet + endpoint_move_detect: default + ip_learning: "no" + l2_unknown_unicast: flood + l3_unknown_multicast: opt-flood + multi_dest: drop + enable_routing: "no" + arp_flooding: "yes" + route_profile_l3out: ansible_l3out + route_profile: ansible_l3out_route + register: bd_present_2 + when: version.current.0.topSystem.attributes.version is version('4.2', '<') + + - name: create another bd - check more params (>v4.2) + cisco.aci.aci_bd: + <<: *aci_bd_present + bd: anstest2 + bd_type: ethernet + endpoint_move_detect: default + ip_learning: "no" + l2_unknown_unicast: flood + l3_unknown_multicast: opt-flood + ipv6_l3_unknown_multicast: opt-flood + multi_dest: drop + enable_routing: "no" + arp_flooding: "yes" + route_profile_l3out: ansible_l3out + route_profile: ansible_l3out_route + register: bd_present_2b + when: version.current.0.topSystem.attributes.version is version('4.2', '>=') + + - name: create bd without all necessary params - failure message works + cisco.aci.aci_bd: + <<: *aci_bd_present + tenant: "{{ fake_var | default(omit) }}" + ignore_errors: true + register: bd_present_missing_param + + - name: present asserts (<v4.2) + assert: + that: + - bd_present_check_mode is changed + - bd_present_check_mode.sent.fvBD.attributes.descr == 'Ansible Test' + - bd_present_check_mode.sent.fvBD.attributes.name == 'anstest' + - bd_present is changed + - bd_present.current.0.fvBD.attributes.annotation == 'orchestrator:ansible' + - bd_present.sent == bd_present_check_mode.sent + - bd_present.previous == [] + - bd_present_idempotent is not changed + - bd_present_idempotent.previous != [] + - bd_update is changed + - bd_update.previous != [] + - bd_update.sent != bd_update.proposed + - bd_update.sent.fvBD.attributes.descr == 'Ansible Test Update' + - bd_update.sent.fvBD.children.0.fvRsCtx.attributes.tnFvCtxName == 'anstest' + - bd_present_2.sent.fvBD.attributes.arpFlood == 'yes' + - bd_present_2.sent.fvBD.attributes.descr == 'Ansible Test' + - bd_present_2.sent.fvBD.attributes.ipLearning == 'no' + - bd_present_2.sent.fvBD.attributes.multiDstPktAct == 'drop' + - bd_present_2.sent.fvBD.attributes.name == 'anstest2' + - bd_present_2.sent.fvBD.attributes.unicastRoute == 'no' + - bd_present_2.sent.fvBD.attributes.unkMacUcastAct == 'flood' + - bd_present_2.sent.fvBD.attributes.unkMcastAct == 'opt-flood' + - bd_present_2.sent.fvBD.attributes.type == 'regular' + - bd_present_2.sent.fvBD.children.0.fvRsBDToProfile.attributes.tnL3extOutName == 'ansible_l3out' + - bd_present_2.sent.fvBD.children.0.fvRsBDToProfile.attributes.tnRtctrlProfileName == 'ansible_l3out_route' + - bd_present_missing_param is failed + - 'bd_present_missing_param.msg == "state is present but all of the following are missing: tenant"' + when: version.current.0.topSystem.attributes.version is version('4.2', '<') + + - name: present asserts (>v4.2) + assert: + that: + - bd_present_check_mode is changed + - bd_present_check_mode.sent.fvBD.attributes.descr == 'Ansible Test' + - bd_present_check_mode.sent.fvBD.attributes.name == 'anstest' + - bd_present is changed + - bd_present.sent == bd_present_check_mode.sent + - bd_present.previous == [] + - bd_present_idempotent is not changed + - bd_present_idempotent.previous != [] + - bd_update is changed + - bd_update.previous != [] + - bd_update.sent != bd_update.proposed + - bd_update.sent.fvBD.attributes.descr == 'Ansible Test Update' + - bd_update.sent.fvBD.children.0.fvRsCtx.attributes.tnFvCtxName == 'anstest' + - bd_present_2b.sent.fvBD.attributes.arpFlood == 'yes' + - bd_present_2b.sent.fvBD.attributes.descr == 'Ansible Test' + - bd_present_2b.sent.fvBD.attributes.ipLearning == 'no' + - bd_present_2b.sent.fvBD.attributes.multiDstPktAct == 'drop' + - bd_present_2b.sent.fvBD.attributes.name == 'anstest2' + - bd_present_2b.sent.fvBD.attributes.unicastRoute == 'no' + - bd_present_2b.sent.fvBD.attributes.unkMacUcastAct == 'flood' + - bd_present_2b.sent.fvBD.attributes.unkMcastAct == 'opt-flood' + - bd_present_2b.sent.fvBD.attributes.v6unkMcastAct == 'opt-flood' + - bd_present_2b.sent.fvBD.attributes.type == 'regular' + - bd_present_2b.sent.fvBD.children.0.fvRsBDToProfile.attributes.tnL3extOutName == 'ansible_l3out' + - bd_present_2b.sent.fvBD.children.0.fvRsBDToProfile.attributes.tnRtctrlProfileName == 'ansible_l3out_route' + - bd_present_missing_param is failed + - 'bd_present_missing_param.msg == "state is present but all of the following are missing: tenant"' + when: version.current.0.topSystem.attributes.version is version('4.2', '>=') + + - name: get all bd + cisco.aci.aci_bd: &aci_query + <<: *aci_tenant_present + state: query + tenant: "{{ fake_var | default(omit) }}" + register: query_all + + - name: get all in tenant + cisco.aci.aci_bd: + <<: *aci_query + tenant: ansible_test + register: query_tenant + + - name: get all with name + cisco.aci.aci_bd: + <<: *aci_query + bd: anstest + register: query_bd_bd + + - name: get bd + cisco.aci.aci_bd: + <<: *aci_bd_present + state: query + register: query_bd + + - name: query asserts + assert: + that: + - query_all is not changed + - query_all.current | length > 1 + - query_all.current.0.fvBD is defined + - '"rsp-subtree-class=fvRsBDToNdP,fvRsBDToProfile,fvRsBdToEpRet,fvRsCtx,fvRsIgmpsn" in query_all.filter_string' + - '"class/fvBD.json" in query_all.url' + - query_tenant is not changed + - query_tenant.current | length == 1 + - query_tenant.current.0.fvTenant.children | length == 2 + - '"rsp-subtree-class=fvBD,fvRsBDToNdP,fvRsBDToProfile,fvRsBdToEpRet,fvRsCtx,fvRsIgmpsn" in query_tenant.filter_string' + - '"tn-ansible_test.json" in query_tenant.url' + - query_bd_bd is not changed + - query_bd_bd.current != [] + - '"query-target-filter=eq(fvBD.name,\"anstest\")" in query_bd_bd.filter_string' + - '"rsp-subtree-class=fvRsBDToNdP,fvRsBDToProfile,fvRsBdToEpRet,fvRsCtx,fvRsIgmpsn" in query_bd_bd.filter_string' + - '"class/fvBD.json" in query_bd_bd.url' + - query_bd is not changed + - query_bd.current | length == 1 + - query_bd.current.0.fvBD.attributes.name == "anstest" + - '"rsp-subtree-class=fvRsBDToNdP,fvRsBDToProfile,fvRsBdToEpRet,fvRsCtx,fvRsIgmpsn" in query_bd.filter_string' + - '"tn-ansible_test/BD-anstest.json" in query_bd.url' + + - name: delete bd - check mode works + cisco.aci.aci_bd: &aci_bd_absent + <<: *aci_bd_present + state: absent + check_mode: true + register: bd_absent_check_mode + + - name: delete bd - delete works + cisco.aci.aci_bd: + <<: *aci_bd_absent + register: bd_absent + + - name: delete bd again - idempotency works + cisco.aci.aci_bd: + <<: *aci_bd_absent + register: bd_absent_idempotent + + - name: delete bd - cleanup + cisco.aci.aci_bd: + <<: *aci_bd_absent + bd: anstest2 + + - name: delete bd missing param - fails properly + cisco.aci.aci_bd: + <<: *aci_bd_absent + bd: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: bd_absent_missing_param + + - name: asserts for deletion task + assert: + that: + - bd_absent_check_mode is changed + - bd_absent_check_mode.proposed == {} + - bd_absent is changed + - bd_absent.previous != [] + - bd_absent_idempotent is not changed + - bd_absent_idempotent.previous == [] + - bd_absent_missing_param is failed + - 'bd_absent_missing_param.msg == "state is absent but all of the following are missing: bd"' + + - name: delete vrf - cleanup before ending tests + cisco.aci.aci_vrf: + <<: *aci_vrf_present + state: absent + when: vrf_present is changed + + - name: delete l3out - cleanup before ending tests + cisco.aci.aci_l3out: + <<: *aci_l3_out_present + state: absent + + - 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_bd_dhcp_label/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_dhcp_label/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_dhcp_label/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_dhcp_label/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_dhcp_label/tasks/main.yml new file mode 100644 index 000000000..937ea80a3 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_dhcp_label/tasks/main.yml @@ -0,0 +1,154 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Shreyas Srish (@shrsr) + +# 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: create bd - creation works + aci_bd: + <<: *aci_info + tenant: ansible_tenant + bd: database + register: bd_present + + #CREATE LABELS + - name: Create a new DHCP Relay Label to a Bridge Domain - check mode + aci_bd_dhcp_label: + <<: *aci_info + tenant: ansible_tenant + bd: database + dhcp_label: label1 + owner: infra + state: present + check_mode: true + register: cm_dhcp_label1 + + - name: Verify creation of label1 in check mode + assert: + that: + - cm_dhcp_label1 is changed + - cm_dhcp_label1.sent.dhcpLbl.attributes.name == 'label1' + + - name: Create a new DHCP Relay Label to a Bridge Domain - normal mode + aci_bd_dhcp_label: + <<: *aci_info + tenant: ansible_tenant + bd: database + dhcp_label: label1 + owner: infra + state: present + register: nm_dhcp_label1 + + - name: Verify creation of label1 + assert: + that: + - nm_dhcp_label1 is changed + - nm_dhcp_label1.current.0.dhcpLbl.attributes.dn == 'uni/tn-ansible_tenant/BD-database/dhcplbl-label1' + - nm_dhcp_label1.current.0.dhcpLbl.attributes.name == 'label1' + - nm_dhcp_label1.current.0.dhcpLbl.attributes.annotation == 'orchestrator:ansible' + + - name: Create another DHCP Relay Label to a Bridge Domain - normal mode + aci_bd_dhcp_label: + <<: *aci_info + tenant: ansible_tenant + bd: database + dhcp_label: label2 + owner: infra + state: present + register: nm_dhcp_label2 + + - name: Verify creation of label2 + assert: + that: + - nm_dhcp_label2 is changed + - nm_dhcp_label2.current.0.dhcpLbl.attributes.dn == 'uni/tn-ansible_tenant/BD-database/dhcplbl-label2' + - nm_dhcp_label2.current.0.dhcpLbl.attributes.name == 'label2' + + #QUERY LABELS + - name: Query a DHCP Relay Label of a Bridge Domain + aci_bd_dhcp_label: + <<: *aci_info + tenant: ansible_tenant + bd: database + dhcp_label: label1 + owner: infra + state: query + register: query_dhcp_label1 + + - name: Verify query of label + assert: + that: + - query_dhcp_label1 is not changed + - query_dhcp_label1.current.0.dhcpLbl.attributes.dn == 'uni/tn-ansible_tenant/BD-database/dhcplbl-label1' + + - name: Query all DHCP Relay Labels of a Bridge Domain + aci_bd_dhcp_label: + <<: *aci_info + tenant: ansible_tenant + bd: database + state: query + register: query_all_labels + + - name: Verify query all of labels + assert: + that: + - query_all_labels is not changed + + #REMOVE LABELS + - name: Remove a DHCP Relay Label for a Bridge Domain + aci_bd_dhcp_label: + <<: *aci_info + tenant: ansible_tenant + bd: database + dhcp_label: label1 + owner: infra + state: absent + register: delete_dhcp_label + + - name: Verify deletion of label + assert: + that: + - delete_dhcp_label is changed + - delete_dhcp_label.current == [] + + # CLEAN ENVIRONMENT AGAIN + - name: Remove the ansible_tenant + aci_tenant: + <<: *aci_info + tenant: ansible_tenant + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_subnet/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_subnet/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_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_bd_subnet/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_subnet/tasks/main.yml new file mode 100644 index 000000000..10f00990c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bd_subnet/tasks/main.yml @@ -0,0 +1,247 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) + +# 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 + 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 + tenant: ansible_test + register: tenant_present + + - name: ensure bd exists for tests to kick off + cisco.aci.aci_bd: &aci_bd_present + <<: *aci_tenant_present + bd: anstest + register: bd_present + + - name: ensure subnet does not exist for tests to kick off + cisco.aci.aci_bd_subnet: &aci_subnet_absent + <<: *aci_bd_present + state: absent + gateway: 10.100.100.1 + mask: 24 + + - name: ensure subnet does not exist for tests to kick off + cisco.aci.aci_bd_subnet: &aci_subnet2_absent + <<: *aci_subnet_absent + gateway: 10.100.101.1 + mask: 25 + + - name: create subnet - check mode works + cisco.aci.aci_bd_subnet: &aci_subnet_present + <<: *aci_subnet_absent + state: present + subnet_name: anstest + descr: Ansible Test + check_mode: true + register: create_check_mode + + - name: create subnet - creation works + cisco.aci.aci_bd_subnet: + <<: *aci_subnet_present + register: create_subnet + + - name: create new subnet - creation works + cisco.aci.aci_bd_subnet: &aci_subnet2_present + <<: *aci_subnet2_absent + state: present + descr: Ansible Test + scope: [private, shared] + route_profile: default + route_profile_l3_out: default + register: create_subnet2 + + - name: create subnet again - idempotency works + cisco.aci.aci_bd_subnet: + <<: *aci_subnet2_present + register: create_idempotency + + - name: modify subnet - update works + cisco.aci.aci_bd_subnet: + <<: *aci_subnet_present + scope: [shared, public] + subnet_control: querier_ip + register: modify_subnet + + - name: create subnet with bad scope - failure message works + cisco.aci.aci_bd_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_bd_subnet: + <<: *aci_subnet_present + bd: "{{ fake_var | default(omit) }}" + register: create_incomplete_data + 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_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 + - modify_subnet.previous != [] + - modify_subnet.sent != modify_subnet.proposed + - modify_subnet.sent.fvSubnet.attributes.ctrl == 'querier' + - modify_subnet.sent.fvSubnet.attributes.scope == 'public,shared' + - 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: bd"' + + - name: get all subnets + cisco.aci.aci_bd_subnet: &aci_query + <<: *aci_tenant_present + state: query + tenant: "{{ fake_var | default(omit) }}" + register: get_all + + - name: get all in tenant + cisco.aci.aci_bd_subnet: + <<: *aci_query + tenant: ansible_test + register: get_all_tenant + + - name: get all in bd + cisco.aci.aci_bd_subnet: + <<: *aci_query + bd: anstest + register: get_all_bd + + - name: get all tenant and bd + cisco.aci.aci_bd_subnet: + <<: *aci_bd_present + state: query + register: get_all_tenant_bd + + - name: get subnet in tenant + cisco.aci.aci_bd_subnet: + <<: *aci_subnet_present + state: query + bd: "{{ fake_var | default(omit) }}" + register: get_subnet_tenant + + - name: get subnet in bd + cisco.aci.aci_bd_subnet: + <<: *aci_subnet_present + state: query + tenant: "{{ fake_var | default(omit) }}" + register: get_subnet_bd + + - name: get specific subnet + cisco.aci.aci_bd_subnet: + <<: *aci_subnet_present + state: query + register: get_subnet + + - name: get all subnets matching gateway + cisco.aci.aci_bd_subnet: + <<: *aci_subnet_present + state: query + tenant: "{{ fake_var | default(omit) }}" + bd: "{{ fake_var | default(omit) }}" + register: get_subnets_gateway + + - name: asserts for query tasks + assert: + that: + - get_all is not changed + - get_all.current | length > 1 + - get_all_tenant is not changed + - '"tn-ansible_test.json" in get_all_tenant.url' + - get_all_bd is not changed + - '"query-target-filter=eq(fvBD.name,\"anstest\")" in get_all_bd.filter_string' + - '"class/fvBD.json" in get_all_bd.url' + - get_all_tenant_bd is not changed + - '"tn-ansible_test/BD-anstest.json" in get_all_tenant_bd.url' + - get_all_tenant_bd.current.0.fvBD.children | length > 1 + - get_subnet_tenant is not changed + - '"rsp-subtree-filter=eq(fvSubnet.ip,\"10.100.100.1/24\")" in get_subnet_tenant.filter_string' + - '"tn-ansible_test.json" in get_subnet_tenant.url' + - get_subnet_bd is not changed + - '"query-target-filter=eq(fvBD.name,\"anstest\")"' + - '"rsp-subtree-filter=eq(fvSubnet.ip,\"10.100.100.1/24\")" in get_subnet_bd.filter_string' + - '"class/fvBD.json" in get_subnet_bd.url' + - get_subnet is not changed + - get_subnet.current | length == 1 + - '"tn-ansible_test/BD-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_bd_subnet: + <<: *aci_subnet_absent + check_mode: true + register: delete_check_mode + + - name: delete subnet - delete works + cisco.aci.aci_bd_subnet: + <<: *aci_subnet_absent + register: delete_subnet + + - name: delete subnet - cleanup + cisco.aci.aci_bd_subnet: + <<: *aci_subnet2_absent + + - name: delete subnet again - idempotency works + cisco.aci.aci_bd_subnet: + <<: *aci_subnet2_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 bd - cleanup before ending tests + cisco.aci.aci_bd: + <<: *aci_bd_present + state: absent + when: bd_present is changed + + - 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_bgp_rr_asn/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_rr_asn/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_rr_asn/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_rr_asn/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_rr_asn/tasks/main.yml new file mode 100644 index 000000000..3b65520bc --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_rr_asn/tasks/main.yml @@ -0,0 +1,87 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove BGP Route Reflector ASN if it already exists + cisco.aci.aci_bgp_rr_asn: + <<: *aci_info + state: absent + +# ADD ROUTE REFLECTOR BGP ASN +- name: Add BGP Route Reflector ASN + cisco.aci.aci_bgp_rr_asn: + <<: *aci_info + asn: 65001 + state: present + register: add_bgp_rr_asn + +- name: Verify that BGP route reflector ASN has been created with correct attributes + assert: + that: + - add_bgp_rr_asn is changed + - add_bgp_rr_asn.current.0.bgpAsP.attributes.annotation == 'orchestrator:ansible' + - add_bgp_rr_asn.current.0.bgpAsP.attributes.dn == "uni/fabric/bgpInstP-default/as" + - add_bgp_rr_asn.current.0.bgpAsP.attributes.asn == "65001" + +# ADD ROUTE REFLECTOR ASN AGAIN TO TEST IDEMPOTENCE +- name: Add BGP route reflector ASN again + cisco.aci.aci_bgp_rr_asn: + <<: *aci_info + asn: 65001 + state: present + register: add_bgp_rr_asn_again + +- name: Verify that BGP route reflector ASN idempotence + assert: + that: + - add_bgp_rr_asn_again is not changed + - add_bgp_rr_asn_again.current.0.bgpAsP.attributes.dn == "uni/fabric/bgpInstP-default/as" + - add_bgp_rr_asn_again.current.0.bgpAsP.attributes.asn == "65001" + +# MODIFY ROUTE REFLECTOR ASN +- name: Update BGP route reflector ASN + cisco.aci.aci_bgp_rr_asn: + <<: *aci_info + asn: 65002 + state: present + register: update_bgp_rr_asn + +- name: Verify that BGP route reflector ASN has been updated with correct attributes + assert: + that: + - update_bgp_rr_asn is changed + - update_bgp_rr_asn.current.0.bgpAsP.attributes.dn == "uni/fabric/bgpInstP-default/as" + - update_bgp_rr_asn.current.0.bgpAsP.attributes.asn == "65002" + +# QUERY ROUTE REFLECTOR ASN +- name: Query BGP route reflector ASN + cisco.aci.aci_bgp_rr_asn: + <<: *aci_info + state: query + register: query_bgp_rr_asn + +- name: Verify BGP route reflector ASN + assert: + that: + - query_bgp_rr_asn is not changed + - query_bgp_rr_asn.current.0.bgpAsP.attributes.dn == "uni/fabric/bgpInstP-default/as" + - query_bgp_rr_asn.current.0.bgpAsP.attributes.asn == "65002" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_rr_node/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_rr_node/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_rr_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_bgp_rr_node/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_rr_node/tasks/main.yml new file mode 100644 index 000000000..d1ec77a27 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bgp_rr_node/tasks/main.yml @@ -0,0 +1,132 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove BGP Route Reflector Node 101 if it already exists + cisco.aci.aci_bgp_rr_node: + <<: *aci_info + node_id: 101 + state: absent + +# ADD ROUTE REFLECTOR NODE +- name: Add BGP Route Reflector Node + cisco.aci.aci_bgp_rr_node: + <<: *aci_info + node_id: 101 + pod_id: 1 + description: ans_node + state: present + register: add_bgp_rr_node + +- name: Verify that BGP route reflector node has been created with correct attributes + assert: + that: + - add_bgp_rr_node is changed + - add_bgp_rr_node.current.0.bgpRRNodePEp.attributes.annotation == 'orchestrator:ansible' + - add_bgp_rr_node.current.0.bgpRRNodePEp.attributes.dn == "uni/fabric/bgpInstP-default/rr/node-101" + - add_bgp_rr_node.current.0.bgpRRNodePEp.attributes.id == "101" + - add_bgp_rr_node.current.0.bgpRRNodePEp.attributes.podId == "1" + - add_bgp_rr_node.current.0.bgpRRNodePEp.attributes.descr == "ans_node" + +# ADD ROUTE REFLECTOR NODE AGAIN TO TEST IDEMPOTENCE +- name: Add BGP route reflector node again + cisco.aci.aci_bgp_rr_node: + <<: *aci_info + node_id: 101 + pod_id: 1 + description: ans_node + state: present + register: add_bgp_rr_node_again + +- name: Verify that BGP route reflector node has been created with correct attributes + assert: + that: + - add_bgp_rr_node_again is not changed + - add_bgp_rr_node_again.current.0.bgpRRNodePEp.attributes.dn == "uni/fabric/bgpInstP-default/rr/node-101" + - add_bgp_rr_node_again.current.0.bgpRRNodePEp.attributes.id == "101" + - add_bgp_rr_node_again.current.0.bgpRRNodePEp.attributes.podId == "1" + - add_bgp_rr_node_again.current.0.bgpRRNodePEp.attributes.descr == "ans_node" + +# MODIFY ROUTE REFLECTOR NODE +- name: Add BGP route reflector node again + cisco.aci.aci_bgp_rr_node: + <<: *aci_info + node_id: 101 + pod_id: 1 + description: ans_node_update + state: present + register: update_bgp_rr_node + +- name: Verify that BGP route reflector node has been updated with correct attributes + assert: + that: + - update_bgp_rr_node is changed + - update_bgp_rr_node.current.0.bgpRRNodePEp.attributes.dn == "uni/fabric/bgpInstP-default/rr/node-101" + - update_bgp_rr_node.current.0.bgpRRNodePEp.attributes.id == "101" + - update_bgp_rr_node.current.0.bgpRRNodePEp.attributes.podId == "1" + - update_bgp_rr_node.current.0.bgpRRNodePEp.attributes.descr == "ans_node_update" + +# QUERY ROUTE REFLECTOR NODE +- name: Add BGP route reflector node again + cisco.aci.aci_bgp_rr_node: + <<: *aci_info + node_id: 101 + state: query + register: query_bgp_rr_node + +- name: Verify that BGP route reflector node attributes + assert: + that: + - query_bgp_rr_node is not changed + - query_bgp_rr_node.current.0.bgpRRNodePEp.attributes.dn == "uni/fabric/bgpInstP-default/rr/node-101" + - query_bgp_rr_node.current.0.bgpRRNodePEp.attributes.id == "101" + - query_bgp_rr_node.current.0.bgpRRNodePEp.attributes.podId == "1" + - query_bgp_rr_node.current.0.bgpRRNodePEp.attributes.descr == "ans_node_update" + +- name: Query all route relector nodes + cisco.aci.aci_bgp_rr_node: + <<: *aci_info + state: query + register: query_bgp_rr_node_all + +- name: Verify query_bgp_rr_node_all + assert: + that: + - query_bgp_rr_node_all is not changed + +# DELETE ROUTE REFLECTOR NODE +- name: Remove BGP route reflector node + cisco.aci.aci_bgp_rr_node: + <<: *aci_info + node_id: 101 + state: absent + register: remove_bgp_rr_node + +- name: Verify BGP route reflector node removal + assert: + that: + - remove_bgp_rr_node is changed + - remove_bgp_rr_node.current == [] + - remove_bgp_rr_node.previous.0.bgpRRNodePEp.attributes.dn == "uni/fabric/bgpInstP-default/rr/node-101" + - remove_bgp_rr_node.previous.0.bgpRRNodePEp.attributes.id == "101" + - remove_bgp_rr_node.previous.0.bgpRRNodePEp.attributes.podId == "1" + - remove_bgp_rr_node.previous.0.bgpRRNodePEp.attributes.descr == "ans_node_update" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_bulk_static_binding_to_epg/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_bulk_static_binding_to_epg/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bulk_static_binding_to_epg/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_bulk_static_binding_to_epg/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_bulk_static_binding_to_epg/tasks/main.yml new file mode 100644 index 000000000..909cf933c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_bulk_static_binding_to_epg/tasks/main.yml @@ -0,0 +1,772 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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 + +- 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 + - name: Ensure ansible_test tenant does not exists + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + tenant: ansible_test + state: absent + + - name: Ensure ansible_test tenant exists + cisco.aci.aci_tenant: &tenant_present + <<: *tenant_absent + state: present + + - name: Ensure anstest ap exists + cisco.aci.aci_ap: &ap_present + <<: *tenant_present + ap: anstest + + - name: Ensure anstest epg exists + cisco.aci.aci_epg: &epg_present + <<: *ap_present + epg: anstest + + - name: Add list of interfaces with check mode + cisco.aci.aci_bulk_static_binding_to_epg: &cm_interfaces_present + <<: *epg_present + interface_type: switch_port + interface_mode: trunk + deploy_immediacy: lazy + encap_id: 107 + interface_configs: + - interface: 1/7 + leafs: 101 + pod: 1 + - interface: 1/7 + leafs: 107 + pod: 7 + - interface: 1/8 + leafs: 108 + pod: 8 + encap_id: 108 + primary_encap_id: 1008 + state: present + check_mode: true + register: cm_interfaces_present + + - name: Assertions check for add list of interfaces with check mode + assert: + that: + - cm_interfaces_present is changed + - cm_interfaces_present.current.0.fvAEPg.attributes.name == "anstest" + - "'children' not in cm_interfaces_present.previous.0.fvAEPg" + - "'children' not in cm_interfaces_present.current.0.fvAEPg" + + - name: Add list of interfaces with normal mode + cisco.aci.aci_bulk_static_binding_to_epg: &nm_interfaces_present + <<: *cm_interfaces_present + register: nm_interfaces_present + + - name: Assertions check for add list of interfaces with normal mode + assert: + that: + - nm_interfaces_present is changed + - nm_interfaces_present.current.0.fvAEPg.attributes.name == "anstest" + - nm_interfaces_present.current.0.fvAEPg.children | length == 3 + - "'children' not in nm_interfaces_present.previous.0.fvAEPg" + - nm_interfaces_present.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.descr == "" + + - name: Add list of interfaces with normal mode - idempotency works + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *nm_interfaces_present + register: idempotency_interfaces_present + + - name: Idempotency assertions check for add list of interfaces with normal mode + assert: + that: + - idempotency_interfaces_present is not changed + - idempotency_interfaces_present.current.0.fvAEPg.attributes.name == "anstest" + - idempotency_interfaces_present.current.0.fvAEPg.children | length == 3 + - idempotency_interfaces_present.previous.0.fvAEPg.children | length == 3 + + - name: Update list of interfaces - description with check mode + cisco.aci.aci_bulk_static_binding_to_epg: &cm_update_interfaces_present + <<: *nm_interfaces_present + description: "Description set from module level attributes" + check_mode: true + register: cm_update_interfaces_present + + - name: Assertions check for update list of interfaces - description with normal mode + assert: + that: + - cm_update_interfaces_present is changed + - cm_update_interfaces_present.current.0.fvAEPg.attributes.name == "anstest" + - cm_update_interfaces_present.current.0.fvAEPg.children | length == 3 + - cm_update_interfaces_present.previous.0.fvAEPg.children | length == 3 + - cm_update_interfaces_present.previous.0.fvAEPg.children.1.fvRsPathAtt.attributes.descr == "" + - cm_update_interfaces_present.current.0.fvAEPg.children.1.fvRsPathAtt.attributes.descr == "" + + - name: Update list of interfaces - description with normal mode + cisco.aci.aci_bulk_static_binding_to_epg: &nm_update_interfaces_present + <<: *cm_update_interfaces_present + register: nm_update_interfaces_present + + - name: Assertions check for update list of interfaces - description with normal mode + assert: + that: + - nm_update_interfaces_present is changed + - nm_update_interfaces_present.current.0.fvAEPg.attributes.name == "anstest" + - nm_update_interfaces_present.current.0.fvAEPg.children | length == 3 + - nm_update_interfaces_present.previous.0.fvAEPg.children | length == 3 + - nm_update_interfaces_present.previous.0.fvAEPg.children.1.fvRsPathAtt.attributes.descr == "" + - nm_update_interfaces_present.current.0.fvAEPg.children.1.fvRsPathAtt.attributes.descr == "Description set from module level attributes" + + - name: Update list of interfaces - description with normal mode - idempotency works + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *nm_update_interfaces_present + register: idempotency_nm_update_interfaces_present + + - name: Idempotency assertions check for update list of interfaces - description with normal mode + assert: + that: + - idempotency_nm_update_interfaces_present is not changed + - idempotency_nm_update_interfaces_present.current.0.fvAEPg.attributes.name == "anstest" + - idempotency_nm_update_interfaces_present.current.0.fvAEPg.children | length == 3 + - idempotency_nm_update_interfaces_present.previous.0.fvAEPg.children | length == 3 + - idempotency_nm_update_interfaces_present.current.0.fvAEPg.children.2.fvRsPathAtt.attributes.descr == "Description set from module level attributes" + - idempotency_nm_update_interfaces_present.previous.0.fvAEPg.children.2.fvRsPathAtt.attributes.descr == "Description set from module level attributes" + + - name: Update list of interfaces description using path level attributes with check mode + cisco.aci.aci_bulk_static_binding_to_epg: &cm_path_update_interfaces_present + <<: *epg_present + interface_type: switch_port + interface_mode: trunk + deploy_immediacy: lazy + interface_configs: + - interface: 1/7 + leafs: 101 + pod: 1 + description: "Description set from path level attributes" + - interface: 1/7 + leafs: 107 + pod: 7 + description: "Description set from path level attributes" + - interface: 1/8 + leafs: 108 + pod: 8 + encap_id: 108 + primary_encap_id: 1008 + description: "Description set from path level attributes" + state: present + check_mode: true + register: cm_path_update_interfaces_present + + - name: Assertions check for update list of interfaces description using path level attributes with check mode + assert: + that: + - cm_path_update_interfaces_present is changed + - cm_path_update_interfaces_present.current.0.fvAEPg.attributes.name == "anstest" + - cm_path_update_interfaces_present.current.0.fvAEPg.children | length == 3 + - cm_path_update_interfaces_present.previous.0.fvAEPg.children | length == 3 + - cm_path_update_interfaces_present.current.0.fvAEPg.children.1.fvRsPathAtt.attributes.descr == "Description set from module level attributes" + - cm_path_update_interfaces_present.previous.0.fvAEPg.children.2.fvRsPathAtt.attributes.descr == "Description set from module level attributes" + - cm_path_update_interfaces_present.sent.fvAEPg.children.2.fvRsPathAtt.attributes.descr == "Description set from path level attributes" + + - name: Update list of interfaces description using path level attributes with normal mode + cisco.aci.aci_bulk_static_binding_to_epg: &nm_path_update_interfaces_present + <<: *cm_path_update_interfaces_present + register: nm_path_update_interfaces_present + + - name: Assertions check for update list of interfaces description using path level attributes with normal mode + assert: + that: + - nm_path_update_interfaces_present is changed + - nm_path_update_interfaces_present.current.0.fvAEPg.attributes.name == "anstest" + - nm_path_update_interfaces_present.current.0.fvAEPg.children | length == 3 + - nm_path_update_interfaces_present.previous.0.fvAEPg.children | length == 3 + - nm_path_update_interfaces_present.current.0.fvAEPg.children.1.fvRsPathAtt.attributes.descr == "Description set from path level attributes" + - nm_path_update_interfaces_present.previous.0.fvAEPg.children.2.fvRsPathAtt.attributes.descr == "Description set from module level attributes" + + - name: Update list of interfaces description using path level attributes with normal mode - idempotency works + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *nm_path_update_interfaces_present + register: idempotency_path_update_interfaces_present + + - name: Idempotency assertions check for update list of interfaces description using path level attributes with normal mode + assert: + that: + - idempotency_path_update_interfaces_present is not changed + - idempotency_path_update_interfaces_present.current.0.fvAEPg.attributes.name == "anstest" + - idempotency_path_update_interfaces_present.current.0.fvAEPg.children | length == 3 + - idempotency_path_update_interfaces_present.previous.0.fvAEPg.children | length == 3 + - idempotency_path_update_interfaces_present.current.0.fvAEPg.children.2.fvRsPathAtt.attributes.descr == "Description set from path level attributes" + + - name: Query all interfaces of an EPG + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *aci_info + tenant: ansible_test + ap: anstest + epg: anstest + state: query + register: query_result_of_anstest_epg + + - name: Assertions check for query all interfaces of an EPG + assert: + that: + - query_result_of_anstest_epg is not changed + - query_result_of_anstest_epg.current.0.fvAEPg.children | length == 3 + - query_result_of_anstest_epg.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.descr == "Description set from path level attributes" + - query_result_of_anstest_epg.current.0.fvAEPg.children.1.fvRsPathAtt.attributes.descr == "Description set from path level attributes" + - query_result_of_anstest_epg.current.0.fvAEPg.children.2.fvRsPathAtt.attributes.descr == "Description set from path level attributes" + + - name: Query all interfaces + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *aci_info + state: query + register: query_all_interfaces + + - name: Assertions check for query all interfaces # Check covers only EPG level + assert: + that: + - query_all_interfaces is not changed + - query_all_interfaces.current | length >= 1 + + - name: Remove list of interfaces with check mode + cisco.aci.aci_bulk_static_binding_to_epg: &cm_interfaces_absent + <<: *cm_interfaces_present + state: absent + check_mode: true + register: cm_interfaces_absent + + - name: Assertions check for remove list of interfaces with check mode + assert: + that: + - cm_interfaces_absent is changed + - cm_interfaces_absent.current.0.fvAEPg.children | length == 3 + - cm_interfaces_absent.current.0.fvAEPg.attributes.name == "anstest" + - cm_interfaces_absent.previous.0.fvAEPg.children | length == 3 + - cm_interfaces_absent.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.descr == "Description set from path level attributes" + - cm_interfaces_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.descr == "Description set from path level attributes" + + - name: Remove list of interfaces with normal mode + cisco.aci.aci_bulk_static_binding_to_epg: &nm_interfaces_absent + <<: *cm_interfaces_absent + register: nm_interfaces_absent + + - name: Assertions check for remove list of interfaces with normal mode + assert: + that: + - nm_interfaces_absent is changed + - "'children' not in nm_interfaces_absent.current.0.fvAEPg" + - nm_interfaces_absent.current.0.fvAEPg.attributes.name == "anstest" + - nm_interfaces_absent.previous.0.fvAEPg.children | length == 3 + - nm_interfaces_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.descr == "Description set from path level attributes" + - nm_interfaces_absent.previous.0.fvAEPg.children.1.fvRsPathAtt.attributes.descr == "Description set from path level attributes" + - nm_interfaces_absent.previous.0.fvAEPg.children.2.fvRsPathAtt.attributes.descr == "Description set from path level attributes" + + - name: Remove list of interfaces with normal mode - idempotency works + cisco.aci.aci_bulk_static_binding_to_epg: &idempotency_interfaces_absent + <<: *nm_interfaces_absent + register: idempotency_interfaces_absent + + - name: Idempotency assertions check for remove list of interfaces with normal mode + assert: + that: + - idempotency_interfaces_absent is changed + - "'children' not in idempotency_interfaces_absent.current.0.fvAEPg" + - "'children' not in idempotency_interfaces_absent.previous.0.fvAEPg" + - idempotency_interfaces_absent.current.0.fvAEPg.attributes.name == "anstest" + + - name: Add fex_port_channel interfaces to anstest epg + cisco.aci.aci_bulk_static_binding_to_epg: &fex_port_channel_present + <<: *epg_present + interface_mode: trunk + interface_type: fex_port_channel + deploy_immediacy: lazy + descr: "fex_port_channel - interface created" + encap_id: 222 + interface_configs: + - extpaths: + - 1012 + interface: 2/7 + leafs: 102 + pod: 2 + register: fex_port_channel_present + + - name: Assertions check for add fex_port_channel interfaces to anstest epg + assert: + that: + - fex_port_channel_present is changed + - fex_port_channel_present.current.0.fvAEPg.children | length == 1 + - '"children" not in fex_port_channel_present.previous.0.fvAEPg' + - fex_port_channel_present.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.encap == "vlan-222" + - fex_port_channel_present.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.tDn == "topology/pod-2/paths-102/extpaths-1012/pathep-[2/7]" + - fex_port_channel_present.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.descr == "fex_port_channel - interface created" + + - name: Remove fex_port_channel interfaces from anstest epg + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *fex_port_channel_present + state: absent + register: fex_port_channel_absent + + - name: Assertions check for remove fex_port_channel interfaces from anstest epg + assert: + that: + - fex_port_channel_absent is changed + - fex_port_channel_absent.previous.0.fvAEPg.children | length == 1 + - "'children' not in fex_port_channel_absent.current.0.fvAEPg" + - fex_port_channel_absent.previous.0.fvAEPg.attributes.name == "anstest" + - fex_port_channel_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.encap == "vlan-222" + - fex_port_channel_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.tDn == "topology/pod-2/paths-102/extpaths-1012/pathep-[2/7]" + + - name: Add fex_vpc interfaces to anstest epg + cisco.aci.aci_bulk_static_binding_to_epg: &fex_vpc_present + <<: *epg_present + interface_mode: trunk + interface_type: fex_vpc + deploy_immediacy: lazy + descr: fex_vpc - interface created + encap_id: 223 + interface_configs: + - extpaths: + - 103 + - 104 + interface: 3/7 + leafs: + - 103 + - 104 + pod: 3 + register: fex_vpc_present + + - name: Assertions check for add fex_vpc interfaces to anstest epg + assert: + that: + - fex_vpc_present is changed + - fex_vpc_present.current.0.fvAEPg.children | length == 1 + - "'children' not in fex_vpc_present.previous.0.fvAEPg" + - fex_vpc_present.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.descr == "fex_vpc - interface created" + - fex_vpc_present.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.encap == "vlan-223" + - fex_vpc_present.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.tDn == "topology/pod-3/protpaths-103-104/extprotpaths-103-104/pathep-[3/7]" + + - name: Remove fex_vpc interfaces from anstest epg + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *fex_vpc_present + state: absent + register: fex_vpc_absent + + - name: Assertions check for remove fex_vpc interfaces from anstest epg + assert: + that: + - fex_vpc_absent is changed + - fex_vpc_absent.previous.0.fvAEPg.children | length == 1 + - "'children' not in fex_vpc_absent.current.0.fvAEPg" + - fex_vpc_absent.previous.0.fvAEPg.attributes.name == "anstest" + - fex_vpc_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.encap == "vlan-223" + - fex_vpc_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.tDn == "topology/pod-3/protpaths-103-104/extprotpaths-103-104/pathep-[3/7]" + + - name: Add vpc interfaces to anstest epg + cisco.aci.aci_bulk_static_binding_to_epg: &vpc_present + <<: *epg_present + deploy_immediacy: lazy + descr: vpc - interface created + interface_mode: trunk + interface_type: vpc + encap_id: 224 + interface_configs: + - interface: 4/7 + leafs: + - 105 + - 106 + pod: 4 + extpaths: + - 1015 + register: vpc_present + + - name: Assertions check for add vpc interfaces to anstest epg + assert: + that: + - vpc_present is changed + - vpc_present.current.0.fvAEPg.children | length == 1 + - "'children' not in vpc_present.previous.0.fvAEPg" + - vpc_present.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.descr == "vpc - interface created" + - vpc_present.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.encap == "vlan-224" + - vpc_present.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.tDn == "topology/pod-4/protpaths-105-106/pathep-[4/7]" + + - name: Remove vpc interfaces from anstest epg + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *vpc_present + state: absent + register: vpc_absent + + - name: Assertions check for remove vpc interfaces from anstest epg + assert: + that: + - vpc_absent is changed + - vpc_absent.previous.0.fvAEPg.children | length == 1 + - "'children' not in vpc_absent.current.0.fvAEPg" + - vpc_absent.previous.0.fvAEPg.attributes.name == "anstest" + - vpc_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.encap == "vlan-224" + - vpc_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.tDn == "topology/pod-4/protpaths-105-106/pathep-[4/7]" + + - name: Query all interfaces before start module and path level check + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *aci_info + tenant: ansible_test + ap: anstest + epg: anstest + state: query + register: query_result + + - name: Assertions check for query all interfaces before start module and path level check + assert: + that: + - query_result is not changed + - "'children' not in query_result.current.0.fvAEPg" + - query_result.current.0.fvAEPg.attributes.name == "anstest" + + - name: Add an interface with module level attributes + cisco.aci.aci_bulk_static_binding_to_epg: &module_level_check_present + <<: *epg_present + interface_type: switch_port + interface_mode: trunk + deploy_immediacy: lazy + encap_id: 108 + primary_encap_id: unknown + description: "Module level test" + interface_configs: + - interface: 1/8 + leafs: 108 + pod: 8 + state: present + register: module_level_check + + - name: Assertions check for add an interface with module level attributes + assert: + that: + - module_level_check is changed + - module_level_check.current.0.fvAEPg.children | length == 1 + - module_level_check.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.encap == "vlan-108" + - module_level_check.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.primaryEncap == "unknown" + - module_level_check.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.tDn == "topology/pod-8/paths-108/pathep-[eth1/8]" + - module_level_check.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.descr == "Module level test" + - module_level_check.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.instrImedcy == "lazy" + - module_level_check.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.mode == "regular" + + - name: Remove an interface with module level attributes + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *module_level_check_present + state: absent + register: module_level_check_absent + + - name: Assertions check for remove an interface with module level attributes + assert: + that: + - module_level_check_absent is changed + - "'children' not in module_level_check_absent.current.0.fvAEPg" + - module_level_check_absent.current.0.fvAEPg.attributes.name == "anstest" + - module_level_check_absent.previous.0.fvAEPg.children | length == 1 + - module_level_check_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.encap == "vlan-108" + - module_level_check_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.primaryEncap == "unknown" + - module_level_check_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.descr == "Module level test" + - module_level_check_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.tDn == "topology/pod-8/paths-108/pathep-[eth1/8]" + + - name: Add an interface with path level attributes + cisco.aci.aci_bulk_static_binding_to_epg: &path_level_check_present + <<: *epg_present + interface_configs: + - interface_type: switch_port + interface_mode: trunk + deploy_immediacy: lazy + encap_id: 109 + description: "Path level test" + interface: 1/9 + leafs: 109 + pod: 9 + state: present + register: path_level_check + + - name: Assertions check for add an interface with path level attributes + assert: + that: + - path_level_check is changed + - path_level_check.current.0.fvAEPg.children | length == 1 + - path_level_check.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.encap == "vlan-109" + - path_level_check.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.tDn == "topology/pod-9/paths-109/pathep-[eth1/9]" + + - name: Remove an interface with path level attributes + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *path_level_check_present + state: absent + register: path_level_check_absent + + - name: Assertions check for remove an interface with path level attributes + assert: + that: + - path_level_check_absent is changed + - "'children' not in path_level_check_absent.current.0.fvAEPg" + - path_level_check_absent.current.0.fvAEPg.attributes.name == "anstest" + - path_level_check_absent.previous.0.fvAEPg.children | length == 1 + - path_level_check_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.encap == "vlan-109" + - path_level_check_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.descr == "Path level test" + - path_level_check_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.tDn == "topology/pod-9/paths-109/pathep-[eth1/9]" + + - name: Add an interface encap_id with path and module level attributes + cisco.aci.aci_bulk_static_binding_to_epg: &path_and_module_encap_id_present + <<: *epg_present + encap_id: 108 + interface_type: switch_port + interface_mode: trunk + deploy_immediacy: lazy + description: "Path and Module level test" + interface_configs: + - interface: 1/7 + leafs: 107 + pod: 7 + encap_id: 107 + state: present + register: path_and_module_encap_id_present + + - name: Assertions check for add an interface encap_id with path and module level attributes + assert: + that: + - path_and_module_encap_id_present is changed + - path_and_module_encap_id_present.current.0.fvAEPg.children | length == 1 + - path_and_module_encap_id_present.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.encap == "vlan-107" + - path_and_module_encap_id_present.current.0.fvAEPg.children.0.fvRsPathAtt.attributes.tDn == "topology/pod-7/paths-107/pathep-[eth1/7]" + + - name: Remove an interface encap_id with path and module level attributes + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *path_and_module_encap_id_present + state: absent + register: path_and_module_encap_id_absent + + - name: Assertions check for remove an interface encap_id with path and module level attributes + assert: + that: + - path_and_module_encap_id_absent is changed + - "'children' not in path_and_module_encap_id_absent.current.0.fvAEPg" + - path_and_module_encap_id_absent.current.0.fvAEPg.attributes.name == "anstest" + - path_and_module_encap_id_absent.previous.0.fvAEPg.children | length == 1 + - path_and_module_encap_id_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.encap == "vlan-107" + - path_and_module_encap_id_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.descr == "Path and Module level test" + - path_and_module_encap_id_absent.previous.0.fvAEPg.children.0.fvRsPathAtt.attributes.tDn == "topology/pod-7/paths-107/pathep-[eth1/7]" + + - name: Bind static-binding to epg - interface type switch_port - no leafs (normal mode) + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *epg_present + interface_configs: + - interface_type: switch_port + interface_mode: trunk + deploy_immediacy: lazy + encap_id: 107 + interface: 'ansible_test' + pod: 1 + state: present + ignore_errors: true + register: switch_port_no_leafs + + - name: Bind static-binding to epg - interface type fex_vpc - no extpaths (normal mode) + cisco.aci.aci_bulk_static_binding_to_epg: &fex_vpc_no_extpaths + <<: *epg_present + interface_configs: + - interface_type: fex_vpc + interface_mode: trunk + deploy_immediacy: lazy + encap_id: 107 + interface: 'ansible_test' + leafs: 101 + pod: 1 + state: present + ignore_errors: true + register: fex_vpc_no_extpaths + + - name: Bind static-binding to epg - interface type fex_vpc - incorrect extpaths (normal mode) + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *fex_vpc_no_extpaths + interface_configs: + - interface_type: fex_vpc + interface_mode: trunk + deploy_immediacy: lazy + encap_id: 107 + interface: 'ansible_test' + leafs: 101 + pod: 1 + extpaths: + - 1012 + ignore_errors: true + register: fex_vpc_one_node + + - name: Bind static-binding to epg - fex_vpc with one extpaths (normal mode) + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *fex_vpc_no_extpaths + interface_configs: + - interface_type: fex_vpc + interface_mode: trunk + deploy_immediacy: lazy + encap_id: 107 + interface: 'ansible_test' + pod: 1 + leafs: + - 101 + - 102 + extpaths: + - 103 + ignore_errors: true + register: fex_vpc_one_extpaths + + - name: Bind static-binding to epg - switch_port with two leafs (normal mode) + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *fex_vpc_no_extpaths + interface_configs: + - interface_type: switch_port + interface_mode: trunk + deploy_immediacy: lazy + encap_id: 107 + interface: 'ansible_test' + pod: 1 + leafs: + - 101 + - 102 + ignore_errors: true + register: switch_port_two_leafs + + - name: Bind static-binding to epg - switch_port with two extpaths (normal mode) + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *fex_vpc_no_extpaths + interface_configs: + - interface_type: switch_port + interface_mode: trunk + deploy_immediacy: lazy + encap_id: 107 + interface: 'ansible_test' + pod: 1 + leafs: + - 101 + extpaths: + - 102 + - 103 + ignore_errors: true + register: switch_port_two_extpaths + + - name: Bind static-binding to epg - fex_vpc with 3 nodes (normal mode) + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *fex_vpc_no_extpaths + interface_configs: + - interface_type: fex_vpc + interface_mode: trunk + deploy_immediacy: lazy + encap_id: 107 + interface: 'ansible_test' + pod: 1 + leafs: + - 101 + - 102 + - 103 + extpaths: + - 101 + - 102 + ignore_errors: true + register: fex_vpc_three_leafs + + - name: Bind static-binding to epg - fex_vpc with 3 expaths (normal mode) + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *fex_vpc_no_extpaths + interface_configs: + - interface_type: fex_vpc + interface_mode: trunk + deploy_immediacy: lazy + encap_id: 107 + interface: 'ansible_test' + pod: 1 + leafs: + - 101 + - 102 + extpaths: + - 101 + - 102 + - 103 + ignore_errors: true + register: fex_vpc_three_expaths + + - name: Bind static-binding to epg - switch_port with encap_id 5000 (normal mode) + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *fex_vpc_no_extpaths + interface_configs: + - interface_type: switch_port + interface_mode: trunk + deploy_immediacy: lazy + encap_id: 5000 + interface: 'ansible_test' + pod: 1 + leafs: + - 101 + ignore_errors: true + register: switch_port_encap_id_too_high + + - name: Bind static-binding to epg - switch_port with primary_encap_id 5000 (normal mode) + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *fex_vpc_no_extpaths + interface_configs: + - interface_type: switch_port + interface_mode: trunk + deploy_immediacy: lazy + encap_id: 107 + primary_encap_id: 5000 + interface: 'ansible_test' + pod: 1 + leafs: + - 101 + ignore_errors: true + register: switch_port_primary_encap_id_too_high + + - name: Bind static-binding to epg - switch_port with primary_encap_id 5000 (normal mode) + cisco.aci.aci_bulk_static_binding_to_epg: + <<: *fex_vpc_no_extpaths + interface_configs: + - interface_type: switch_port + interface_mode: trunk + deploy_immediacy: lazy + encap_id: 107 + primary_encap_id: not_unknown + interface: 'ansible_test' + pod: 1 + leafs: + - 101 + ignore_errors: true + register: switch_port_primary_encap_id_not_unknown + + - name: Negative assertions to check error messages + assert: + that: + - switch_port_no_leafs.msg == "missing required arguments{{':'}} leafs found in interface_configs" + - fex_vpc_no_extpaths.msg == "extpaths is required when interface_type is{{':'}} fex_vpc" + - fex_vpc_one_node.msg == "A interface_type of \"vpc\" requires 2 leafs" + - fex_vpc_one_extpaths.msg == "A interface_type of \"fex_vpc\" requires 2 extpaths" + - switch_port_two_leafs.msg == "The interface_types \"switch_port\", \"port_channel\", and \"fex\" do not support using multiple leafs for a single binding" + - switch_port_two_extpaths.msg == "The interface_types \"fex\" and \"fex_port_channel\" do not support using multiple extpaths for a single binding" + - fex_vpc_three_leafs.msg == "The \"leafs\" parameter must not have more than 2 entries" + - fex_vpc_three_expaths.msg == "The \"extpaths\" parameter must not have more than 2 entries" + - switch_port_encap_id_too_high.msg == "Valid VLAN assignments are from 1 to 4096" + - switch_port_primary_encap_id_too_high.msg == "Valid VLAN assignments are from 1 to 4096 or unknown." + - switch_port_primary_encap_id_not_unknown.msg.startswith("Valid VLAN assignments are from 1 to 4096 or unknown. ") + + # Cleanup part + - name: Remove anstest tenant + cisco.aci.aci_tenant: + <<: *tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_ap/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_ap/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_ap/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_ap/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_ap/tasks/main.yml new file mode 100644 index 000000000..08a62f8cc --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_ap/tasks/main.yml @@ -0,0 +1,157 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, Cindy Zhao (@cizhao) + +# 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: 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 + tenant: ansible_test + register: tenant_present + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for cloud sites + when: query_cloud.current | length > 0 # This condition will execute only cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: ensure cloud ap does not exist initially + cisco.aci.aci_cloud_ap: + <<: *aci_tenant_present + name: '{{ item }}' + state: absent + loop: + - anstest + - anstest2 + + - name: create cloud ap - check mode + cisco.aci.aci_cloud_ap: &aci_cloud_ap_present + <<: *aci_tenant_present + name: anstest + description: Ansible Test Cloud APIC + state: present + check_mode: true + register: cm_create_cloud_ap + + - name: create cloud ap - normal mode + cisco.aci.aci_cloud_ap: + <<: *aci_cloud_ap_present + register: nm_create_cloud_ap + + - name: create cloud ap again - idempotency works + cisco.aci.aci_cloud_ap: + <<: *aci_cloud_ap_present + register: create_cloud_ap_again + + - name: create another ap - extra for query + cisco.aci.aci_cloud_ap: + <<: *aci_cloud_ap_present + name: anstest2 + register: extra_cloud_ap + + - name: update cloud ap + cisco.aci.aci_cloud_ap: + <<: *aci_cloud_ap_present + description: Update Ansible Test Update + register: update_cloud_ap + + - name: verify cloud ap creation + assert: + that: + - cm_create_cloud_ap is changed + - nm_create_cloud_ap is changed + - cm_create_cloud_ap.previous == nm_create_cloud_ap.previous == [] + - cm_create_cloud_ap.proposed.cloudApp.attributes.name == 'anstest' + - cm_create_cloud_ap.proposed.cloudApp.attributes.descr == 'Ansible Test Cloud APIC' + - nm_create_cloud_ap.current.0.cloudApp.attributes.annotation == 'orchestrator:ansible' + - nm_create_cloud_ap.current.0.cloudApp.attributes.name == 'anstest' + - nm_create_cloud_ap.current.0.cloudApp.attributes.descr == 'Ansible Test Cloud APIC' + - create_cloud_ap_again is not changed + - extra_cloud_ap is changed + - extra_cloud_ap.previous == [] + - extra_cloud_ap.current.0.cloudApp.attributes.name == 'anstest2' + - extra_cloud_ap.current.0.cloudApp.attributes.descr == 'Ansible Test Cloud APIC' + - update_cloud_ap is changed + - update_cloud_ap.previous.0.cloudApp.attributes.name == 'anstest' + - update_cloud_ap.previous.0.cloudApp.attributes.descr == 'Ansible Test Cloud APIC' + - update_cloud_ap.current.0.cloudApp.attributes.name == 'anstest' + - update_cloud_ap.current.0.cloudApp.attributes.descr == 'Update Ansible Test Update' + + - name: query all cloud ap for tenant - query tenant aps + cisco.aci.aci_cloud_ap: &aci_cloud_ap_query + <<: *aci_cloud_ap_present + name: "{{ fakevar | default(omit) }}" + state: query + register: query_all_tenant + + - name: query all cloud ap by name + cisco.aci.aci_cloud_ap: + <<: *aci_cloud_ap_query + tenant: "{{ fakevar | default(omit) }}" + name: anstest + register: query_all_ap + + - name: query all cloud ap - query general + cisco.aci.aci_cloud_ap: + <<: *aci_cloud_ap_query + tenant: "{{ fakevar | default(omit) }}" + name: "{{ fakevar | default(omit) }}" + register: query_all + + - name: query specific cloud ap + cisco.aci.aci_cloud_ap: + <<: *aci_cloud_ap_present + tenant: ansible_test + name: anstest + state: query + register: query_cloud_ap + + - name: verify query + assert: + that: + - query_all_tenant is not changed + - query_all_tenant.current.0.fvTenant.children | length >= 2 + - query_all_ap is not changed + - query_all_ap.current.0.cloudApp.attributes.name == 'anstest' + - query_all_ap.current.0.cloudApp.attributes.descr == 'Update Ansible Test Update' + - query_all is not changed + - query_all.current | length >= 2 + - query_cloud_ap is not changed + - query_cloud_ap.current.0.cloudApp.attributes.name == 'anstest' + - query_cloud_ap.current.0.cloudApp.attributes.descr == 'Update Ansible Test Update' + - query_cloud_ap.current.0.cloudApp.attributes.dn == 'uni/tn-ansible_test/cloudapp-anstest' + + - name: delete cloud ap + cisco.aci.aci_cloud_ap: + <<: *aci_tenant_present + name: anstest + state: absent + register: rm_cloud_ap + + - name: delete cloud ap again + cisco.aci.aci_cloud_ap: + <<: *aci_tenant_present + name: anstest + state: absent + register: rm_cloud_ap_again + + - name: verify deletion + assert: + that: + - rm_cloud_ap is changed + - rm_cloud_ap.previous.0.cloudApp.attributes.name == 'anstest' + - rm_cloud_ap.current == [] + - rm_cloud_ap_again is not changed + - rm_cloud_ap_again.previous == rm_cloud_ap_again.current == []
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_aws_provider/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_aws_provider/tasks/main.yml new file mode 100644 index 000000000..4679bf78d --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_aws_provider/tasks/main.yml @@ -0,0 +1,133 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, Shreyas Srish (@shrsr) + +# 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 aws cloud site + when: + - query_cloud.current | length > 0 + - query_cloud.current.0.cloudProvP.attributes.vendor == "aws" # This condition will execute only on cloud aws + block: # block specifies execution of tasks within, based on conditions + + - name: Ensure tenant doesn't exist + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_test + state: absent + + - name: Create tenant + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_test + state: present + + - name: Create aws provider + cisco.aci.aci_cloud_aws_provider: + <<: *aci_info + tenant: ansible_test + account_id: 111111111111 + is_trusted: true + state: present + register: aws_present + + - name: Create aws provider again + cisco.aci.aci_cloud_aws_provider: + <<: *aci_info + tenant: ansible_test + account_id: 111111111111 + is_trusted: true + state: present + register: aws_present_again + + - name: Change to untrusted aws provider + cisco.aci.aci_cloud_aws_provider: + <<: *aci_info + tenant: ansible_test + account_id: 111111111111 + is_trusted: false + state: present + register: aws_present_not_trusted + ignore_errors: true + + - name: Delete aws provider + cisco.aci.aci_cloud_aws_provider: + <<: *aci_info + tenant: ansible_test + state: absent + register: aws_absent + + - name: Create aws provider again after deletion as not trusted + cisco.aci.aci_cloud_aws_provider: + <<: *aci_info + tenant: ansible_test + account_id: 111111111111 + is_trusted: false + access_key_id: 1 + secret_access_key: 1 + state: present + register: aws_present_new + + - name: Create aws provider again after deletion as not trusted with account in org + cisco.aci.aci_cloud_aws_provider: + <<: *aci_info + tenant: ansible_test + account_id: 111111111111 + is_trusted: false + access_key_id: 1 + secret_access_key: 1 + is_account_in_org: true + state: present + register: aws_present_add_in_org + + - name: Query aws provider + cisco.aci.aci_cloud_aws_provider: + <<: *aci_info + tenant: ansible_test + state: query + register: aws_query + + - name: Query all aws provider + cisco.aci.aci_cloud_aws_provider: + <<: *aci_info + state: query + register: aws_query_all + + - name: Verify all + assert: + that: + - aws_present is changed + - aws_present_again is not changed + - aws_absent is changed + - aws_absent.current == [] + - aws_present_not_trusted.msg == "APIC Error 1{{ ":" }} Invalid Configuration {{ ":" }} Untrusted tenant ansible_test has missing access or secret key" + - aws_present_new is changed + - aws_present_new.current.0.cloudAwsProvider.attributes.annotation == 'orchestrator:ansible' + - aws_present_new.current.0.cloudAwsProvider.attributes.accessKeyId == "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" + - aws_present_new.current.0.cloudAwsProvider.attributes.accountId == "************************************************************************************************" + - aws_present_new.current.0.cloudAwsProvider.attributes.dn == "uni/tn-ansible_test/awsprovider" + - aws_present_new.current.0.cloudAwsProvider.attributes.isAccountInOrg == "no" + - aws_present_add_in_org is changed + - aws_present_add_in_org.current.0.cloudAwsProvider.attributes.isAccountInOrg == "yes" + - aws_query is not changed + - aws_query.current.0.fvTenant.children.0.cloudAwsProvider.attributes.accessKeyId == "1" + - aws_query.current.0.fvTenant.children.0.cloudAwsProvider.attributes.accountId == "111111111111" + - aws_query.current.0.fvTenant.children.0.cloudAwsProvider.attributes.isAccountInOrg == "yes" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_bgp_asn/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_bgp_asn/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_bgp_asn/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_bgp_asn/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_bgp_asn/tasks/main.yml new file mode 100644 index 000000000..8d442bf14 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_bgp_asn/tasks/main.yml @@ -0,0 +1,123 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, Anvitha Jain (@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 + +# These tasks need not be executed now, to execute the given tasks follow these steps: +# 1. Go to cloud APIC +# 2. Go to Region Management (top right corner blue arrow symbol) +# 3. Deselect the box whose cloud routers option is selected +# 4. Run the below task +# 5. Once the tasks are completed revert the changes made in above steps. + +# CLEAN ENVIRONMENT +- 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 cloud sites +# when: query_cloud.current | length > 0 # This condition will execute only cloud sites +# block: # block specifies execution of tasks within, based on conditions + +# - name: Ensure cloud BGP ASN doesn't exist +# aci_cloud_bgp_asn: +# <<: *aci_info +# state: absent + +# - name: Create cloud BGP ASN +# aci_cloud_bgp_asn: +# <<: *aci_info +# state: present +# register: asn_present + +# - name: Verify asn_present +# assert: +# that: +# - asn_present is changed +# - asn_present.current.0.cloudBgpAsP.attributes.asn == '0' + +# - name: Create cloud BGP ASN +# aci_cloud_bgp_asn: +# <<: *aci_info +# annotation: 'tag_system' +# asn: 64605 +# description: 'sample autonomous profile' +# name: 'BGP_ASN' +# name_alias: 'alias_sys_prof' +# state: present +# register: asn_present_2 + +# - name: Verify asn_present_2 +# assert: +# that: +# - asn_present_2 is changed +# - asn_present_2.current.0.cloudBgpAsP.attributes.asn == '64605' + +# - name: Create same cloud BGP ASN again +# aci_cloud_bgp_asn: +# <<: *aci_info +# annotation: 'tag_system' +# asn: 64605 +# description: 'sample autonomous profile' +# name: 'BGP_ASN' +# name_alias: 'alias_sys_prof' +# state: present +# register: asn_present_again + +# - name: Verify asn_present_again +# assert: +# that: +# - asn_present_again is not changed +# - asn_present_again.current.0.cloudBgpAsP.attributes.asn == '64605' + +# - name: Query particular cloud BGP ASN +# aci_cloud_bgp_asn: +# <<: *aci_info +# annotation: 'tag_system' +# asn: 64605 +# description: 'sample autonomous profile' +# name: 'BGP_ASN' +# name_alias: 'alias_sys_prof' +# state: query +# register: asn_query + +# # Query all will give same result as query +# # There can be only one cloud BGP ASN +# - name: Query all cloud BGP ASN +# aci_cloud_bgp_asn: +# <<: *aci_info +# state: query +# register: asn_query_all + +# - name: Verify query +# assert: +# that: +# - asn_query is not changed +# - asn_query_all is not changed + +# - name: Delete cloud BGP ASN +# aci_cloud_bgp_asn: +# <<: *aci_info +# state: absent +# register: asn_absent + +# - name: Verify absent +# assert: +# that: +# - asn_absent is changed +# - asn_absent.current == []
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_cidr/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_cidr/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_cidr/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_cidr/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_cidr/tasks/main.yml new file mode 100644 index 000000000..ab61eba83 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_cidr/tasks/main.yml @@ -0,0 +1,310 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Cindy Zhao (@cizhao) + +# 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 + +# CLEAN ENVIRONMENT +- 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 cloud sites + when: query_cloud.current | length > 0 # This condition will execute only cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Ensure tenant doesn't exist + aci_tenant: + <<: *aci_info + state: absent + tenant: ansible_test + register: tenant_absent + + - name: Ensure tenant exists for tests to kick off + aci_tenant: + <<: *aci_info + state: present + tenant: ansible_test + register: tenant_present + + - name: Ensure aci cloud context profile does not exists + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + name: ctx_profile_1 + state: absent + register: rm_ctx_profile_1 + + - name: Create aci cloud context profile + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + name: ctx_profile_1 + vrf: ctx_profile_vrf_1 + region: "{{ region_2 }}" + primary_cidr: '10.11.0.0/16' + cloud: "{{ cloud_type }}" + state: present + register: nm_add_aci_ctx_profile + + - name: Create non_primary CIDR (check_mode) + aci_cloud_cidr: + <<: *aci_info + tenant: ansible_test + address: 10.0.0.0/16 + cloud_context_profile: ctx_profile_1 + state: present + check_mode: true + register: cm_non_primary_cidr + + - name: Create non_primary CIDR (normal_mode) + aci_cloud_cidr: + <<: *aci_info + tenant: ansible_test + address: 10.0.0.0/16 + cloud_context_profile: ctx_profile_1 + state: present + register: nm_non_primary_cidr + + - name: Verify cm_non_primary_cidr and nm_non_primary_cidr + assert: + that: + - cm_non_primary_cidr is changed + - nm_non_primary_cidr is changed + - cm_non_primary_cidr.previous == [] + - nm_non_primary_cidr.previous == [] + - cm_non_primary_cidr.proposed.cloudCidr.attributes.addr == "10.0.0.0/16" + - cm_non_primary_cidr.proposed.cloudCidr.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1/cidr-[10.0.0.0/16]" + - cm_non_primary_cidr.proposed.cloudCidr.attributes.primary == "no" + - nm_non_primary_cidr.current.0.cloudCidr.attributes.annotation == 'orchestrator:ansible' + - nm_non_primary_cidr.current.0.cloudCidr.attributes.addr == "10.0.0.0/16" + - nm_non_primary_cidr.current.0.cloudCidr.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1/cidr-[10.0.0.0/16]" + - nm_non_primary_cidr.current.0.cloudCidr.attributes.primary == "no" + + - name: Create non_primary CIDR again + aci_cloud_cidr: + <<: *aci_info + tenant: ansible_test + address: 10.0.0.0/16 + cloud_context_profile: ctx_profile_1 + state: present + register: nm_non_primary_cidr_again + + - name: Verify nm_non_primary_cidr_again + assert: + that: + - nm_non_primary_cidr_again is not changed + - nm_non_primary_cidr_again.previous.0.cloudCidr.attributes.addr == "10.0.0.0/16" + - nm_non_primary_cidr_again.previous.0.cloudCidr.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1/cidr-[10.0.0.0/16]" + - nm_non_primary_cidr_again.previous.0.cloudCidr.attributes.primary == "no" + - nm_non_primary_cidr_again.current.0.cloudCidr.attributes.addr == "10.0.0.0/16" + - nm_non_primary_cidr_again.current.0.cloudCidr.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1/cidr-[10.0.0.0/16]" + - nm_non_primary_cidr_again.current.0.cloudCidr.attributes.primary == "no" + + - name: Change primary CIDR to non_primary (check_mode) + aci_cloud_cidr: + <<: *aci_info + tenant: ansible_test + address: 10.11.0.0/16 + cloud_context_profile: ctx_profile_1 + state: present + check_mode: true + register: cm_change_to_non_primary_cidr + + - name: Change primary CIDR to non_primary (normal_mode) + aci_cloud_cidr: + <<: *aci_info + tenant: ansible_test + address: 10.11.0.0/16 + cloud_context_profile: ctx_profile_1 + state: present + ignore_errors: true + register: nm_change_to_non_primary_cidr + + - name: Verify cm_primary_cidr and nm_change_to_non_primary_cidr + assert: + that: + - nm_change_to_non_primary_cidr.msg == "APIC Error 1{{':'}} Invalid Configuration {{':'}} Exactly one Primary CIDR expected for{{':'}} uni/tn-ansible_test/ctxprofile-ctx_profile_1, but found{{':'}} 0" + - cm_change_to_non_primary_cidr.proposed.cloudCidr.attributes.primary == "no" + - cm_change_to_non_primary_cidr.previous.0.cloudCidr.attributes.primary == cm_change_to_non_primary_cidr.current.0.cloudCidr.attributes.primary == "yes" + + - name: Remove primary CIDR (check_mode) + aci_cloud_cidr: + <<: *aci_info + tenant: ansible_test + address: 10.11.0.0/16 + cloud_context_profile: ctx_profile_1 + state: absent + check_mode: true + register: cm_remove_primary_cidr + + - name: Remove primary CIDR (normal_mode) + aci_cloud_cidr: + <<: *aci_info + tenant: ansible_test + address: 10.11.0.0/16 + cloud_context_profile: ctx_profile_1 + state: absent + ignore_errors: true + register: nm_remove_primary_cidr + + - name: Verify cm_remove_primary_cidr and nm_remove_primary_cidr + assert: + that: + - nm_remove_primary_cidr.msg == "APIC Error 1{{':'}} Invalid Configuration {{':'}} Exactly one Primary CIDR expected for{{':'}} uni/tn-ansible_test/ctxprofile-ctx_profile_1, but found{{':'}} 0" + - cm_remove_primary_cidr.proposed == {} + - cm_remove_primary_cidr.previous.0.cloudCidr.attributes.primary == cm_remove_primary_cidr.current.0.cloudCidr.attributes.primary == "yes" + + - name: Create second non_primary CIDR + aci_cloud_cidr: + <<: *aci_info + tenant: ansible_test + address: 10.18.0.0/16 + cloud_context_profile: ctx_profile_1 + state: present + register: nm_add_second_non_primary_cidr + + - name: Verify nm_add_second_non_primary_cidr + assert: + that: + - nm_add_second_non_primary_cidr is changed + - nm_add_second_non_primary_cidr.previous == [] + - nm_add_second_non_primary_cidr.current.0.cloudCidr.attributes.addr == "10.18.0.0/16" + - nm_add_second_non_primary_cidr.current.0.cloudCidr.attributes.primary == "no" + - nm_add_second_non_primary_cidr.current.0.cloudCidr.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1/cidr-[10.18.0.0/16]" + + - name: Change setting of second non_primary CIDR + aci_cloud_cidr: + <<: *aci_info + tenant: ansible_test + cidr: 10.18.0.0/16 + cloud_context_profile: ctx_profile_1 + description: This is not a primary CIDR + name_alias: cidr_block_range + state: present + register: change_non_primary_cidr + + - name: Verify change_non_primary_cidr + assert: + that: + - change_non_primary_cidr is changed + - change_non_primary_cidr.current.0.cloudCidr.attributes.addr == "10.18.0.0/16" + - change_non_primary_cidr.current.0.cloudCidr.attributes.descr == "This is not a primary CIDR" + - change_non_primary_cidr.current.0.cloudCidr.attributes.nameAlias == "cidr_block_range" + - change_non_primary_cidr.current.0.cloudCidr.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1/cidr-[10.18.0.0/16]" + + - name: Query all CIDRs + aci_cloud_cidr: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + state: query + register: query_all + + - name: Verify query_all + assert: + that: + - query_all is not changed + - query_all.current.0.cloudCtxProfile.attributes.name == "ctx_profile_1" + - query_all.current.0.cloudCtxProfile.children | length == 3 + - query_all.current.0.cloudCtxProfile.children.0.cloudCidr.attributes.addr == "10.18.0.0/16" + - query_all.current.0.cloudCtxProfile.children.0.cloudCidr.attributes.primary == "no" + - query_all.current.0.cloudCtxProfile.children.1.cloudCidr.attributes.addr == "10.0.0.0/16" + - query_all.current.0.cloudCtxProfile.children.1.cloudCidr.attributes.primary == "no" + - query_all.current.0.cloudCtxProfile.children.2.cloudCidr.attributes.addr == "10.11.0.0/16" + - query_all.current.0.cloudCtxProfile.children.2.cloudCidr.attributes.primary == "yes" + + - name: Query primary CIDR + aci_cloud_cidr: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + address: 10.11.0.0/16 + state: query + register: query_primary + + - name: Verify query_primary + assert: + that: + - query_primary is not changed + - query_primary.current.0.cloudCidr.attributes.addr == "10.11.0.0/16" + - query_primary.current.0.cloudCidr.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1/cidr-[10.11.0.0/16]" + - query_primary.current.0.cloudCidr.attributes.primary == "yes" + + - name: Query non_primary CIDR + aci_cloud_cidr: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + address: 10.0.0.0/16 + state: query + register: query_non_primary + + - name: Verify query_non_primary + assert: + that: + - query_non_primary is not changed + - query_non_primary.current.0.cloudCidr.attributes.addr == "10.0.0.0/16" + - query_non_primary.current.0.cloudCidr.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1/cidr-[10.0.0.0/16]" + - query_non_primary.current.0.cloudCidr.attributes.primary == "no" + + - name: Query non_exsisting CIDR + aci_cloud_cidr: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + address: non_exsisting + state: query + ignore_errors: true + register: query_non_existing + + - name: Verify query_non_existing + assert: + that: + - query_non_existing.msg == "APIC Error 104{{':'}} Invalid RN cidr-[non_exsisting]" + + - name: Remove non_primary CIDR(check_mode) + aci_cloud_cidr: + <<: *aci_info + tenant: ansible_test + address: 10.0.0.0/16 + cloud_context_profile: ctx_profile_1 + state: absent + check_mode: true + register: cm_remove_non_primary_cidr + + - name: Remove non_primary CIDR(normal_mode) + aci_cloud_cidr: + <<: *aci_info + tenant: ansible_test + address: 10.0.0.0/16 + cloud_context_profile: ctx_profile_1 + state: absent + register: nm_remove_non_primary_cidr + + - name: Verify cm_remove_non_primary_cidr and nm_remove_non_primary_cidr + assert: + that: + - cm_remove_non_primary_cidr is changed + - nm_remove_non_primary_cidr is changed + - cm_remove_non_primary_cidr.proposed == {} + - nm_remove_non_primary_cidr.current == [] + - cm_remove_non_primary_cidr.previous.0.cloudCidr.attributes.addr == "10.0.0.0/16" + - cm_remove_non_primary_cidr.previous.0.cloudCidr.attributes.primary == "no" + - cm_remove_non_primary_cidr.previous.0.cloudCidr.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1/cidr-[10.0.0.0/16]" + - nm_remove_non_primary_cidr.previous.0.cloudCidr.attributes.addr == "10.0.0.0/16" + - nm_remove_non_primary_cidr.previous.0.cloudCidr.attributes.primary == "no" + - nm_remove_non_primary_cidr.previous.0.cloudCidr.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1/cidr-[10.0.0.0/16]" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_ctx_profile/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_ctx_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_ctx_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_cloud_ctx_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_ctx_profile/tasks/main.yml new file mode 100644 index 000000000..981eadea8 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_ctx_profile/tasks/main.yml @@ -0,0 +1,255 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Cindy Zhao (@cizhao) <cizhao@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 + +# CLEAN ENVIRONMENT +- 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 cloud sites + when: query_cloud.current | length > 0 # This condition will execute only cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Ensure tenant doesn't exist + aci_tenant: + <<: *aci_info + state: absent + tenant: ansible_test + register: tenant_absent + + - name: Ensure tenant exists for tests to kick off + aci_tenant: + <<: *aci_info + state: present + tenant: ansible_test + register: tenant_present + + - name: Ensure aci cloud context profile does not exists + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + name: ctx_profile_1 + state: absent + register: rm_ctx_profile_1 + + - name: Verify rm_ctx_profile_1 + assert: + that: + - rm_ctx_profile_1.current == [] + + - name: Ensure aci cloud context profile 2 does not exists + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + name: ctx_profile_2 + state: absent + register: rm_ctx_profile_2 + + - name: Verify rm_ctx_profile_2 + assert: + that: + - rm_ctx_profile_2.current == [] + + - name: Create aci cloud context profile (check mode) + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + cloud: "{{ cloud_type }}" + name: ctx_profile_1 + vrf: ctx_profile_vrf_1 + region: "{{ region }}" + primary_cidr: '10.100.0.0/16' + state: present + check_mode: true + register: cm_add_aci_ctx_profile + + - name: Create aci cloud context profile (normal mode) + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + cloud: "{{ cloud_type }}" + name: ctx_profile_1 + vrf: ctx_profile_vrf_1 + region: "{{ region }}" + primary_cidr: '10.100.0.0/16' + state: present + register: nm_add_aci_ctx_profile + + - name: Verify cm_add_aci_ctx_profile + assert: + that: + - cm_add_aci_ctx_profile is changed + - cm_add_aci_ctx_profile.previous == [] + - cm_add_aci_ctx_profile.proposed.cloudCtxProfile.attributes.name == "ctx_profile_1" + - cm_add_aci_ctx_profile.proposed.cloudCtxProfile.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1" + - cm_add_aci_ctx_profile.proposed.cloudCtxProfile.children[0].cloudRsToCtx.attributes.tnFvCtxName == "ctx_profile_vrf_1" + - cm_add_aci_ctx_profile.proposed.cloudCtxProfile.children[2].cloudCidr.attributes.addr == "10.100.0.0/16" + - cm_add_aci_ctx_profile.proposed.cloudCtxProfile.children[2].cloudCidr.attributes.primary == "yes" + + - name: Verify nm_add_aci_ctx_profile + assert: + that: + - nm_add_aci_ctx_profile is changed + - nm_add_aci_ctx_profile.previous == [] + - nm_add_aci_ctx_profile.current[0].cloudCtxProfile.attributes.annotation == 'orchestrator:ansible' + - nm_add_aci_ctx_profile.current[0].cloudCtxProfile.attributes.name == "ctx_profile_1" + - nm_add_aci_ctx_profile.current[0].cloudCtxProfile.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1" + - nm_add_aci_ctx_profile.current[0].cloudCtxProfile.children[2].cloudRsToCtx.attributes.tnFvCtxName == "ctx_profile_vrf_1" + - nm_add_aci_ctx_profile.current[0].cloudCtxProfile.children[0].cloudCidr.attributes.addr == "10.100.0.0/16" + - nm_add_aci_ctx_profile.current[0].cloudCtxProfile.children[0].cloudCidr.attributes.primary == "yes" + + - name: Add aci cloud context profile again (check_mode) + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + cloud: "{{ cloud_type }}" + name: ctx_profile_1 + vrf: ctx_profile_vrf_1 + region: "{{ region }}" + primary_cidr: '10.100.0.0/16' + state: present + check_mode: true + register: cm_add_aci_ctx_profile_again + + - name: Verify cm_add_aci_ctx_profile_again + assert: + that: + - cm_add_aci_ctx_profile_again is not changed + - cm_add_aci_ctx_profile_again.previous[0].cloudCtxProfile.attributes.name == "ctx_profile_1" + - cm_add_aci_ctx_profile_again.previous[0].cloudCtxProfile.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1" + - cm_add_aci_ctx_profile_again.previous[0].cloudCtxProfile.children[2].cloudRsToCtx.attributes.tnFvCtxName == "ctx_profile_vrf_1" + - cm_add_aci_ctx_profile_again.previous[0].cloudCtxProfile.children[0].cloudCidr.attributes.addr == "10.100.0.0/16" + - cm_add_aci_ctx_profile_again.previous[0].cloudCtxProfile.children[0].cloudCidr.attributes.primary == "yes" + + + - name: Add aci cloud context profile again (normal_mode) + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + cloud: "{{ cloud_type }}" + name: ctx_profile_1 + vrf: ctx_profile_vrf_1 + region: "{{ region }}" + primary_cidr: '10.100.0.0/16' + state: present + register: nm_add_aci_ctx_profile_again + + - name: Verify nm_add_aci_ctx_profile_again + assert: + that: + - nm_add_aci_ctx_profile_again is not changed + - nm_add_aci_ctx_profile_again.current[0].cloudCtxProfile.attributes.name == "ctx_profile_1" + - nm_add_aci_ctx_profile_again.current[0].cloudCtxProfile.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1" + - nm_add_aci_ctx_profile_again.current[0].cloudCtxProfile.children[2].cloudRsToCtx.attributes.tnFvCtxName == "ctx_profile_vrf_1" + - nm_add_aci_ctx_profile_again.current[0].cloudCtxProfile.children[0].cloudCidr.attributes.addr == "10.100.0.0/16" + - nm_add_aci_ctx_profile_again.current[0].cloudCtxProfile.children[0].cloudCidr.attributes.primary == "yes" + + - name: Add another aci cloud context profile (check_mode) + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + cloud: "{{ cloud_type }}" + name: ctx_profile_2 + vrf: ctx_profile_vrf_2 + region: "{{ region_2 }}" + primary_cidr: '10.101.0.0/16' + description: "add ctx_profile_2" + state: present + check_mode: true + register: cm_add_another_aci_ctx_profile + + - name: Verify cm_add_another_aci_ctx_profile + assert: + that: + - cm_add_another_aci_ctx_profile is changed + - cm_add_another_aci_ctx_profile.previous == [] + - cm_add_another_aci_ctx_profile.proposed.cloudCtxProfile.attributes.name == "ctx_profile_2" + - cm_add_another_aci_ctx_profile.proposed.cloudCtxProfile.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_2" + - cm_add_another_aci_ctx_profile.proposed.cloudCtxProfile.children[0].cloudRsToCtx.attributes.tnFvCtxName == "ctx_profile_vrf_2" + - cm_add_another_aci_ctx_profile.proposed.cloudCtxProfile.children[2].cloudCidr.attributes.addr == "10.101.0.0/16" + - cm_add_another_aci_ctx_profile.proposed.cloudCtxProfile.children[2].cloudCidr.attributes.primary == "yes" + - cm_add_another_aci_ctx_profile.proposed.cloudCtxProfile.attributes.descr == "add ctx_profile_2" + + - name: Add another aci cloud context profile (normal_mode) + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + cloud: "{{ cloud_type }}" + name: ctx_profile_2 + vrf: ctx_profile_vrf_2 + region: "{{ region_2 }}" + primary_cidr: '10.101.0.0/16' + description: "add ctx_profile_2" + state: present + register: nm_add_another_aci_ctx_profile + + - name: Verify nm_add_another_aci_ctx_profile + assert: + that: + - nm_add_another_aci_ctx_profile is changed + - nm_add_another_aci_ctx_profile.previous == [] + - nm_add_another_aci_ctx_profile.current[0].cloudCtxProfile.attributes.name == "ctx_profile_2" + - nm_add_another_aci_ctx_profile.current[0].cloudCtxProfile.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_2" + - nm_add_another_aci_ctx_profile.current[0].cloudCtxProfile.children[2].cloudRsToCtx.attributes.tnFvCtxName == "ctx_profile_vrf_2" + - nm_add_another_aci_ctx_profile.current[0].cloudCtxProfile.children[0].cloudCidr.attributes.addr == "10.101.0.0/16" + - nm_add_another_aci_ctx_profile.current[0].cloudCtxProfile.children[0].cloudCidr.attributes.primary == "yes" + - nm_add_another_aci_ctx_profile.current[0].cloudCtxProfile.attributes.descr == "add ctx_profile_2" + + - name: Query aci cloud context profile ctx_profile_1 + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + name: ctx_profile_1 + state: query + register: query_aci_cloud_profile_1 + + - name: Verify query_aci_cloud_profile_1 + assert: + that: + - query_aci_cloud_profile_1 is not changed + - query_aci_cloud_profile_1.current[0].cloudCtxProfile.attributes.name == "ctx_profile_1" + - query_aci_cloud_profile_1.current[0].cloudCtxProfile.children | length == 3 + + - name: Query all aci cloud context profiles + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + state: query + register: query_all + + - name: Verify query_all + assert: + that: + - query_all is not changed + - query_all.current | length == 1 + - query_all.current.0.fvTenant.children | length == 2 + + - name: Remove aci cloud context profile + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + name: ctx_profile_1 + state: absent + register: rm_ctx_profile + + - name: Verify rm_ctx_profile + assert: + that: + - rm_ctx_profile.current == [] + - rm_ctx_profile.previous.0.cloudCtxProfile.attributes.name == "ctx_profile_1" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_epg/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_epg/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_epg/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_epg/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_epg/tasks/main.yml new file mode 100644 index 000000000..966b6afc2 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_epg/tasks/main.yml @@ -0,0 +1,185 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, Cindy Zhao (@cizhao) + +# 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 cloud sites + when: query_cloud.current | length > 0 # This condition will execute only cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Ensure tenant doesn't exist + cisco.aci.aci_tenant: + <<: *aci_info + state: absent + tenant: ansible_test + register: tenant_absent + + - name: Ensure tenant exists + cisco.aci.aci_tenant: &aci_tenant_present + <<: *aci_info + state: present + tenant: ansible_test + register: tenant_present + + - name: Ensure application profile exists + cisco.aci.aci_cloud_ap: &aci_cloud_ap_present + <<: *aci_tenant_present + name: anstest + description: Ansible Test Cloud APIC + state: present + register: create_cloud_ap + + - name: Ensure vrf exist + cisco.aci.aci_vrf: &aci_vrf_present + <<: *aci_tenant_present + vrf: anstest + description: Ansible Test + register: vrf_present + + - name: Create another vrf + cisco.aci.aci_vrf: + <<: *aci_vrf_present + vrf: anstest_2 + register: another_vrf_present + + - name: Create aci cloud epg (check_mode) + cisco.aci.aci_cloud_epg: &aci_cloud_epg_present + <<: *aci_info + tenant: ansible_test + ap: anstest + vrf: anstest + description: Aci Cloud EPG + name: anstest + state: present + check_mode: true + register: cm_epg_present + + - name: Create aci cloud epg (normal mode) + cisco.aci.aci_cloud_epg: + <<: *aci_cloud_epg_present + register: nm_epg_present + + - name: Create aci cloud epg again + cisco.aci.aci_cloud_epg: + <<: *aci_cloud_epg_present + register: nm_epg_present_again + + - name: Create another cloud epg + cisco.aci.aci_cloud_epg: + <<: *aci_cloud_epg_present + name: ansible_cloud_epg + register: nm_another_epg_present + + - name: Verify cloud epg creation + assert: + that: + - cm_epg_present is changed + - nm_epg_present is changed + - nm_epg_present_again is not changed + - cm_epg_present.previous == nm_epg_present.previous == [] + - cm_epg_present.proposed.cloudEPg.attributes.name == 'anstest' + - cm_epg_present.proposed.cloudEPg.attributes.descr == 'Aci Cloud EPG' + - cm_epg_present.proposed.cloudEPg.attributes.dn == 'uni/tn-ansible_test/cloudapp-anstest/cloudepg-anstest' + - cm_epg_present.proposed.cloudEPg.children.0.cloudRsCloudEPgCtx.attributes.tnFvCtxName == 'anstest' + - nm_epg_present.current.0.cloudEPg.attributes.annotation == 'orchestrator:ansible' + - nm_epg_present.current.0.cloudEPg.attributes.name == 'anstest' + - nm_epg_present.current.0.cloudEPg.attributes.descr == 'Aci Cloud EPG' + - nm_epg_present.current.0.cloudEPg.attributes.dn == 'uni/tn-ansible_test/cloudapp-anstest/cloudepg-anstest' + - nm_epg_present.current.0.cloudEPg.children.0.cloudRsCloudEPgCtx.attributes.tnFvCtxName == 'anstest' + - nm_epg_present_again.previous == nm_epg_present_again.current + - nm_another_epg_present is changed + - nm_another_epg_present.previous == [] + - nm_another_epg_present.current.0.cloudEPg.attributes.name == 'ansible_cloud_epg' + + - name: Update cloud epg with another vrf + cisco.aci.aci_cloud_epg: + <<: *aci_cloud_epg_present + vrf: anstest_2 + register: update_cloud_epg + + - name: Update cloud epg without vrf + cisco.aci.aci_cloud_epg: + <<: *aci_cloud_epg_present + vrf: "{{ fakevar | default(omit) }}" + register: no_vrf + + # - name: Create cloud epg without vrf + # cisco.aci.aci_cloud_epg: + # <<: *aci_cloud_epg_present + # name: epg_without_vrf + # vrf: "{{ fakevar | default(omit) }}" + # register: create_no_vrf + + - name: Veirfy update_cloud_epg + assert: + that: + - update_cloud_epg is changed + - update_cloud_epg.current.0.cloudEPg.children.0.cloudRsCloudEPgCtx.attributes.tnFvCtxName == 'anstest_2' + + - name: Query specific cloud epg + cisco.aci.aci_cloud_epg: + <<: *aci_info + tenant: ansible_test + ap: anstest + name: anstest + state: query + register: cloud_epg_query + + - name: query all + cisco.aci.aci_cloud_epg: + <<: *aci_info + tenant: ansible_test + ap: anstest + state: query + register: query_all + + - name: Verify query + assert: + that: + - cloud_epg_query is not changed + - cloud_epg_query.current.0.cloudEPg.attributes.name == 'anstest' + - cloud_epg_query.current.0.cloudEPg.attributes.dn == 'uni/tn-ansible_test/cloudapp-anstest/cloudepg-anstest' + - cloud_epg_query.current.0.cloudEPg.attributes.descr == 'Aci Cloud EPG' + - cloud_epg_query.current.0.cloudEPg.children.0.cloudRsCloudEPgCtx.attributes.tnFvCtxName == 'anstest_2' + - cloud_epg_query.current.0.cloudEPg.children.0.cloudRsCloudEPgCtx.attributes.tDn == 'uni/tn-ansible_test/ctx-anstest_2' + - query_all is not changed + - query_all.current.0.cloudApp.children | length >= 2 + + - name: Remove cloud epg + cisco.aci.aci_cloud_epg: &cloud_epg_absent + <<: *aci_info + tenant: ansible_test + ap: anstest + name: anstest + state: absent + register: cloud_epg_absent + + - name: Remove cloud epg again + cisco.aci.aci_cloud_epg: + <<: *cloud_epg_absent + register: cloud_epg_absent_again + + - name: Verify deletion + assert: + that: + - cloud_epg_absent is changed + - cloud_epg_absent.current == [] + - cloud_epg_absent_again is not changed diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_epg_selector/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_epg_selector/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_epg_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_cloud_epg_selector/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_epg_selector/tasks/main.yml new file mode 100644 index 000000000..c1261eae7 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_epg_selector/tasks/main.yml @@ -0,0 +1,232 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, Cindy Zhao (@cizhao) + +# 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 cloud sites + when: query_cloud.current | length > 0 # This condition will execute only cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Ensure tenant doesn't exist + cisco.aci.aci_tenant: + <<: *aci_info + state: absent + tenant: ansible_test + register: tenant_absent + + - name: Ensure tenant exists + cisco.aci.aci_tenant: &aci_tenant_present + <<: *aci_info + state: present + tenant: ansible_test + register: tenant_present + + - name: Ensure application profile exists + cisco.aci.aci_cloud_ap: &aci_cloud_ap_present + <<: *aci_tenant_present + name: anstest + description: Ansible Test Cloud APIC + state: present + register: create_cloud_ap + + - name: Ensure vrf exist + cisco.aci.aci_vrf: &aci_vrf_present + <<: *aci_tenant_present + vrf: anstest + description: Ansible Test + register: vrf_present + + - name: Create aci cloud epg + cisco.aci.aci_cloud_epg: &aci_cloud_epg_present + <<: *aci_info + tenant: ansible_test + ap: anstest + vrf: anstest + description: Aci Cloud EPG + name: anstest + state: present + register: nm_epg_present + + - name: Create aci cloud epg selector (check_mode) + cisco.aci.aci_cloud_epg_selector: &aci_cloud_epg_selector + <<: *aci_info + tenant: ansible_test + ap: anstest + epg: anstest + description: cloud epg selector + name: ansible_selector + expressions: + - key: ip + operator: in + value: 10.10.10.1 + state: present + check_mode: true + register: cm_selector_present + + - name: Create aci cloud epg selector (normal mode) + cisco.aci.aci_cloud_epg_selector: + <<: *aci_cloud_epg_selector + register: nm_selector_present + + - name: Create aci cloud epg again + cisco.aci.aci_cloud_epg_selector: + <<: *aci_cloud_epg_selector + register: selector_present_again + + - name: Verify creation of cloud epg selector + assert: + that: + - cm_selector_present is changed + - nm_selector_present is changed + - selector_present_again is not changed + - cm_selector_present.previous == nm_selector_present.previous == [] + - cm_selector_present.proposed.cloudEPSelector.attributes.descr == 'cloud epg selector' + - cm_selector_present.proposed.cloudEPSelector.attributes.matchExpression == "IP in('10.10.10.1')" + - cm_selector_present.proposed.cloudEPSelector.attributes.dn == 'uni/tn-ansible_test/cloudapp-anstest/cloudepg-anstest/epselector-ansible_selector' + - cm_selector_present.proposed.cloudEPSelector.attributes.name == 'ansible_selector' + - nm_selector_present.current.0.cloudEPSelector.attributes.annotation == 'orchestrator:ansible' + - nm_selector_present.current.0.cloudEPSelector.attributes.descr == 'cloud epg selector' + - nm_selector_present.current.0.cloudEPSelector.attributes.matchExpression == "IP in('10.10.10.1')" + - nm_selector_present.current.0.cloudEPSelector.attributes.dn == 'uni/tn-ansible_test/cloudapp-anstest/cloudepg-anstest/epselector-ansible_selector' + - nm_selector_present.current.0.cloudEPSelector.attributes.name == 'ansible_selector' + - selector_present_again is not changed + - selector_present_again.previous == selector_present_again.current == nm_selector_present.current + + - name: Update aci cloud epg selector + cisco.aci.aci_cloud_epg_selector: + <<: *aci_cloud_epg_selector + expressions: + - key: ip + operator: in + value: 10.10.10.1,10.10.10.2 + - key: region + operator: equals + value: '{{ region }}' + - key: test_expression + operator: does_not_have_key + register: udpate_selector + + - name: Create second aci cloud epg selector + cisco.aci.aci_cloud_epg_selector: + <<: *aci_cloud_epg_selector + description: second cloud epg selector + name: ansible_selector_2 + expressions: + - key: ip + operator: not_equals + value: 10.10.10.3 + - key: region + operator: not_in + value: '{{ region_2 }}' + - key: test_expression_2 + operator: has_key + - key: zone + operator: does_not_have_key + register: sec_selector + + - name: Create selector with incorrect parameter - has_key with ip + cisco.aci.aci_cloud_epg_selector: + <<: *aci_cloud_epg_selector + name: ip_has_key + expressions: + - key: ip + operator: has_key + ignore_errors: true + register: ip_has_key + + - name: Create selector with incorrect parameter - does_not_have_key with value + cisco.aci.aci_cloud_epg_selector: + <<: *aci_cloud_epg_selector + name: does_not_have_key + expressions: + - key: ctm_test + operator: does_not_have_key + value: test_value + ignore_errors: true + register: does_not_without_key + + - name: Create selector with incorrect parameter - without value + cisco.aci.aci_cloud_epg_selector: + <<: *aci_cloud_epg_selector + name: equals_without_value + expressions: + - key: ctm_test + operator: equals + ignore_errors: true + register: equals_without_value + + - name: Verify creation of other selectors + assert: + that: + - sec_selector is changed + - udpate_selector is changed + - sec_selector.current.0.cloudEPSelector.attributes.name == 'ansible_selector_2' + - sec_selector.current.0.cloudEPSelector.attributes.dn == 'uni/tn-ansible_test/cloudapp-anstest/cloudepg-anstest/epselector-ansible_selector_2' + - ip_has_key.msg == "Operator 'has_key' is not supported when expression key is 'ip'" + - equals_without_value.msg == "Attribute 'value' needed for operator 'equals' in expression 'ctm_test'" + - does_not_without_key.msg == "Attribute 'value' is not supported for operator 'does_not_have_key' in expression 'ctm_test'" + + - name: Query specific cloud epg selector + cisco.aci.aci_cloud_epg_selector: + <<: *aci_info + tenant: ansible_test + ap: anstest + epg: anstest + name: ansible_selector + state: query + register: query_selector + + - name: Query all cloud epg selectors + cisco.aci.aci_cloud_epg_selector: + <<: *aci_info + tenant: ansible_test + ap: anstest + epg: anstest + state: query + register: query_all + + - name: Verify query + assert: + that: + - query_selector.current.0.cloudEPSelector.attributes.name == 'ansible_selector' + - query_all.current.0.cloudEPg.children | length >= 2 + + - name: Remove cloud epg selector + cisco.aci.aci_cloud_epg_selector: &selector_absent + <<: *aci_info + tenant: ansible_test + ap: anstest + epg: anstest + name: ansible_selector_2 + state: absent + register: rm_selector_2 + + - name: Remove cloud epg selector again + cisco.aci.aci_cloud_epg_selector: + <<: *selector_absent + register: rm_selector_2_again + + - name: Verify rm_selector_2 + assert: + that: + - rm_selector_2 is changed + - rm_selector_2.current == [] + - rm_selector_2_again is not changed
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_external_epg/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_external_epg/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_external_epg/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_external_epg/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_external_epg/tasks/main.yml new file mode 100644 index 000000000..b9511e98f --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_external_epg/tasks/main.yml @@ -0,0 +1,191 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, Anvitha Jain (@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: '{{ 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 cloud sites + when: query_cloud.current | length > 0 # This condition will execute only cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Ensure tenant doesn't exist + cisco.aci.aci_tenant: + <<: *aci_info + state: absent + tenant: ansible_test + register: tenant_absent + + - name: Ensure cloud external epg doesn't exist + cisco.aci.aci_cloud_external_epg: + <<: *aci_info + tenant: ansible_test + ap: anstest + name: anstest + state: absent + + - name: Ensure tenant exists + cisco.aci.aci_tenant: &aci_tenant_present + <<: *aci_info + state: present + tenant: ansible_test + register: tenant_present + + - name: Ensure application profile exists + cisco.aci.aci_cloud_ap: &aci_cloud_ap_present + <<: *aci_tenant_present + name: anstest + description: Ansible Test Cloud APIC + state: present + register: create_cloud_ap + + - name: Ensure vrf exist + cisco.aci.aci_vrf: &aci_vrf_present + <<: *aci_tenant_present + vrf: anstest + description: Ansible Test + register: vrf_present + + - name: Create another vrf + cisco.aci.aci_vrf: + <<: *aci_vrf_present + vrf: anstest_2 + register: another_vrf_present + + - name: Create aci cloud external epg (check_mode) + cisco.aci.aci_cloud_external_epg: &aci_cloud_ext_epg_present + <<: *aci_info + tenant: ansible_test + ap: anstest + vrf: anstest + description: Aci Cloud External EPG + name: anstest + route_reachability: internet + state: present + check_mode: true + register: cm_epg_present + + - name: Create aci cloud external epg (normal mode) + cisco.aci.aci_cloud_external_epg: + <<: *aci_cloud_ext_epg_present + register: nm_epg_present + + - name: Create aci cloud external epg again + cisco.aci.aci_cloud_external_epg: + <<: *aci_cloud_ext_epg_present + register: nm_epg_present_again + + - name: Verify cloud external epg creation + assert: + that: + - cm_epg_present is changed + - nm_epg_present is changed + - nm_epg_present_again is not changed + - cm_epg_present.previous == nm_epg_present.previous == [] + - cm_epg_present.proposed.cloudExtEPg.attributes.name == 'anstest' + - cm_epg_present.proposed.cloudExtEPg.attributes.descr == 'Aci Cloud External EPG' + - cm_epg_present.proposed.cloudExtEPg.attributes.dn == 'uni/tn-ansible_test/cloudapp-anstest/cloudextepg-anstest' + - cm_epg_present.proposed.cloudExtEPg.children.0.cloudRsCloudEPgCtx.attributes.tnFvCtxName == 'anstest' + - nm_epg_present.current.0.cloudExtEPg.attributes.annotation == 'orchestrator:ansible' + - nm_epg_present.current.0.cloudExtEPg.attributes.name == 'anstest' + - nm_epg_present.current.0.cloudExtEPg.attributes.descr == 'Aci Cloud External EPG' + - nm_epg_present.current.0.cloudExtEPg.attributes.dn == 'uni/tn-ansible_test/cloudapp-anstest/cloudextepg-anstest' + - nm_epg_present.current.0.cloudExtEPg.children.0.cloudRsCloudEPgCtx.attributes.tnFvCtxName == 'anstest' + - nm_epg_present_again.previous == nm_epg_present_again.current + + - name: Create another cloud external epg + cisco.aci.aci_cloud_external_epg: + <<: *aci_cloud_ext_epg_present + name: ansible_cloud_ext_epg + register: nm_another_epg_present + + - name: Verify another cloud external epg creation + assert: + that: + - nm_another_epg_present is changed + - nm_another_epg_present.previous == [] + - nm_another_epg_present.current.0.cloudExtEPg.attributes.name == 'ansible_cloud_ext_epg' + + - name: Update cloud external epg with another vrf + cisco.aci.aci_cloud_external_epg: + <<: *aci_cloud_ext_epg_present + vrf: anstest_2 + register: update_cloud_ext_epg + + - name: Update cloud external epg without vrf + cisco.aci.aci_cloud_external_epg: + <<: *aci_cloud_ext_epg_present + vrf: "{{ fakevar | default(omit) }}" + register: no_vrf + + - name: Veirfy update_cloud_ext_epg + assert: + that: + - update_cloud_ext_epg is changed + - update_cloud_ext_epg.current.0.cloudExtEPg.children.0.cloudRsCloudEPgCtx.attributes.tnFvCtxName == 'anstest_2' + + - name: Query specific cloud external epg + cisco.aci.aci_cloud_external_epg: + <<: *aci_info + tenant: ansible_test + ap: anstest + name: anstest + state: query + register: cloud_ext_epg_query + + - name: query all + cisco.aci.aci_cloud_external_epg: + <<: *aci_info + tenant: ansible_test + ap: anstest + state: query + register: query_all + + - name: Verify query + assert: + that: + - cloud_ext_epg_query is not changed + - cloud_ext_epg_query.current.0.cloudExtEPg.attributes.name == 'anstest' + - cloud_ext_epg_query.current.0.cloudExtEPg.attributes.dn == 'uni/tn-ansible_test/cloudapp-anstest/cloudextepg-anstest' + - cloud_ext_epg_query.current.0.cloudExtEPg.attributes.descr == 'Aci Cloud External EPG' + - cloud_ext_epg_query.current.0.cloudExtEPg.children.0.cloudRsCloudEPgCtx.attributes.tnFvCtxName == 'anstest_2' + - cloud_ext_epg_query.current.0.cloudExtEPg.children.0.cloudRsCloudEPgCtx.attributes.tDn == 'uni/tn-ansible_test/ctx-anstest_2' + - query_all is not changed + - query_all.current.0.cloudApp.children | length >= 2 + + - name: Remove cloud external epg + cisco.aci.aci_cloud_external_epg: &cloud_ext_epg_absent + <<: *aci_info + tenant: ansible_test + ap: anstest + name: anstest + state: absent + register: cloud_ext_epg_absent + + - name: Remove cloud external epg again + cisco.aci.aci_cloud_external_epg: + <<: *cloud_ext_epg_absent + register: cloud_ext_epg_absent_again + + - name: Verify deletion + assert: + that: + - cloud_ext_epg_absent is changed + - cloud_ext_epg_absent.current == [] + - cloud_ext_epg_absent_again is not changed diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_external_epg_selector/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_external_epg_selector/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_external_epg_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_cloud_external_epg_selector/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_external_epg_selector/tasks/main.yml new file mode 100644 index 000000000..21260c054 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_external_epg_selector/tasks/main.yml @@ -0,0 +1,182 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, Anvitha Jain (@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: '{{ 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 cloud sites + when: query_cloud.current | length > 0 # This condition will execute only cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Ensure tenant doesn't exist + cisco.aci.aci_tenant: + <<: *aci_info + state: absent + tenant: ansible_test + register: tenant_absent + + - name: Ensure cloud external epg doesn't exist + cisco.aci.aci_cloud_external_epg: + <<: *aci_info + tenant: ansible_test + ap: anstest + name: anstest + state: absent + + - name: Ensure tenant exists + cisco.aci.aci_tenant: &aci_tenant_present + <<: *aci_info + state: present + tenant: ansible_test + register: tenant_present + + - name: Ensure application profile exists + cisco.aci.aci_cloud_ap: &aci_cloud_ap_present + <<: *aci_tenant_present + name: anstest + description: Ansible Test Cloud APIC + state: present + register: create_cloud_ap + + - name: Ensure vrf exist + cisco.aci.aci_vrf: &aci_vrf_present + <<: *aci_tenant_present + vrf: anstest + description: Ansible Test + register: vrf_present + + - name: Create another vrf + cisco.aci.aci_vrf: + <<: *aci_vrf_present + vrf: anstest_2 + register: another_vrf_present + + - name: Ensure aci cloud external epg exist + cisco.aci.aci_cloud_external_epg: + <<: *aci_info + tenant: ansible_test + ap: anstest + vrf: anstest + description: Aci Cloud External EPG + name: anstest + route_reachability: internet + state: present + register: ext_epg_present + + - name: Create aci cloud external epg selector (check_mode) + cisco.aci.aci_cloud_external_epg_selector: &aci_cloud_ext_epg_present + <<: *aci_info + tenant: ansible_test + ap: anstest + cloud_external_epg: anstest + name: subnet1 + subnet: 10.0.0.0/16 + state: present + check_mode: true + register: cm_epg_present + + - name: Create aci cloud external epg selector (normal mode) + cisco.aci.aci_cloud_external_epg_selector: + <<: *aci_cloud_ext_epg_present + register: nm_epg_present + + - name: Create aci cloud external epg selector again + cisco.aci.aci_cloud_external_epg_selector: + <<: *aci_cloud_ext_epg_present + register: nm_epg_present_again + + - name: Verify cloud external epg creation + assert: + that: + - cm_epg_present is changed + - nm_epg_present is changed + - nm_epg_present_again is not changed + - cm_epg_present.previous == nm_epg_present.previous == [] + - cm_epg_present.proposed.cloudExtEPSelector.attributes.name == 'subnet1' + - cm_epg_present.proposed.cloudExtEPSelector.attributes.subnet == '10.0.0.0/16' + - cm_epg_present.proposed.cloudExtEPSelector.attributes.dn == 'uni/tn-ansible_test/cloudapp-anstest/cloudextepg-anstest/extepselector-[10.0.0.0/16]' + - nm_epg_present.current.0.cloudExtEPSelector.attributes.annotation == 'orchestrator:ansible' + - nm_epg_present.current.0.cloudExtEPSelector.attributes.name == 'subnet1' + - nm_epg_present.proposed.cloudExtEPSelector.attributes.subnet == '10.0.0.0/16' + - nm_epg_present.current.0.cloudExtEPSelector.attributes.dn == 'uni/tn-ansible_test/cloudapp-anstest/cloudextepg-anstest/extepselector-[10.0.0.0/16]' + - nm_epg_present_again.previous == nm_epg_present_again.current + + - name: Create another cloud external epg + cisco.aci.aci_cloud_external_epg_selector: + <<: *aci_cloud_ext_epg_present + name: subnet2 + subnet: 10.10.10.10/24 + register: nm_another_epg_present + + - name: Verify another cloud external epg creation + assert: + that: + - nm_another_epg_present is changed + - nm_another_epg_present.previous == [] + - nm_another_epg_present.current.0.cloudExtEPSelector.attributes.name == 'subnet2' + - nm_another_epg_present.current.0.cloudExtEPSelector.attributes.subnet == '10.10.10.10/24' + + - name: Query specific cloud external epg selector + cisco.aci.aci_cloud_external_epg_selector: + <<: *aci_info + tenant: ansible_test + ap: anstest + cloud_external_epg: anstest + name: subnet1 + state: query + register: cloud_ext_epg_query + + - name: query all selectors + cisco.aci.aci_cloud_external_epg_selector: + <<: *aci_info + tenant: ansible_test + ap: anstest + cloud_external_epg: anstest + state: query + register: query_all + + - name: Verify query + assert: + that: + - query_all is not changed + - query_all.current.0.cloudExtEPg.children | length >= 2 + + - name: Remove cloud external epg selector + cisco.aci.aci_cloud_external_epg_selector: &cloud_ext_epg_absent + <<: *aci_info + tenant: ansible_test + ap: anstest + cloud_external_epg: anstest + name: subnet1 + subnet: 10.0.0.0/16 + state: absent + register: cloud_ext_epg_absent + + - name: Remove cloud external epg again + cisco.aci.aci_cloud_external_epg_selector: + <<: *cloud_ext_epg_absent + register: cloud_ext_epg_absent_again + + - name: Verify deletion + assert: + that: + - cloud_ext_epg_absent is changed + - cloud_ext_epg_absent.current == [] + - cloud_ext_epg_absent_again is not changed diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_provider/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_provider/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_provider/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_provider/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_provider/tasks/main.yml new file mode 100644 index 000000000..9cc4c87b7 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_provider/tasks/main.yml @@ -0,0 +1,56 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Lionel Hercot (@lhercot) <lhercot@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 + +# CLEAN ENVIRONMENT +- 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 + aci_system: + <<: *aci_info + id: 1 + state: query + register: version + +# QUERY OBJECTS +- name: Query cloud provider object + aci_cloud_provider: + <<: *aci_info + state: query + register: query_cloud + when: version.current.0.topSystem.attributes.version is version('4.1', '>=') + +- name: Set vars + set_fact: + query_cloud: + current: [] + when: version.current.0.topSystem.attributes.version is version('4.1', '<') + +- name: Verify query_cloud for all sites + assert: + that: + - query_cloud is not changed + +- name: Verify query_cloud for Cloud Sites + assert: + that: + - query_cloud is not changed + - query_cloud.current.0.cloudProvP.attributes.environment == "public-cloud" + - '"vendor" in query_cloud.current.0.cloudProvP.attributes' + when: + - query_cloud.current | length > 0 # This condition will execute only cloud sites diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_region/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_region/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_region/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_region/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_region/tasks/main.yml new file mode 100644 index 000000000..f4c19c3f7 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_region/tasks/main.yml @@ -0,0 +1,74 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Cindy Zhao (@cizhao) <cizhao@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 + +# CLEAN ENVIRONMENT +- 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 cloud sites + when: query_cloud.current | length > 0 # This condition will execute only cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Query all regions + aci_cloud_region: + <<: *aci_info + cloud: "{{ cloud_type }}" + state: query + register: query_all + + - name: Verify query_all + assert: + that: + - query_all is not changed + - query_all.current.0.cloudProvP.attributes.dn == "uni/clouddomp/provp-{{cloud_type}}" + - query_all.current.0.cloudProvP.attributes.vendor == "{{cloud_type}}" + - query_all.current.0.cloudProvP.children | length > 10 + when: query_all.current != [] + + - name: Query a specific region + aci_cloud_region: + <<: *aci_info + cloud: "{{ cloud_type }}" + region: "{{ region_2 }}" + state: query + register: query_region + + - name: Verify query_region + assert: + that: + - query_region is not changed + - query_region.current.0.cloudRegion.attributes.adminSt == "managed" + - query_region.current.0.cloudRegion.attributes.dn == "uni/clouddomp/provp-{{cloud_type}}/region-{{region_2}}" + - query_region.current.0.cloudRegion.attributes.name == "{{region_2}}" + when: query_region.current != [] + + - name: Query non_existing region + aci_cloud_region: + <<: *aci_info + cloud: "{{ cloud_type }}" + region: non_existing + state: query + register: query_non_existing_region + + - name: Verify query_non_existing_region + assert: + that: + - query_non_existing_region is not changed + - query_non_existing_region.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_subnet/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_subnet/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_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_cloud_subnet/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_subnet/tasks/main.yml new file mode 100644 index 000000000..e438b4144 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_subnet/tasks/main.yml @@ -0,0 +1,261 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Cindy Zhao (@cizhao) <cizhao@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 + +# CLEAN ENVIRONMENT +- 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 cloud sites + when: query_cloud.current | length > 0 # This condition will execute only cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Ensure tenant doesn't exist + aci_tenant: + <<: *aci_info + state: absent + tenant: ansible_test + register: tenant_absent + + - name: Ensure tenant exists for tests to kick off + aci_tenant: + <<: *aci_info + state: present + tenant: ansible_test + register: tenant_present + + - name: Ensure aci cloud context profile does not exists + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + name: ctx_profile_1 + state: absent + register: rm_ctx_profile_1 + + - name: Verify rm_ctx_profile_1 + assert: + that: + - rm_ctx_profile_1.current == [] + + - name: Create aci cloud context profile (normal mode) + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + cloud: "{{ cloud_type }}" + name: ctx_profile_1 + vrf: ctx_profile_vrf_1 + region: "{{ region_2 }}" + primary_cidr: '10.50.0.0/16' + state: present + register: nm_add_aci_ctx_profile + + - name: Create aci cloud subnet (check_mode) + aci_cloud_subnet: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + cidr: '10.50.0.0/16' + availability_zone: "{{ availability_zone | default(omit) }}" + address: 10.50.0.1 + description: test description + check_mode: true + register: cm_add_subnet + + - name: Create aci cloud subnet (normal_mode) + aci_cloud_subnet: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + cidr: '10.50.0.0/16' + availability_zone: "{{ availability_zone | default(omit) }}" + address: 10.50.0.1 + description: test description + register: nm_add_subnet + + - name: Verify cm_add_subnet + assert: + that: + - cm_add_subnet is changed + - cm_add_subnet.previous == [] + - cm_add_subnet.proposed.cloudSubnet.attributes.ip == "10.50.0.1" + - cm_add_subnet.proposed.cloudSubnet.attributes.descr == "test description" + - cm_add_subnet.proposed.cloudSubnet.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1/cidr-[10.50.0.0/16]/subnet-[10.50.0.1]" + + - name: Create aci cloud subnet again (normal_mode) + aci_cloud_subnet: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + cidr: '10.50.0.0/16' + availability_zone: "{{ availability_zone | default(omit) }}" + address: 10.50.0.1 + description: test description + register: nm_add_subnet_again + + - name: Verify nm_add_subnet_again + assert: + that: + - nm_add_subnet_again is not changed + + - name: Create another cloud subnet (normal_mode) + aci_cloud_subnet: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + cidr: '10.50.0.0/16' + availability_zone: "{{ availability_zone | default(omit) }}" + address: 10.50.0.2 + description: another subnet + register: nm_add_another_subnet + + - name: Verify nm_add_another_subnet + assert: + that: + - nm_add_another_subnet is changed + - nm_add_another_subnet.previous == [] + - nm_add_another_subnet.current.0.cloudSubnet.attributes.annotation == 'orchestrator:ansible' + - nm_add_another_subnet.current.0.cloudSubnet.attributes.descr == "another subnet" + - nm_add_another_subnet.current.0.cloudSubnet.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1/cidr-[10.50.0.0/16]/subnet-[10.50.0.2]" + + - name: Create cloud subnet 3(normal_mode) + aci_cloud_subnet: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + cidr: '10.50.0.0/16' + availability_zone: "{{ availability_zone | default(omit) }}" + address: 10.50.0.3 + name: subnet_3 + register: nm_add_subnet_3 + + - name: Specify subnet as VpnGateway enabled + aci_cloud_subnet: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + cidr: '10.50.0.0/16' + availability_zone: "{{ availability_zone | default(omit) }}" + address: 10.50.0.1 + # name: subnet_1 + description: change subnet 1 + vnet_gateway: "{{ vnet_gateway | default(omit)}}" + #scope: public + register: nm_change_subnet_1 + + # Enable vpn_gateway router in cloud ctx profile + - name: Enable VpnGateway + aci_cloud_vpn_gateway: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + state: present + + # Try to disable vpn_gateway router again in cloud ctx profile + - name: Disable VpnGateway + aci_cloud_vpn_gateway: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + state: absent + + - name: Query all subnets + aci_cloud_subnet: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + cidr: '10.50.0.0/16' + state: query + register: query_all + + - name: Verify query_all + assert: + that: + - query_all is not changed + - query_all.current.0.cloudCidr.attributes.addr == "10.50.0.0/16" + - query_all.current.0.cloudCidr.children | length == 3 + + - name: Query a specific subnet + aci_cloud_subnet: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + cidr: '10.50.0.0/16' + address: 10.50.0.1 + state: query + register: query_subnet_1 + + - name: Verify query_subnet_1 + assert: + that: + - query_subnet_1 is not changed + - query_subnet_1.current.0.cloudSubnet.attributes.ip == "10.50.0.1" + - query_subnet_1.current.0.cloudSubnet.attributes.scope == "private" + - query_subnet_1.current.0.cloudSubnet.attributes.dn == "uni/tn-ansible_test/ctxprofile-ctx_profile_1/cidr-[10.50.0.0/16]/subnet-[10.50.0.1]" + + - name: Remove subnet 3 (check_mode) + aci_cloud_subnet: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + cidr: '10.50.0.0/16' + address: 10.50.0.3 + state: absent + check_mode: true + register: cm_remove_subnet_3 + + - name: Verify cm_remove_subnet_3 + assert: + that: + - cm_remove_subnet_3 is changed + - cm_remove_subnet_3.proposed == {} + - cm_remove_subnet_3.previous.0.cloudSubnet.attributes.ip == "10.50.0.3" + + - name: Remove subnet 3 (normal_mode) + aci_cloud_subnet: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + cidr: '10.50.0.0/16' + address: 10.50.0.3 + state: absent + register: nm_remove_subnet_3 + + - name: Verify nm_remove_subnet_3 + assert: + that: + - nm_remove_subnet_3 is changed + - nm_remove_subnet_3.current == [] + - nm_remove_subnet_3.previous.0.cloudSubnet.attributes.ip == "10.50.0.3" + + - name: Remove subnet 3 again + aci_cloud_subnet: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + cidr: '10.50.0.0/16' + address: 10.50.0.3 + state: absent + register: nm_remove_subnet_3_again + + - name: Verify nm_remove_subnet_3_again + assert: + that: + - nm_remove_subnet_3_again is not changed + - nm_remove_subnet_3_again.previous == [] + - nm_remove_subnet_3_again.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_vpn_gateway/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_vpn_gateway/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_vpn_gateway/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_vpn_gateway/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_vpn_gateway/tasks/main.yml new file mode 100644 index 000000000..834331a03 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_vpn_gateway/tasks/main.yml @@ -0,0 +1,114 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Cindy Zhao (@cizhao) <cizhao@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 + +# CLEAN ENVIRONMENT +- 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 cloud sites + when: query_cloud.current | length > 0 # This condition will execute only cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Ensure tenant doesn't exist + aci_tenant: + <<: *aci_info + state: absent + tenant: ansible_test + register: tenant_absent + + - name: Ensure tenant exists for tests to kick off + aci_tenant: + <<: *aci_info + state: present + tenant: ansible_test + register: tenant_present + + - name: Ensure aci cloud context profile does not exists + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + name: ctx_profile_1 + state: absent + register: rm_ctx_profile_1 + + - name: Verify rm_ctx_profile_1 + assert: + that: + - rm_ctx_profile_1.current == [] + + - name: Create aci cloud context profile (normal mode) + aci_cloud_ctx_profile: + <<: *aci_info + tenant: ansible_test + cloud: "{{ cloud_type }}" + name: ctx_profile_1 + vrf: ctx_profile_vrf_1 + region: "{{ region_2 }}" + primary_cidr: '10.50.0.0/16' + state: present + register: nm_add_aci_ctx_profile + + - name: Create aci cloud subnet with VpnGateway enabled (normal_mode) + aci_cloud_subnet: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + cidr: '10.50.0.0/16' + availability_zone: "{{ availability_zone | default(omit) }}" + address: 10.50.0.1 + description: specify this subnet as VpnGateway router + vnet_gateway: "{{ vnet_gateway | default(omit)}}" + state: present + register: nm_add_subnet + + - name: Enable VpnGateway + aci_cloud_vpn_gateway: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + state: present + + - name: Disable VpnGateway + aci_cloud_vpn_gateway: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + state: absent + + - name: Enable VpnGateway again + aci_cloud_vpn_gateway: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + state: present + + - name: Query VpnGateway + aci_cloud_vpn_gateway: + <<: *aci_info + tenant: ansible_test + cloud_context_profile: ctx_profile_1 + register: query_vpn_gateway + + - name: Verify VpnGateway + assert: + that: + - query_vpn_gateway is not changed + - query_vpn_gateway.current.0.cloudRouterP.children | length == 3 + - query_vpn_gateway.current.0.cloudRouterP.attributes.annotation == 'orchestrator:ansible' diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_zone/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_zone/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_zone/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_zone/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_zone/tasks/main.yml new file mode 100644 index 000000000..85a2ec087 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_cloud_zone/tasks/main.yml @@ -0,0 +1,97 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Cindy Zhao (@cizhao) <cizhao@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 + +# CLEAN ENVIRONMENT +- 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 cloud sites + when: query_cloud.current | length > 0 # This condition will execute only cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Query all zones under us-west-1 + aci_cloud_zone: + <<: *aci_info + cloud: "{{ cloud_type }}" + region: "{{ region_2 }}" + state: query + register: query_all + + - name: Verify query_all + assert: + that: + - query_all is not changed + - query_all.current.0.cloudRegion.attributes.name == "{{region_2}}" + - query_all.current.0.cloudRegion.children | length >= 1 + + - name: Query a specific zone under region us-west-1 + aci_cloud_zone: + <<: *aci_info + cloud: "{{ cloud_type }}" + region: "{{ region_2 }}" + zone: "{{ availability_zone | default(omit) }}" + state: query + register: query_zone_1 + + - name: Query another specific zone under region us-west-1 + aci_cloud_zone: + <<: *aci_info + cloud: "{{ cloud_type }}" + region: "{{ region_2 }}" + zone: us-west-1b + state: query + register: query_zone_2 + + - name: Verify query_zone_1 and query_zone_2 + assert: + that: + - query_zone_1 is not changed + - query_zone_2 is not changed + - query_zone_1.current.0.cloudZone.attributes.name == "{{availability_zone}}" + - query_zone_1.current.0.cloudZone.attributes.dn == "uni/clouddomp/provp-{{cloud_type}}/region-{{region_2}}/zone-us-west-1a" + - query_zone_2.current.0.cloudZone.attributes.name == "us-west-1b" + - query_zone_2.current.0.cloudZone.attributes.dn == "uni/clouddomp/provp-{{cloud_type}}/region-{{region_2}}/zone-us-west-1b" + when: query_zone_1.current != [] and query_zone_2.current != [] + + - name: Query non_existing zone under region us-west-1 + aci_cloud_zone: + <<: *aci_info + cloud: "{{ cloud_type }}" + region: "{{ region_2 }}" + zone: non_existing + state: query + register: query_non_existing_zone + + - name: Query zone under non_existing region + aci_cloud_zone: + <<: *aci_info + cloud: "{{ cloud_type }}" + region: non_existing + zone: "{{ availability_zone | default(omit) }}" + state: query + register: query_non_existing_region + + - name: Verify query_non_existing_zone + assert: + that: + - query_non_existing_zone is not changed + - query_non_existing_zone.current == [] + - query_non_existing_region is not changed + - query_non_existing_region.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_config_export_policy/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_export_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_export_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_config_export_policy/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_export_policy/tasks/main.yml new file mode 100644 index 000000000..bb290aa5f --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_export_policy/tasks/main.yml @@ -0,0 +1,161 @@ +# Author: Tim Cragg (@timcragg) +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# 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") }}' + +# CLEAN ENVIRONMENT +- name: Remove the ansible_export_policy + cisco.aci.aci_config_export_policy: + <<: *aci_info + name: ansible_export_policy + state: absent + +- name: Delete Config Export Policy with scheduler + cisco.aci.aci_config_export_policy: + <<: *aci_info + name: ansible_export_policy_scheduler + state: absent + +- name: Delete Config Export Policy with export destination + cisco.aci.aci_config_export_policy: + <<: *aci_info + name: ansible_export_policy_destination + state: absent + +# CREATE CONFIG EXPORT POLICY +- name: Create a Config Export Policy (check mode) + cisco.aci.aci_config_export_policy: &aci_conf_policy + <<: *aci_info + name: ansible_export_policy + description: Test Config Export Policy + scheduler: test_scheduler + export_destination: test_dest + start_now: no + check_mode: yes + register: cm_create_conf_export + +- name: Create a Config Export Policy + cisco.aci.aci_config_export_policy: + <<: *aci_conf_policy + register: nm_create_conf_export + +- name: Create a Config Export Policy again + cisco.aci.aci_config_export_policy: + <<: *aci_conf_policy + register: nm_create_conf_export_again + +- name: Create a Config Export Policy with scheduler, set to start_now + cisco.aci.aci_config_export_policy: + <<: *aci_info + name: ansible_export_policy_scheduler + scheduler: test_scheduler + start_now: yes + register: sched_policy + +- name: Create a Config Export Policy with export destination + cisco.aci.aci_config_export_policy: + <<: *aci_info + name: ansible_export_policy_destination + export_destination: test_dest + register: dest_policy + +- name: Verify creation of File Remote Path + ansible.builtin.assert: + that: + - cm_create_conf_export is changed + - nm_create_conf_export is changed + - nm_create_conf_export_again is not changed + - nm_create_conf_export.current.0.configExportP.attributes.name == "ansible_export_policy" + - nm_create_conf_export.current.0.configExportP.attributes.descr == "Test Config Export Policy" + - nm_create_conf_export.current.0.configExportP.attributes.format == "json" + - nm_create_conf_export.current.0.configExportP.attributes.adminSt == "untriggered" + - nm_create_conf_export_again.current.0.configExportP.attributes.name == "ansible_export_policy" + - nm_create_conf_export_again.current.0.configExportP.attributes.descr == "Test Config Export Policy" + - nm_create_conf_export_again.current.0.configExportP.attributes.format == "json" + - nm_create_conf_export_again.current.0.configExportP.attributes.adminSt == "untriggered" + - sched_policy.current.0.configExportP.children.1.configRsExportScheduler.attributes.tnTrigSchedPName == "test_scheduler" + - sched_policy.sent.configExportP.attributes.adminSt == "triggered" + - dest_policy.current.0.configExportP.children.0.configRsRemotePath.attributes.tnFileRemotePathName == "test_dest" + +# UPDATE CONFIG EXPORT POLICY +- name: Update Config Export Policy + cisco.aci.aci_config_export_policy: + <<: *aci_conf_policy + format: xml + target_dn: uni/tn-common + register: update_conf_export + +- name: Verify update of File Remote Path + ansible.builtin.assert: + that: + - update_conf_export is changed + - update_conf_export.current.0.configExportP.attributes.name == "ansible_export_policy" + - update_conf_export.current.0.configExportP.attributes.descr == "Test Config Export Policy" + - update_conf_export.current.0.configExportP.attributes.format == "xml" + - update_conf_export.current.0.configExportP.attributes.targetDn == "uni/tn-common" + +# QUERY CONFIG EXPORT POLICY +- name: Query Config Export Policy + cisco.aci.aci_config_export_policy: + <<: *aci_conf_policy + state: query + register: query_one + +- name: Query all Config Export Policies + cisco.aci.aci_config_export_policy: + <<: *aci_info + state: query + register: query_all + +- name: Verify Config Export Policy queries + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current.0.configExportP.attributes.name == "ansible_export_policy" + - query_one.current.0.configExportP.attributes.descr == "Test Config Export Policy" + - query_one.current.0.configExportP.attributes.format == "xml" + - query_one.current.0.configExportP.attributes.targetDn == "uni/tn-common" + - query_all is not changed + - query_all.current | length > 1 + +# REMOVE CONFIG EXPORT POLICY +- name: Delete a Config Export Policy + cisco.aci.aci_config_export_policy: + <<: *aci_conf_policy + state: absent + register: delete + +- name: Delete File Config Export Policy again + cisco.aci.aci_config_export_policy: + <<: *aci_conf_policy + state: absent + register: delete_again + +- name: Verify deletion of Config Export Policy + ansible.builtin.assert: + that: + - delete is changed + - delete_again is not changed + - delete.current == [] + +- name: Delete Config Export Policy with scheduler + cisco.aci.aci_config_export_policy: + <<: *aci_info + name: ansible_export_policy_scheduler + state: absent + +- name: Delete Config Export Policy with export destination + cisco.aci.aci_config_export_policy: + <<: *aci_info + name: ansible_export_policy_destination + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_config_rollback/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_rollback/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_rollback/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..df4c64069 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_rollback/tasks/main.yml @@ -0,0 +1,110 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) + +# 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: ensure tenant does not exist for tests to kick off + cisco.aci.aci_tenant: &aci_tenant_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 + state: absent + tenant: ansible_test + +- name: create a snapshot + cisco.aci.aci_config_snapshot: &create_snapshot + <<: *aci_tenant_absent + state: present + tenant: "{{ fakevar | default(omit) }}" + export_policy: anstest + +- name: create a tenant - use for rollback + cisco.aci.aci_tenant: &aci_tenant + <<: *create_snapshot + export_policy: "{{ fakevar | default(omit) }}" + tenant: ansible_test + register: tenant_present + +- name: create a new snapshot + cisco.aci.aci_config_snapshot: + <<: *create_snapshot + register: create_snapshot_annotation_check + +- name: waiting for snapshot to be finished before querying + pause: + seconds: 10 + +- name: get snapshots + cisco.aci.aci_config_snapshot: + <<: *create_snapshot + 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' diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_config_snapshot/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_snapshot/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_snapshot/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..22bcbcb79 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_config_snapshot/tasks/main.yml @@ -0,0 +1,148 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.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: create a snapshot - creation works + cisco.aci.aci_config_snapshot: &create_snapshot + 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 + export_policy: anstest + include_secure: false + format: json + description: ansible test + register: create + +- name: update snapshot to include secure and use xml - update works + cisco.aci.aci_config_snapshot: + <<: *create_snapshot + max_count: 10 + include_secure: true + format: xml + register: create_update + +- name: create a snapshot invalid max_count - error message + cisco.aci.aci_config_snapshot: + <<: *create_snapshot + max_count: 11 + ignore_errors: true + register: invalid_max_count + +- name: create a snapshot invalid max_count - error message + cisco.aci.aci_config_snapshot: + <<: *create_snapshot + export_policy: "{{ fake_var | default(omit) }}" + ignore_errors: true + register: missing_param + +- name: present assertion tests + assert: + that: + - create is not failed + - create is changed + - create.sent.configExportP.attributes.adminSt == "triggered" + - create_update is not failed + - create_update is changed + - create_update.current.0.configExportP.attributes.annotation == 'orchestrator:ansible' + - create_update.sent.configExportP.attributes.adminSt == 'triggered' + - create_update.sent.configExportP.attributes.format == 'xml' + - create_update.sent.configExportP.attributes.includeSecureFields == 'yes' + - invalid_max_count is failed + - invalid_max_count.msg == "Parameter 'max_count' must be a number between 1 and 10" + - missing_param is failed + - 'missing_param.msg == "state is present but all of the following are missing: export_policy"' + - create.job_details.attributes.dn == "uni/backupst/jobs-[uni/fabric/configexp-anstest]" + - create.job_details.attributes.name == "anstest" + - "'lastJobName' in create.job_details.attributes" + +- name: query with export_policy + cisco.aci.aci_config_snapshot: &query_snapshot + <<: *create_snapshot + state: query + register: query_export + +- name: generate snapshot name + set_fact: + test_snapshot: "{{ query_export.current.0.configSnapshotCont.children.0.configSnapshot.attributes.rn.strip('snapshot-') }}" + +- name: query with export_policy and snapshot + cisco.aci.aci_config_snapshot: &query_both + <<: *query_snapshot + snapshot: "{{ test_snapshot }}" + register: query_export_snapshot + +- name: query with snapshot - module add run- to snapshot + cisco.aci.aci_config_snapshot: + <<: *query_snapshot + export_policy: "{{ fake_var | default(omit) }}" + snapshot: "{{ test_snapshot.strip('run-') }}" + register: query_snapshot + +- name: query no params + cisco.aci.aci_config_snapshot: + <<: *query_snapshot + export_policy: "{{ fake_var | default(omit) }}" + register: query_all + +- name: query assertion tests + assert: + that: + - query_export is not failed + - query_export is not changed + - '"snapshots-[uni/fabric/configexp-anstest].json" in query_export.url' + - query_export.current.0.configSnapshotCont.attributes.name == "anstest" + - query_export.current.0.configSnapshotCont.children | length > 1 + - query_export_snapshot is not failed + - query_export_snapshot is not changed + - '"snapshots-[uni/fabric/configexp-anstest]/snapshot-{{ test_snapshot }}.json" in query_export_snapshot.url' + - query_export_snapshot.current | length == 1 + - query_snapshot is not failed + - query_snapshot is not changed + - '"class/configSnapshot.json" in query_snapshot.url' + - '"configSnapshot.name,\"{{ test_snapshot }}\"" in query_snapshot.filter_string' + - query_all is not failed + - query_all is not changed + - '"class/configSnapshot.json" in query_all.url' + - query_all.current | length > 1 + +- name: delete works + cisco.aci.aci_config_snapshot: &delete + <<: *query_both + state: absent + register: delete_snapshot + +- name: delete works - idempotency + cisco.aci.aci_config_snapshot: + <<: *delete + register: delete_idempotent + +- name: delete missing param + cisco.aci.aci_config_snapshot: + <<: *delete + snapshot: "{{ fake_var | default(omit) }}" + ignore_errors: true + register: delete_missing_param + +- name: absent assertion tests + assert: + that: + - delete_snapshot is not failed + - delete_snapshot is changed + - delete_snapshot.sent.configSnapshot.attributes.retire == 'yes' + - delete_snapshot.previous != [] + - delete_snapshot.previous.0.configSnapshot.attributes.name == test_snapshot + - delete_idempotent is not failed + - delete_idempotent is not changed + - delete_idempotent.previous == [] + - delete_missing_param is failed + - 'delete_missing_param.msg == "state is absent but all of the following are missing: snapshot"' diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_contract/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_contract/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract/tasks/main.yml new file mode 100644 index 000000000..635f2d331 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract/tasks/main.yml @@ -0,0 +1,165 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) + +# 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: 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 + tenant: ansible_test + state: present + register: tenant_present + +- name: create contract - check mode works + cisco.aci.aci_contract: &aci_contract_present + <<: *aci_tenant_present + contract: anstest + description: Ansible Test + check_mode: true + register: present_check_mode + +- name: create contract - creation works + cisco.aci.aci_contract: + <<: *aci_contract_present + register: contract_present + +- name: create contract - idempotency works + cisco.aci.aci_contract: + <<: *aci_contract_present + register: present_idempotent + +- name: update contract - update works + cisco.aci.aci_contract: + <<: *aci_contract_present + scope: application-profile + register: present_update + +- name: create contract - used for query + cisco.aci.aci_contract: + <<: *aci_contract_present + contract: anstest2 + +- name: missing param - failure message works + cisco.aci.aci_contract: + <<: *aci_tenant_present + ignore_errors: true + register: present_missing_param + +- name: present assertions + assert: + that: + - present_check_mode is changed + - present_check_mode.previous == [] + - present_check_mode.sent.vzBrCP.attributes.name == 'anstest' + - present_check_mode.sent.vzBrCP.attributes.descr == 'Ansible Test' + - contract_present is changed + - contract_present.current.0.vzBrCP.attributes.annotation == 'orchestrator:ansible' + - contract_present.sent == present_check_mode.sent + - present_idempotent is not changed + - present_update is changed + - present_update.sent != present_update.proposed + - present_update.sent.vzBrCP.attributes.scope == "application-profile" + - present_missing_param is failed + - 'present_missing_param.msg == "state is present but all of the following are missing: contract"' + +- name: query contract + cisco.aci.aci_contract: &aci_contract_query + <<: *aci_contract_present + state: query + register: query_contract + +- name: query all in tenant + cisco.aci.aci_contract: + <<: *aci_contract_query + contract: "{{ fakevar | default(omit) }}" + register: query_tenant + +- name: query all with name + cisco.aci.aci_contract: + <<: *aci_contract_query + tenant: "{{ fakevar | default(omit) }}" + register: query_name + +- name: query all + cisco.aci.aci_contract: + <<: *aci_contract_query + tenant: "{{ fakevar | default(omit) }}" + contract: "{{ fakevar | default(omit) }}" + register: query_all + +- name: query assertions + assert: + that: + - query_contract is not changed + - query_contract.current | length == 1 + - '"tn-ansible_test/brc-anstest.json" in query_contract.url' + - query_tenant is not changed + - query_tenant.current | length == 1 + - query_tenant.current.0.fvTenant.children | length > 1 + - '"rsp-subtree-class=vzBrCP" in query_tenant.filter_string' + - '"tn-ansible_test.json" in query_tenant.url' + - query_name is not changed + - query_name.current != [] + - '"query-target-filter=eq(vzBrCP.name,\"anstest\")" in query_name.filter_string' + - '"class/vzBrCP.json" in query_name.url' + - query_all is not changed + - query_all.current | length > 1 + - '"class/vzBrCP.json" in query_all.url' + +- name: delete contract - check mode works + cisco.aci.aci_contract: &aci_contract_absent + <<: *aci_contract_present + state: absent + check_mode: true + register: absent_check_mode + +- name: delete contract - deletion works + cisco.aci.aci_contract: + <<: *aci_contract_absent + register: contract_absent + +- name: delete contract - idempotency works + cisco.aci.aci_contract: + <<: *aci_contract_absent + register: absent_idempotent + +- name: delete contract - cleanup second contract + cisco.aci.aci_contract: + <<: *aci_contract_absent + contract: anstest2 + +- name: missing param - fail message works + cisco.aci.aci_contract: + <<: *aci_contract_absent + tenant: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: absent_missing_param + +- name: absent assertions + assert: + that: + - absent_check_mode is changed + - absent_check_mode.previous != [] + - contract_absent is changed + - contract_absent.previous == absent_check_mode.previous + - absent_idempotent is not changed + - absent_idempotent.previous == [] + - absent_missing_param is failed + - 'absent_missing_param.msg == "state is absent but all of the following are missing: tenant"' + +- 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_contract_export/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_export/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_export/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_export/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_export/tasks/main.yml new file mode 100644 index 000000000..5a1139947 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_export/tasks/main.yml @@ -0,0 +1,140 @@ +# Author: Marcel Zehnder (@maercu) +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# 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") }}' + +# CLEAN ENVIRONMENT +- name: Remove test tenant1 before we kickoff + cisco.aci.aci_tenant: &tenant1_absent + <<: *aci_info + tenant: ansible_test + state: absent + +- name: Remove test tenant2 before we kickoff + cisco.aci.aci_tenant: &tenant2_absent + <<: *aci_info + tenant: ansible_test_2 + state: absent + +# SETUP ENVIRONMENT +- name: Create tenant1 + cisco.aci.aci_tenant: &tenant1_present + <<: *tenant1_absent + state: present + +- name: Create tenant2 + cisco.aci.aci_tenant: &tenant2_present + <<: *tenant2_absent + state: present + +- name: Configure source contracts + cisco.aci.aci_contract: + <<: *tenant1_present + contract: '{{ item }}' + scope: global + loop: + - src_contract1 + - src_contract2 + +# BEGIN WITH TESTS +- name: Create contract interface (check_mode) + cisco.aci.aci_contract_export: &cif_present + <<: *tenant1_present + contract: src_contract1 + destination_tenant: ansible_test_2 + name: testcif1 + check_mode: true + register: cm_add_intf + +- name: Create contract interface (normal_mode) + cisco.aci.aci_contract_export: + <<: *cif_present + register: nm_add_intf + +- name: Verify add_intf + assert: + that: + - cm_add_intf is changed + - nm_add_intf is changed + - cm_add_intf.previous == nm_add_intf.previous == [] + - cm_add_intf.sent.vzCPIf.attributes.name == nm_add_intf.sent.vzCPIf.attributes.name == 'testcif1' + - nm_add_intf.current.0.vzCPIf.attributes.annotation == 'orchestrator:ansible' + +- name: Create interface again, check if idempotency works + cisco.aci.aci_contract_export: + <<: *cif_present + register: add_intf_again + +- name: Verify add_intf_again + assert: + that: + - add_intf_again is not changed + +# UPDATE CONTRACT INTERFACEE +- name: Update interface + cisco.aci.aci_contract_export: &cif_update + <<: *cif_present + description: newdescription + register: update_intf + +- name: Verify update_intf + assert: + that: + - update_intf is changed + - update_intf.previous != [] + +# CREATE ANOTHER CONTRACT INTERFACE +- name: Add another profile + cisco.aci.aci_contract_export: + <<: *cif_present + name: testcif2 + contract: src_contract2 + +# QUERY ALL INTERFACES +- name: Query all interfaces + cisco.aci.aci_contract_export: + <<: *aci_info + state: query + register: query_all_intfs + +- name: Verify query_all_intfs + assert: + that: + - query_all_intfs is not changed + - query_all_intfs.current|length > 1 + +# QUERY A SPECIFIC INTERFACE +- name: Query a specific interface + cisco.aci.aci_contract_export: + <<: *cif_update + state: query + register: query_spec_intf + +- name: Verify query_spec_intf + assert: + that: + - query_spec_intf is not changed + - query_spec_intf.current|length == 1 + +# REMOVE INTERFACE +- name: Remove interface + cisco.aci.aci_contract_export: + <<: *cif_update + state: absent + register: remove_intf + +- name: Verify remove_intf + assert: + that: + - remove_intf is changed + - remove_intf.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject/tasks/main.yml new file mode 100644 index 000000000..b7d53844c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject/tasks/main.yml @@ -0,0 +1,400 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) + +# 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: Assure tenant removal after tests + block: + - name: ensure tenant is deleted for clean state + 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 contract exists for tests to kick off + cisco.aci.aci_contract: &aci_contract_present + <<: *aci_tenant_present + contract: anstest + register: contract_present + + - name: create subject - check mode works + cisco.aci.aci_contract_subject: &aci_subject_present + <<: *aci_contract_present + subject: anstest + description: Ansible Test + check_mode: true + register: subject_present_check_mode + + - name: create subject - creation works + cisco.aci.aci_contract_subject: + <<: *aci_subject_present + register: subject_present + + - name: create subject - idempotency works + cisco.aci.aci_contract_subject: + <<: *aci_subject_present + register: subject_present_idempotent + + - name: update subject - update works + cisco.aci.aci_contract_subject: + <<: *aci_subject_present + description: Ansible Test + reverse_filter: "yes" + provider_match: at_most_one + priority: level2 + register: subject_update + + - name: create subject - try additional params + cisco.aci.aci_contract_subject: &aci_subject_present_2 + <<: *aci_contract_present + subject: anstest2 + reverse_filter: "no" + consumer_match: all + priority: level3 + register: subject_present_2 + + - name: missing param - failure message works + cisco.aci.aci_contract_subject: + <<: *aci_tenant_present + ignore_errors: true + register: present_missing_param + + - name: present assertions + assert: + that: + - subject_present_check_mode is changed + - subject_present_check_mode.sent.vzSubj.attributes.descr == 'Ansible Test' + - subject_present_check_mode.sent.vzSubj.attributes.name == 'anstest' + - subject_present is changed + - subject_present.previous == [] + - subject_present.sent == subject_present_check_mode.sent + - subject_present.current.0.vzSubj.attributes.annotation == 'orchestrator:ansible' + - subject_present_idempotent is not changed + - subject_present_idempotent.previous != [] + - subject_update is changed + - subject_update.sent != subject_update.proposed + - subject_update.sent.vzSubj.attributes.prio == 'level2' + - subject_update.sent.vzSubj.attributes.provMatchT == 'AtmostOne' + - subject_present_2 is changed + - subject_present_2.sent.vzSubj.attributes.consMatchT == 'All' + - subject_present_2.sent.vzSubj.attributes.name == 'anstest2' + - subject_present_2.sent.vzSubj.attributes.prio == 'level3' + - subject_present_2.sent.vzSubj.attributes.revFltPorts == 'no' + - present_missing_param is failed + - 'present_missing_param.msg == "state is present but all of the following are missing: contract, subject"' + + - name: query tenant contract subject + cisco.aci.aci_contract_subject: &aci_query_subject + <<: *aci_subject_present + state: query + register: query_tenant_contract_subject + + - name: query tenant contract + cisco.aci.aci_contract_subject: + <<: *aci_query_subject + subject: "{{ fakevar | default(omit) }}" + register: query_tenant_contract + + - name: query tenant subject + cisco.aci.aci_contract_subject: + <<: *aci_query_subject + contract: "{{ fakevar | default(omit) }}" + register: query_tenant_subject + + - name: query contract subject + cisco.aci.aci_contract_subject: + <<: *aci_query_subject + tenant: "{{ fakevar | default(omit) }}" + register: query_contract_subject + + - name: query tenant + cisco.aci.aci_contract_subject: + <<: *aci_tenant_present + state: query + register: query_tenant + + - name: query contract + cisco.aci.aci_contract_subject: + <<: *aci_contract_present + state: query + tenant: "{{ fakevar | default(omit) }}" + register: query_contract + + - name: query subject + cisco.aci.aci_contract_subject: + <<: *aci_query_subject + tenant: "{{ fakevar | default(omit) }}" + contract: "{{ fakevar | default(omit) }}" + register: query_subject + + - name: query all + cisco.aci.aci_contract_subject: + <<: *aci_info + state: query + register: query_all + + - name: query assertions + assert: + that: + - query_tenant_contract_subject is not changed + - query_tenant_contract_subject.current | length == 1 + - query_tenant_contract_subject.current.0.vzSubj.attributes.name == "anstest" + - '"tn-ansible_test/brc-anstest/subj-anstest.json" in query_tenant_contract_subject.url' + - query_tenant_contract is not changed + - query_tenant_contract.current | length == 1 + - query_tenant_contract.current.0.vzBrCP.attributes.name == "anstest" + - query_tenant_contract.current.0.vzBrCP.children | length == 2 + - '"?rsp-subtree=full&rsp-subtree-class=vzInTerm,vzOutTerm,vzSubj" in query_tenant_contract.filter_string' + - '"tn-ansible_test/brc-anstest.json" in query_tenant_contract.url' + - query_tenant_subject is not changed + - query_tenant_subject.current | length == 1 + - query_tenant_subject.current.0.fvTenant.attributes.name == "ansible_test" + - query_tenant_subject.current.0.fvTenant.children.0.vzBrCP.children | length == 1 + - query_tenant_subject.current.0.fvTenant.children.0.vzBrCP.children.0.vzSubj.attributes.name == "anstest" + - '"rsp-subtree-filter=eq(vzSubj.name,\"anstest\")" in query_tenant_subject.filter_string' + - '"rsp-subtree-class=vzInTerm,vzOutTerm,vzSubj" in query_tenant_subject.filter_string' + - '"tn-ansible_test.json" in query_tenant_subject.url' + - query_contract_subject is not changed + - query_contract_subject.current.0.vzBrCP.attributes.name == "anstest" + - query_contract_subject.current.0.vzBrCP.children | length == 1 + - query_contract_subject.current.0.vzBrCP.children.0.vzSubj.attributes.name == "anstest" + - '"query-target-filter=eq(vzBrCP.name,\"anstest\")" in query_contract_subject.filter_string' + - '"rsp-subtree-filter=eq(vzSubj.name,\"anstest\")" in query_contract_subject.filter_string' + - '"rsp-subtree-class=vzInTerm,vzOutTerm,vzSubj" in query_contract_subject.filter_string' + - '"class/vzBrCP.json" in query_contract_subject.url' + - query_tenant is not changed + - query_tenant.current | length == 1 + - query_tenant.current.0.fvTenant.attributes.name == "ansible_test" + - '"rsp-subtree-class=vzBrCP,vzInTerm,vzOutTerm,vzSubj" in query_tenant.filter_string' + - '"tn-ansible_test.json" in query_tenant.url' + - query_contract is not changed + - query_contract.current.0.vzBrCP.attributes.name == "anstest" + - '"query-target-filter=eq(vzBrCP.name,\"anstest\")" in query_contract.filter_string' + - '"rsp-subtree-class=vzInTerm,vzOutTerm,vzSubj" in query_contract.filter_string' + - '"class/vzBrCP.json" in query_contract.url' + - query_subject is not changed + - query_subject.current.0.vzSubj.attributes.name == "anstest" + - '"query-target-filter=eq(vzSubj.name,\"anstest\")" in query_subject.filter_string' + - '"class/vzSubj.json" in query_subject.url' + - query_all is not changed + - query_all.current|length > 1 + - query_all.current.0.vzSubj is defined + - '"class/vzSubj.json" in query_all.url' + + - name: delete subject - check mode works + cisco.aci.aci_contract_subject: &aci_subject_absent + <<: *aci_subject_present + state: absent + check_mode: true + register: subject_absent_check_mode + + - name: delete subject - deletion works + cisco.aci.aci_contract_subject: + <<: *aci_subject_absent + register: subject_absent + + - name: delete subject - idempotency works + cisco.aci.aci_contract_subject: + <<: *aci_subject_absent + register: subject_absent_idempotent + + - name: delete subject - cleanup + cisco.aci.aci_contract_subject: + <<: *aci_subject_present_2 + state: absent + + - name: missing params - failure message works + cisco.aci.aci_contract_subject: + <<: *aci_subject_absent + subject: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: absent_missing_param + + - name: absent assertions + assert: + that: + - subject_absent_check_mode is changed + - subject_absent_check_mode.previous != [] + - subject_absent_check_mode.proposed == {} + - subject_absent is changed + - subject_absent.previous == subject_absent_check_mode.previous + - subject_absent_idempotent is not changed + - subject_absent_idempotent.previous == [] + - absent_missing_param is failed + - 'absent_missing_param.msg == "state is absent but all of the following are missing: subject"' + + - name: create contract 1 + cisco.aci.aci_contract: &aci_contract1 + <<: *aci_tenant_present + contract: contract1 + register: contract_present + + - name: create subject both (check_mode) + cisco.aci.aci_contract_subject: &aci_subject_both + <<: *aci_contract1 + subject: subjectboth + check_mode: true + register: cm_subject_present_both_default + + - name: create subject both + cisco.aci.aci_contract_subject: + <<: *aci_subject_both + register: nm_subject_present_both_default + + - name: create subject both again with direction both set + cisco.aci.aci_contract_subject: + <<: *aci_subject_both + apply_both_direction: both + register: nm_subject_present_both_again + + - name: create subject one-way (check_mode) + cisco.aci.aci_contract_subject: &aci_subject_one_way + <<: *aci_contract1 + subject: subjectoneway + apply_both_direction: one-way + check_mode: true + register: cm_subject_present_one_way + + - name: create subject one-way + cisco.aci.aci_contract_subject: + <<: *aci_subject_one_way + register: nm_subject_present_one_way + + - name: create subject one-way again + cisco.aci.aci_contract_subject: + <<: *aci_subject_one_way + register: nm_subject_present_one_way_again + + - name: subject assertions + assert: + that: + - cm_subject_present_both_default is changed + - nm_subject_present_both_default is changed + - nm_subject_present_both_default.current.0.vzSubj.attributes.name == "subjectboth" + - nm_subject_present_both_again is not changed + - cm_subject_present_one_way is changed + - nm_subject_present_one_way is changed + - nm_subject_present_one_way.current.0.vzSubj.attributes.name == "subjectoneway" + - nm_subject_present_one_way_again is not changed + + - name: reverse subject both to one-way + cisco.aci.aci_contract_subject: + <<: *aci_subject_both + apply_both_direction: one-way + register: nm_subject_reverse_to_one_way + ignore_errors: true + + - name: reverse subject one-way to both + cisco.aci.aci_contract_subject: + <<: *aci_subject_one_way + apply_both_direction: both + register: nm_subject_reverse_to_both + ignore_errors: true + + - name: subject assertions + assert: + that: + - nm_subject_reverse_to_one_way is not changed + - nm_subject_reverse_to_one_way.msg == "Direction is not allowed, valid option is both." + - nm_subject_reverse_to_both is not changed + - nm_subject_reverse_to_both.msg == "Direction is not allowed, valid option is one-way." + + - name: subject both with qos and dscp + cisco.aci.aci_contract_subject: + <<: *aci_subject_both + priority: level1 + dscp: AF11 + register: nm_subject_both_qos_dscp + + - name: subject both with change to qos + cisco.aci.aci_contract_subject: + <<: *aci_subject_both + priority: unspecified + register: nm_subject_both_qos_change + + - name: subject both with change to dscp + cisco.aci.aci_contract_subject: + <<: *aci_subject_both + dscp: AF41 + register: nm_subject_both_dscp_change + + - name: subject one-way with qos and dscp + cisco.aci.aci_contract_subject: + <<: *aci_subject_one_way + priority_consumer_to_provider: level2 + dscp_consumer_to_provider: AF12 + priority_provider_to_consumer: level3 + dscp_provider_to_consumer: CS4 + register: nm_subject_one_way_qos_dscp + + - name: subject one-way with qos change + cisco.aci.aci_contract_subject: + <<: *aci_subject_one_way + priority_consumer_to_provider: unspecified + priority_provider_to_consumer: level1 + register: nm_subject_one_way_qos_change + + - name: subject one-way with dscp change + cisco.aci.aci_contract_subject: + <<: *aci_subject_one_way + dscp_consumer_to_provider: AF13 + dscp_provider_to_consumer: CS1 + register: nm_subject_one_way_dscp_change + + - name: subject assertions + assert: + that: + - nm_subject_both_qos_dscp is changed + - nm_subject_both_qos_dscp.current.0.vzSubj.attributes.prio == "level1" + - nm_subject_both_qos_dscp.current.0.vzSubj.attributes.targetDscp == "AF11" + - nm_subject_both_qos_change is changed + - nm_subject_both_qos_change.current.0.vzSubj.attributes.prio == "unspecified" + - nm_subject_both_qos_change.current.0.vzSubj.attributes.targetDscp == "AF11" + - nm_subject_both_dscp_change is changed + - nm_subject_both_dscp_change.current.0.vzSubj.attributes.prio == "unspecified" + - nm_subject_both_dscp_change.current.0.vzSubj.attributes.targetDscp == "AF41" + - nm_subject_one_way_qos_dscp is changed + - nm_subject_one_way_qos_dscp.current.0.vzSubj.children.0.vzOutTerm.attributes.prio == "level3" + - nm_subject_one_way_qos_dscp.current.0.vzSubj.children.0.vzOutTerm.attributes.targetDscp == "CS4" + - nm_subject_one_way_qos_dscp.current.0.vzSubj.children.1.vzInTerm.attributes.prio == "level2" + - nm_subject_one_way_qos_dscp.current.0.vzSubj.children.1.vzInTerm.attributes.targetDscp == "AF12" + - nm_subject_one_way_qos_change is changed + - nm_subject_one_way_qos_change.current.0.vzSubj.children.0.vzOutTerm.attributes.prio == "level1" + - nm_subject_one_way_qos_change.current.0.vzSubj.children.0.vzOutTerm.attributes.targetDscp == "CS4" + - nm_subject_one_way_qos_change.current.0.vzSubj.children.1.vzInTerm.attributes.prio == "unspecified" + - nm_subject_one_way_qos_change.current.0.vzSubj.children.1.vzInTerm.attributes.targetDscp == "AF12" + - nm_subject_one_way_dscp_change is changed + - nm_subject_one_way_dscp_change.current.0.vzSubj.children.0.vzOutTerm.attributes.prio == "level1" + - nm_subject_one_way_dscp_change.current.0.vzSubj.children.0.vzOutTerm.attributes.targetDscp == "CS1" + - nm_subject_one_way_dscp_change.current.0.vzSubj.children.1.vzInTerm.attributes.prio == "unspecified" + - nm_subject_one_way_dscp_change.current.0.vzSubj.children.1.vzInTerm.attributes.targetDscp == "AF13" + + always: + - 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_contract_subject_to_filter/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject_to_filter/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject_to_filter/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..f7e69e620 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject_to_filter/tasks/main.yml @@ -0,0 +1,379 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) + +# 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: 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: Assure tenant removal after tests + block: + - name: ensure tenant is deleted for clean state + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_test + state: absent + register: tenant_present + + - 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 filter exists for tests to kick off + cisco.aci.aci_filter: &aci_filter_present_2 + <<: *aci_tenant_present + filter: anstest2 + register: filter_present_2 + + - name: ensure contract exists for tests to kick off + cisco.aci.aci_contract: &aci_contract_present + <<: *aci_tenant_present + contract: anstest + register: contract_present + + - name: ensure subject exists for tests to kick off + cisco.aci.aci_contract_subject: &aci_subject_present + <<: *aci_contract_present + subject: anstest + register: subject_present + + - name: create subject filter binding - check mode works + cisco.aci.aci_contract_subject_to_filter: &aci_subject_filter_present + <<: *aci_subject_present + filter: anstest + log: log + check_mode: true + register: subject_filter_present_check_mode + + - name: create subject filter binding - creation works + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_filter_present + register: subject_filter_present + + - name: create subject filter binding - additional testing + cisco.aci.aci_contract_subject_to_filter: &aci_subject_filter_present_2 + <<: *aci_subject_filter_present + filter: anstest2 + register: subject_filter_present_2 + + - name: create subject filter binding - idempotency works + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_filter_present + register: subject_filter_present_idempotent + + - name: update subject filter binding - update works + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_filter_present + log: none + register: subject_filter_update + + - name: missing param - failure message works + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_tenant_present + ignore_errors: true + register: present_missing_param + + - name: present assertions + assert: + that: + - subject_filter_present_check_mode is changed + - subject_filter_present_check_mode.previous == [] + - subject_filter_present_check_mode.sent.vzRsSubjFiltAtt.attributes.directives == 'log' + - subject_filter_present_check_mode.sent.vzRsSubjFiltAtt.attributes.tnVzFilterName == 'anstest' + - subject_filter_present is changed + - subject_filter_present.previous == [] + - subject_filter_present.sent == subject_filter_present_check_mode.sent + - subject_filter_present.current.0.vzRsSubjFiltAtt.attributes.annotation == 'orchestrator:ansible' + - subject_filter_present_2 is changed + - subject_filter_present_idempotent is not changed + - subject_filter_present_idempotent.previous != [] + - subject_filter_update is changed + - subject_filter_update.sent.vzRsSubjFiltAtt.attributes.directives == '' + - present_missing_param is failed + - 'present_missing_param.msg == "state is present but all of the following are missing: contract, filter, subject"' + + - name: query all + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_tenant_present + state: query + tenant: "{{ fakevar | default(omit) }}" + register: query_all + + - name: query binding + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_filter_present + state: query + register: query_binding + + - name: query assertions + assert: + that: + - query_all is not changed + - query_all.current | length > 1 + - query_all.current.0.vzRsSubjFiltAtt is defined + - query_binding is not changed + - query_binding.current != [] + + - name: delete subject filter binding - check mode works + cisco.aci.aci_contract_subject_to_filter: &aci_subject_filter_absent + <<: *aci_subject_filter_present + state: absent + check_mode: true + register: subject_filter_absent_check_mode + + - name: delete subject filter binding - deletion works + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_filter_absent + register: subject_filter_absent + + - name: delete subject filter binding - idempotency works + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_filter_absent + register: subject_filter_absent_idempotent + + - name: missing param - failure message works + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_filter_absent + filter: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: absent_missing_param + + - name: cleanup subject filter binding + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_filter_present_2 + state: absent + + - name: absent assertions + assert: + that: + - subject_filter_absent_check_mode is changed + - subject_filter_absent_check_mode.proposed == {} + - subject_filter_absent_check_mode.previous != [] + - subject_filter_absent is changed + - subject_filter_absent.previous != [] + - subject_filter_absent_idempotent is not changed + - subject_filter_absent_idempotent.previous == [] + - absent_missing_param is failed + - 'absent_missing_param.msg == "state is absent but all of the following are missing: filter"' + + - name: create filter 1 + cisco.aci.aci_filter: + <<: *aci_tenant_present + filter: filter1 + + - name: create filter 2 + cisco.aci.aci_filter: + <<: *aci_tenant_present + filter: filter2 + + - name: create contract 1 + cisco.aci.aci_contract: &aci_contract1 + <<: *aci_tenant_present + contract: contract1 + + - name: create subject both + cisco.aci.aci_contract_subject: &aci_subject_both + <<: *aci_contract1 + subject: subjectboth + register: subject_both + + - name: create subject one-way + cisco.aci.aci_contract_subject: &aci_subject_one_way + <<: *aci_contract1 + subject: subjectoneway + apply_both_direction: one-way + register: nm_subject_present_one_way_again + + - name: create subject filter with direction both as default (check_mode) + cisco.aci.aci_contract_subject_to_filter: &aci_subject_both_to_filter + <<: *aci_subject_both + filter: filter1 + action: permit + directive: log + priority_override: level1 + state: present + check_mode: true + register: cm_filter1_present_default + + - name: apply subject filter1 with direction both as default + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_both_to_filter + register: nm_filter1_present_default + + - name: apply subject filter1 with direction provider to consumer (error) + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_both_to_filter + direction: provider_to_consumer + register: nm_filter1_present_p2c + ignore_errors: true + + - name: apply subject filter1 with direction consumer to provider (error) + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_both_to_filter + direction: consumer_to_provider + register: nm_filter1_present_c2p + ignore_errors: true + + - name: apply subject filter1 with direction both set + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_both_to_filter + filter: filter1 + direction: both + action: permit + directive: no_stats + priority_override: level2 + state: present + register: nm_filter1_present_both + + - name: apply subject filter2 with direction provider to consumer + cisco.aci.aci_contract_subject_to_filter: &aci_subject_one_way_to_filter + <<: *aci_contract1 + subject: subjectoneway + filter: filter2 + direction: provider_to_consumer + action: permit + directive: none + priority_override: level2 + state: present + register: nm_filter2_present_p2c + + - name: apply subject filter2 with direction consumer to provider + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_one_way_to_filter + direction: provider_to_consumer + register: nm_filter2_present_c2p + + - name: apply subject filter2 with direction both (error) + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_one_way_to_filter + direction: both + register: nm_filter2_present_both + ignore_errors: true + + - name: filter assertions + assert: + that: + - cm_filter1_present_default is changed + - nm_filter1_present_default is changed + - nm_filter1_present_default.current.0.vzRsSubjFiltAtt.attributes.action == "permit" + - nm_filter1_present_default.current.0.vzRsSubjFiltAtt.attributes.tnVzFilterName == "filter1" + - nm_filter1_present_default.current.0.vzRsSubjFiltAtt.attributes.priorityOverride == "level1" + - nm_filter1_present_default.current.0.vzRsSubjFiltAtt.attributes.directives == "log" + - nm_filter1_present_p2c is not changed + - nm_filter1_present_p2c.msg == "Direction is not allowed, valid option is both." + - nm_filter1_present_c2p is not changed + - nm_filter1_present_c2p.msg == "Direction is not allowed, valid option is both." + - nm_filter1_present_both is changed + - nm_filter1_present_both.current.0.vzRsSubjFiltAtt.attributes.action == "permit" + - nm_filter1_present_both.current.0.vzRsSubjFiltAtt.attributes.tnVzFilterName == "filter1" + - nm_filter1_present_both.current.0.vzRsSubjFiltAtt.attributes.priorityOverride == "level2" + - nm_filter1_present_both.current.0.vzRsSubjFiltAtt.attributes.directives == "no_stats" + - nm_filter2_present_p2c is changed + - nm_filter2_present_p2c.current.0.vzRsFiltAtt.attributes.action == "permit" + - nm_filter2_present_p2c.current.0.vzRsFiltAtt.attributes.tnVzFilterName == "filter2" + - nm_filter2_present_p2c.current.0.vzRsFiltAtt.attributes.priorityOverride == "level2" + - nm_filter2_present_p2c.current.0.vzRsFiltAtt.attributes.directives == "" + - nm_filter2_present_c2p is not changed + - nm_filter2_present_c2p.current.0.vzRsFiltAtt.attributes.action == "permit" + - nm_filter2_present_c2p.current.0.vzRsFiltAtt.attributes.tnVzFilterName == "filter2" + - nm_filter2_present_c2p.current.0.vzRsFiltAtt.attributes.priorityOverride == "level2" + - nm_filter2_present_c2p.current.0.vzRsFiltAtt.attributes.directives == "" + - nm_filter2_present_both.msg == "Direction is not allowed, valid option is consumer_to_provider or provider_to_consumer." + + - 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 subject filter with action deny for non-cloud + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_both_to_filter + direction: both + action: deny + register: filter_present_deny_non_cloud_both + + - name: create subject filter with action deny for non-cloud p2c + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_one_way_to_filter + direction: provider_to_consumer + action: deny + register: filter_present_deny_non_cloud_p2c + + - name: create subject filter with action deny for non-cloud p2c + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_one_way_to_filter + direction: consumer_to_provider + action: deny + register: filter_present_deny_non_cloud_c2p + + - name: filter subject with direction assertions + assert: + that: + - filter_present_deny_non_cloud_both is changed + - filter_present_deny_non_cloud_both.current.0.vzRsSubjFiltAtt.attributes.action == "deny" + - filter_present_deny_non_cloud_p2c is changed + - filter_present_deny_non_cloud_p2c.current.0.vzRsFiltAtt.attributes.action == "deny" + - filter_present_deny_non_cloud_c2p is changed + - filter_present_deny_non_cloud_c2p.current.0.vzRsFiltAtt.attributes.action == "deny" + + - name: Execute tasks only for cloud sites + when: query_cloud.current | length > 0 # This condition will execute only cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: create subject filter with action deny casues error for cloud (error) + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_both_to_filter + action: deny + register: filter_present_deny_cloud + ignore_errors: true + + - name: create subject filter with action deny for cloud p2c + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_one_way_to_filter + direction: provider_to_consumer + action: deny + register: filter_present_deny_cloud_p2c + ignore_errors: true + + - name: create subject filter with action deny for cloud p2c + cisco.aci.aci_contract_subject_to_filter: + <<: *aci_subject_one_way_to_filter + direction: provider_to_consumer + action: deny + register: filter_present_deny_cloud_c2p + ignore_errors: true + + - name: cloud assertions + assert: + that: + - filter_present_deny_cloud.msg.startswith("APIC Error 1: Invalid Configuration CLOUD_ONLY_PERMIT_ACTION_SUPPORTED") + - filter_present_deny_cloud_p2c.msg.startswith("APIC Error 1: Invalid Configuration CLOUD_ONLY_PERMIT_ACTION_SUPPORTED") + - filter_present_deny_cloud_c2p.msg.startswith("APIC Error 1: Invalid Configuration CLOUD_ONLY_PERMIT_ACTION_SUPPORTED") + + always: + - 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_contract_subject_to_service_graph/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject_to_service_graph/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject_to_service_graph/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject_to_service_graph/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject_to_service_graph/tasks/main.yml new file mode 100644 index 000000000..c9e41610f --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_contract_subject_to_service_graph/tasks/main.yml @@ -0,0 +1,159 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) + +# 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: 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: '{{ aci_output_level | default("info") }}' + tenant: ansible_test + state: present + register: tenant_present + +# CLEAN ENVIRONMENT +- name: ensure contract is removed + cisco.aci.aci_contract: + <<: *aci_tenant_present + contract: anstest + state: absent + ignore_errors: true + +- name: ensure contract exists for tests to kick off + cisco.aci.aci_contract: &aci_contract_present + <<: *aci_tenant_present + contract: anstest + register: contract_present + +- name: ensure subject exists for tests to kick off + cisco.aci.aci_contract_subject: &aci_subject_present + <<: *aci_contract_present + subject: anstest + register: subject_present + +- name: create subject service graph binding - check mode works + cisco.aci.aci_contract_subject_to_service_graph: &aci_subject_service_graph_present + <<: *aci_subject_present + service_graph: anstest + check_mode: true + register: subject_service_graph_present_check_mode + +- name: create subject service graph binding - creation works + cisco.aci.aci_contract_subject_to_service_graph: + <<: *aci_subject_service_graph_present + register: subject_service_graph_present + +- name: create subject service graph binding - idempotency works + cisco.aci.aci_contract_subject_to_service_graph: + <<: *aci_subject_service_graph_present + register: subject_service_graph_present_idempotent + +- name: update subject service graph binding - update works + cisco.aci.aci_contract_subject_to_service_graph: + <<: *aci_subject_service_graph_present + service_graph: anstest2 + register: subject_service_graph_update + +- name: missing param - failure message works + cisco.aci.aci_contract_subject_to_service_graph: + <<: *aci_tenant_present + ignore_errors: true + register: present_missing_param + +- name: present assertions + assert: + that: + - subject_service_graph_present_check_mode is changed + - subject_service_graph_present_check_mode.previous == [] + - subject_service_graph_present_check_mode.sent.vzRsSubjGraphAtt.attributes.tnVnsAbsGraphName == 'anstest' + - subject_service_graph_present is changed + - subject_service_graph_present.previous == [] + - subject_service_graph_present.sent == subject_service_graph_present_check_mode.sent + - subject_service_graph_present_idempotent is not changed + - subject_service_graph_present_idempotent.previous != [] + - subject_service_graph_present.current.0.vzRsSubjGraphAtt.attributes.annotation == 'orchestrator:ansible' + - subject_service_graph_update is changed + - subject_service_graph_update.sent.vzRsSubjGraphAtt.attributes.tnVnsAbsGraphName == 'anstest2' + - present_missing_param is failed + - 'present_missing_param.msg == "state is present but all of the following are missing: contract, service_graph, subject"' + +- name: query all + cisco.aci.aci_contract_subject_to_service_graph: + <<: *aci_tenant_present + state: query + tenant: "{{ fakevar | default(omit) }}" + register: query_all + +- name: query binding + cisco.aci.aci_contract_subject_to_service_graph: + <<: *aci_subject_service_graph_present + state: query + register: query_binding + +- name: query assertions + assert: + that: + - query_all is not changed + - query_all.current | length > 0 + - query_all.current.0.vzRsSubjGraphAtt is defined + - query_binding is not changed + - query_binding.current != [] + +- name: delete subject service graph binding - check mode works + cisco.aci.aci_contract_subject_to_service_graph: &aci_subject_service_graph_absent + <<: *aci_subject_service_graph_present + state: absent + check_mode: true + register: subject_service_graph_absent_check_mode + +- name: delete subject service graph binding - deletion works + cisco.aci.aci_contract_subject_to_service_graph: + <<: *aci_subject_service_graph_absent + register: subject_service_graph_absent + +- name: delete subject service graph binding - idempotency works + cisco.aci.aci_contract_subject_to_service_graph: + <<: *aci_subject_service_graph_absent + register: subject_service_graph_absent_idempotent + +- name: missing param - failure message works + cisco.aci.aci_contract_subject_to_service_graph: + <<: *aci_subject_service_graph_absent + service_graph: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: absent_missing_param + +- name: absent assertions + assert: + that: + - subject_service_graph_absent_check_mode is changed + - subject_service_graph_absent_check_mode.proposed == {} + - subject_service_graph_absent_check_mode.previous != [] + - subject_service_graph_absent is changed + - subject_service_graph_absent.previous != [] + - subject_service_graph_absent_idempotent is not changed + - subject_service_graph_absent_idempotent.previous == [] + - absent_missing_param is failed + - 'absent_missing_param.msg == "state is absent but all of the following are missing: service_graph"' + +- name: cleanup contract + cisco.aci.aci_contract: + <<: *aci_contract_present + state: absent + when: contract_present is changed + +- name: cleanup tenant + cisco.aci.aci_tenant: + <<: *aci_tenant_present + state: absent + when: tenant_present is changed
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_dhcp_relay/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_dhcp_relay/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_dhcp_relay/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..920a24969 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_dhcp_relay/tasks/main.yml @@ -0,0 +1,161 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Add a new tenant + aci_tenant: + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + +# CREATE DHCP RELAY +- name: Add a new DHCP relay policy + cisco.aci.aci_dhcp_relay: + <<: *aci_info + tenant: ansible_tenant + name: ansible_dhcp_relay + description: Ansible DHCP Relay + state: present + register: add_dhcp_relay + +- name: Verify DHCP Relay creation + assert: + that: + - add_dhcp_relay is changed + - add_dhcp_relay.current.0.dhcpRelayP.attributes.annotation == 'orchestrator:ansible' + - add_dhcp_relay.current.0.dhcpRelayP.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay" + - add_dhcp_relay.current.0.dhcpRelayP.attributes.name == "ansible_dhcp_relay" + - add_dhcp_relay.current.0.dhcpRelayP.attributes.owner == "tenant" + - add_dhcp_relay.current.0.dhcpRelayP.attributes.descr == "Ansible DHCP Relay" + +# CREATE DHCP RELAY AGAIN TO TEST IDEMPOTENCE +- name: Add DHCP relay policy again + cisco.aci.aci_dhcp_relay: + <<: *aci_info + tenant: ansible_tenant + name: ansible_dhcp_relay + description: Ansible DHCP Relay + state: present + register: add_dhcp_relay_again + +- name: Verify DHCP Relay idempotence + assert: + that: + - add_dhcp_relay_again is not changed + - add_dhcp_relay_again.current.0.dhcpRelayP.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay" + - add_dhcp_relay_again.current.0.dhcpRelayP.attributes.name == "ansible_dhcp_relay" + - add_dhcp_relay_again.current.0.dhcpRelayP.attributes.owner == "tenant" + - add_dhcp_relay_again.current.0.dhcpRelayP.attributes.descr == "Ansible DHCP Relay" + +# MODIFY DHCP RELAY +- name: Update DHCP relay policy + cisco.aci.aci_dhcp_relay: + <<: *aci_info + tenant: ansible_tenant + name: ansible_dhcp_relay + description: New Ansible DHCP Relay + state: present + register: update_dhcp_relay + +- name: Verify DHCP Relay change + assert: + that: + - update_dhcp_relay is changed + - update_dhcp_relay.current.0.dhcpRelayP.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay" + - update_dhcp_relay.current.0.dhcpRelayP.attributes.name == "ansible_dhcp_relay" + - update_dhcp_relay.current.0.dhcpRelayP.attributes.owner == "tenant" + - update_dhcp_relay.current.0.dhcpRelayP.attributes.descr == "New Ansible DHCP Relay" + +# QUERY DHCP RELAY +- name: Query DHCP relay policy + cisco.aci.aci_dhcp_relay: + <<: *aci_info + tenant: ansible_tenant + name: ansible_dhcp_relay + state: query + register: query_dhcp_relay + +- name: Verify DHCP Relay query + assert: + that: + - query_dhcp_relay is not changed + - query_dhcp_relay.current.0.dhcpRelayP.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay" + - query_dhcp_relay.current.0.dhcpRelayP.attributes.name == "ansible_dhcp_relay" + - query_dhcp_relay.current.0.dhcpRelayP.attributes.owner == "tenant" + - query_dhcp_relay.current.0.dhcpRelayP.attributes.descr == "New Ansible DHCP Relay" + +- name: Query all DHCP relays in ansible_tenant + cisco.aci.aci_dhcp_relay: + <<: *aci_info + tenant: ansible_tenant + state: query + register: query_dhcp_relay_all + +- name: Verify query idempotence + assert: + that: + - query_dhcp_relay_all is not changed + +# DELETE DHCP RELAY +- name: Delete DHCP relay policy + cisco.aci.aci_dhcp_relay: + <<: *aci_info + tenant: ansible_tenant + name: ansible_dhcp_relay + state: absent + register: delete_dhcp_relay + +- name: Verify DHCP Relay deletion + assert: + that: + - delete_dhcp_relay is changed + - delete_dhcp_relay.current == [] + - delete_dhcp_relay.previous.0.dhcpRelayP.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay" + - delete_dhcp_relay.previous.0.dhcpRelayP.attributes.name == "ansible_dhcp_relay" + - delete_dhcp_relay.previous.0.dhcpRelayP.attributes.owner == "tenant" + - delete_dhcp_relay.previous.0.dhcpRelayP.attributes.descr == "New Ansible DHCP Relay" + +- name: Delete DHCP relay policy again to test idempotence + cisco.aci.aci_dhcp_relay: + <<: *aci_info + tenant: ansible_tenant + name: ansible_dhcp_relay + state: absent + register: delete_dhcp_relay_again + +- name: Verify DHCP Relay deletion idempotence + assert: + that: + - delete_dhcp_relay_again is not changed + +# CLEAN ENVIRONMENT AGAIN +- 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_dhcp_relay_provider/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_dhcp_relay_provider/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_dhcp_relay_provider/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..2edc45e51 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_dhcp_relay_provider/tasks/main.yml @@ -0,0 +1,570 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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: debug + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Remove l2ext domain + cisco.aci.aci_domain: + <<: *aci_info + domain: ansible_l2dom + domain_type: l2dom + state: absent + +- name: Remove l3ext domain + cisco.aci.aci_domain: + <<: *aci_info + domain: ansible_l3dom + domain_type: l3dom + state: absent + +- 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 a new application profile + cisco.aci.aci_ap: + <<: *aci_info + tenant: ansible_tenant + ap: ansible_ap + description: Ansible AP + state: present + + - name: Add a new EPG + cisco.aci.aci_epg: + <<: *aci_info + tenant: ansible_tenant + ap: ansible_ap + epg: ansible_epg + description: Ansible EPG + state: present + + - name: Add another new EPG + cisco.aci.aci_epg: + <<: *aci_info + tenant: ansible_tenant + ap: ansible_ap + epg: ansible_epg_2 + description: Ansible EPG + state: present + + - name: Add a new BD + cisco.aci.aci_bd: + <<: *aci_info + tenant: ansible_tenant + bd: ansible_bd + state: present + + - name: Add l2ext domain + cisco.aci.aci_domain: + <<: *aci_info + domain: ansible_l2dom + domain_type: l2dom + state: present + + - name: Add a new l2out + cisco.aci.aci_l2out: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + domain: ansible_l2dom + bd: ansible_bd + vlan: 3200 + state: present + + - name: Add a new L2 external end point group + cisco.aci.aci_l2out_extepg: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + extepg: ansible_l2out_ext_net + state: present + + - name: Add a new l3ext domain + cisco.aci.aci_domain: + <<: *aci_info + domain: ansible_l3dom + domain_type: l3dom + state: present + + - name: Add a new VRF to a tenant + cisco.aci.aci_vrf: + <<: *aci_info + vrf: ansible_vrf + tenant: ansible_tenant + state: present + + - name: Add a new L3Out + cisco.aci.aci_l3out: + <<: *aci_info + tenant: ansible_tenant + name: ansible_l3out + domain: ansible_l3dom + vrf: ansible_vrf + route_control: + - export + state: present + + - name: Add a new ExtEpg + cisco.aci.aci_l3out_extepg: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + name: ansible_l3out_ext_net + state: present + + # CREATE DHCP RELAY + - name: Add a new DHCP relay policy + cisco.aci.aci_dhcp_relay: + <<: *aci_info + tenant: ansible_tenant + name: ansible_dhcp_relay + description: Ansible DHCP Relay + state: present + + # CREATE DHCP RELAY PROVIDERS + - name: Add a new DHCP relay App EPG provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: epg + anp: ansible_ap + app_epg: ansible_epg + dhcp_server_addr: 10.20.30.40 + state: present + register: add_epg_relay_provider + + - name: Add a new DHCP relay L2out provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: l2_external + l2out_name: ansible_l2out + external_net: ansible_l2out_ext_net + dhcp_server_addr: 10.20.30.41 + state: present + register: add_l2_relay_provider + + - name: Add a new DHCP relay L3out provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_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_l3_relay_provider + + - name: Add a new DHCP relay dn provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_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_dn_relay_provider + + - name: Confirm DHCP relay provider creation + assert: + that: + - add_epg_relay_provider is changed + - add_epg_relay_provider.current.0.dhcpRsProv.attributes.annotation == 'orchestrator:ansible' + - add_epg_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]" + - add_epg_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.40" + - add_epg_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg" + - add_l2_relay_provider is changed + - add_l2_relay_provider.current.0.dhcpRsProv.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay/rsprov-[uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net]" + - add_l2_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.41" + - add_l2_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net" + - add_l3_relay_provider is changed + - add_l3_relay_provider.current.0.dhcpRsProv.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay/rsprov-[uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net]" + - add_l3_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.42" + - add_l3_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net" + - add_dn_relay_provider is changed + - add_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]" + - add_dn_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.43" + - add_dn_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" + + # ADD DHCP RELAY PROVIDERS AGAIN TO TEST IDEMPOTENCE + - name: Add DHCP relay App EPG provider again + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: epg + anp: ansible_ap + app_epg: ansible_epg + dhcp_server_addr: 10.20.30.40 + state: present + register: add_epg_relay_provider_again + + - name: Add DHCP relay L2out provider again + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: l2_external + l2out_name: ansible_l2out + external_net: ansible_l2out_ext_net + dhcp_server_addr: 10.20.30.41 + state: present + register: add_l2_relay_provider_again + + - name: Add DHCP relay L3out provider again + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_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_l3_relay_provider_again + + - name: Add a new DHCP relay dn provider again + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_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_dn_relay_provider_again + + - name: Confirm DHCP relay provider idempotence + assert: + that: + - add_epg_relay_provider_again is not changed + - add_epg_relay_provider_again.current.0.dhcpRsProv.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay/rsprov-[uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg]" + - add_epg_relay_provider_again.current.0.dhcpRsProv.attributes.addr == "10.20.30.40" + - add_epg_relay_provider_again.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg" + - add_l2_relay_provider_again is not changed + - add_l2_relay_provider_again.current.0.dhcpRsProv.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay/rsprov-[uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net]" + - add_l2_relay_provider_again.current.0.dhcpRsProv.attributes.addr == "10.20.30.41" + - add_l2_relay_provider_again.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net" + - add_l3_relay_provider_again is not changed + - add_l3_relay_provider_again.current.0.dhcpRsProv.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay/rsprov-[uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net]" + - add_l3_relay_provider_again.current.0.dhcpRsProv.attributes.addr == "10.20.30.42" + - add_l3_relay_provider_again.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net" + - add_dn_relay_provider_again is not changed + - add_dn_relay_provider_again.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]" + - add_dn_relay_provider_again.current.0.dhcpRsProv.attributes.addr == "10.20.30.43" + - add_dn_relay_provider_again.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" + + # MODIFY DHCP RELAY PROVIDERS + - name: Update DHCP relay App EPG provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: epg + anp: ansible_ap + app_epg: ansible_epg + dhcp_server_addr: 10.20.30.50 + state: present + register: update_epg_relay_provider + + - name: Update DHCP relay L2out provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: l2_external + l2out_name: ansible_l2out + external_net: ansible_l2out_ext_net + dhcp_server_addr: 10.20.30.51 + state: present + register: update_l2_relay_provider + + - name: Update DHCP relay L3out provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_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.52 + state: present + register: update_l3_relay_provider + + - name: Update DHCP relay dn provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: dn + dn: "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" + dhcp_server_addr: 10.20.30.53 + state: present + register: update_dn_relay_provider + + - name: Confirm DHCP relay provider update + assert: + that: + - update_epg_relay_provider is changed + - update_epg_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]" + - update_epg_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.50" + - update_epg_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg" + - update_l2_relay_provider is changed + - update_l2_relay_provider.current.0.dhcpRsProv.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay/rsprov-[uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net]" + - update_l2_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.51" + - update_l2_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net" + - update_l3_relay_provider is changed + - update_l3_relay_provider.current.0.dhcpRsProv.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay/rsprov-[uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net]" + - update_l3_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.52" + - update_l3_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net" + - update_dn_relay_provider is changed + - update_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]" + - 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: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: epg + anp: ansible_ap + app_epg: ansible_epg + state: query + register: query_epg_relay_provider + + - name: Query DHCP relay L2out provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: l2_external + l2out_name: ansible_l2out + external_net: ansible_l2out_ext_net + state: query + register: query_l2_relay_provider + + - name: Query DHCP relay L3out provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: l3_external + l3out_name: ansible_l3out + external_net: ansible_l3out_ext_net + state: query + register: query_l3_relay_provider + + - name: Query DHCP relay dn provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: dn + dn: "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" + state: query + register: query_dn_relay_provider + + - name: Confirm DHCP relay provider query + assert: + that: + - query_epg_relay_provider is not changed + - query_epg_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]" + - query_epg_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.50" + - query_epg_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg" + - query_l2_relay_provider is not changed + - query_l2_relay_provider.current.0.dhcpRsProv.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay/rsprov-[uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net]" + - query_l2_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.51" + - query_l2_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net" + - query_l3_relay_provider is not changed + - query_l3_relay_provider.current.0.dhcpRsProv.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay/rsprov-[uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net]" + - query_l3_relay_provider.current.0.dhcpRsProv.attributes.addr == "10.20.30.52" + - query_l3_relay_provider.current.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net" + - query_dn_relay_provider is not changed + - 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" + + # DELETE DHCP RELAY PROVIDERS + - name: Delete DHCP relay App EPG provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: epg + anp: ansible_ap + app_epg: ansible_epg + state: absent + register: delete_epg_relay_provider + + - name: Delete DHCP relay L2out provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: l2_external + l2out_name: ansible_l2out + external_net: ansible_l2out_ext_net + state: absent + register: delete_l2_relay_provider + + - name: Delete DHCP relay L3out provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: l3_external + provider_tenant: ansible_tenant + l3out_name: ansible_l3out + external_net: ansible_l3out_ext_net + state: absent + register: delete_l3_relay_provider + + - name: Delete DHCP relay dn provider + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: dn + dn: "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" + state: absent + register: delete_dn_relay_provider + + + - name: Confirm DHCP relay provider removal + assert: + that: + - delete_epg_relay_provider is changed + - delete_epg_relay_provider.current == [] + - delete_epg_relay_provider.previous.0.dhcpRsProv.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay/rsprov-[uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg]" + - delete_epg_relay_provider.previous.0.dhcpRsProv.attributes.addr == "10.20.30.50" + - delete_epg_relay_provider.previous.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg" + - delete_l2_relay_provider is changed + - delete_l2_relay_provider.current == [] + - delete_l2_relay_provider.previous.0.dhcpRsProv.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay/rsprov-[uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net]" + - delete_l2_relay_provider.previous.0.dhcpRsProv.attributes.addr == "10.20.30.51" + - delete_l2_relay_provider.previous.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_l2out_ext_net" + - delete_l3_relay_provider is changed + - delete_l3_relay_provider.current == [] + - delete_l3_relay_provider.previous.0.dhcpRsProv.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay/rsprov-[uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net]" + - delete_l3_relay_provider.previous.0.dhcpRsProv.attributes.addr == "10.20.30.52" + - delete_l3_relay_provider.previous.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_l3out_ext_net" + - delete_dn_relay_provider is changed + - delete_dn_relay_provider.previous.0.dhcpRsProv.attributes.dn == "uni/tn-ansible_tenant/relayp-ansible_dhcp_relay/rsprov-[uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2]" + - delete_dn_relay_provider.previous.0.dhcpRsProv.attributes.addr == "10.20.30.53" + - delete_dn_relay_provider.previous.0.dhcpRsProv.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" + + # DELETE DHCP RELAY PROVIDERS AGAIN TO TEST IDEMPOTENCE + - name: Delete DHCP relay App EPG provider again + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: epg + anp: ansible_ap + app_epg: ansible_epg + state: absent + register: delete_epg_relay_provider_again + + - name: Delete DHCP relay L2out provider again + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: l2_external + l2out_name: ansible_l2out + external_net: ansible_l2out_ext_net + state: absent + register: delete_l2_relay_provider_again + + - name: Delete DHCP relay L3out provider again + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: l3_external + provider_tenant: ansible_tenant + l3out_name: ansible_l3out + external_net: ansible_l3out_ext_net + state: absent + register: delete_l3_relay_provider_again + + - name: Delete DHCP relay dn provider again + cisco.aci.aci_dhcp_relay_provider: + <<: *aci_info + tenant: ansible_tenant + relay_policy: ansible_dhcp_relay + epg_type: dn + dn: "uni/tn-ansible_tenant/ap-ansible_ap/epg-ansible_epg_2" + state: absent + register: delete_dn_relay_provider_again + + - name: Confirm DHCP relay provider removal + assert: + that: + - delete_epg_relay_provider_again is not changed + - delete_l2_relay_provider_again is not changed + - delete_l3_relay_provider_again is not changed + - delete_dn_relay_provider_again is not changed + + # CLEAN ENVIRONMENT AGAIN + - name: Remove the ansible_tenant + aci_tenant: + <<: *aci_info + tenant: ansible_tenant + state: absent + + - name: Remove l2ext domain + cisco.aci.aci_domain: + <<: *aci_info + domain: ansible_l2dom + domain_type: l2dom + state: absent + + - name: Remove l3ext domain + cisco.aci.aci_domain: + <<: *aci_info + domain: ansible_l3dom + domain_type: l3dom + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_domain/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_domain/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_domain/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..2d3de4dd0 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_domain/tasks/main.yml @@ -0,0 +1,169 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove DNS profile if it already exists + cisco.aci.aci_dns_profile: + <<: *aci_info + profile_name: ansible_dns_profile + state: absent + delegate_to: localhost + +# ADD DNS PROFILE +- name: Add DNS profile + cisco.aci.aci_dns_profile: + <<: *aci_info + profile_name: ansible_dns_profile + state: present + delegate_to: localhost + +# ADD DNS DOMAIN +- name: Add a new DNS domain + cisco.aci.aci_dns_domain: + <<: *aci_info + dns_profile: ansible_dns_profile + domain: example.com + default: false + state: present + delegate_to: localhost + register: add_dns_domain + +- name: Verify DNS domain creation + assert: + that: + - add_dns_domain is changed + - add_dns_domain.current.0.dnsDomain.attributes.annotation == 'orchestrator:ansible' + - add_dns_domain.current.0.dnsDomain.attributes.dn == "uni/fabric/dnsp-ansible_dns_profile/dom-example.com" + - add_dns_domain.current.0.dnsDomain.attributes.name == "example.com" + - add_dns_domain.current.0.dnsDomain.attributes.isDefault == "no" + +# ADD DNS DOMAIN AGAIN TO TEST IDEMPOTENCE +- name: Add DNS domain again + cisco.aci.aci_dns_domain: + <<: *aci_info + dns_profile: ansible_dns_profile + domain: example.com + default: false + state: present + delegate_to: localhost + register: add_dns_domain_again + +- name: Verify DNS domain creation idempotence + assert: + that: + - add_dns_domain_again is not changed + - add_dns_domain_again.current.0.dnsDomain.attributes.dn == "uni/fabric/dnsp-ansible_dns_profile/dom-example.com" + - add_dns_domain_again.current.0.dnsDomain.attributes.name == "example.com" + - add_dns_domain_again.current.0.dnsDomain.attributes.isDefault == "no" + +# MODIFY DNS DOMAIN +- name: Update DNS domain + cisco.aci.aci_dns_domain: + <<: *aci_info + dns_profile: ansible_dns_profile + domain: example.com + default: true + state: present + delegate_to: localhost + register: update_dns_domain + +- name: Verify DNS domain update + assert: + that: + - update_dns_domain is changed + - update_dns_domain.current.0.dnsDomain.attributes.dn == "uni/fabric/dnsp-ansible_dns_profile/dom-example.com" + - update_dns_domain.current.0.dnsDomain.attributes.name == "example.com" + - update_dns_domain.current.0.dnsDomain.attributes.isDefault == "yes" + +# QUERY DNS DOMAIN +- name: Query DNS domain + cisco.aci.aci_dns_domain: + <<: *aci_info + dns_profile: ansible_dns_profile + domain: example.com + state: query + delegate_to: localhost + register: query_dns_domain + +- name: Verify DNS domain attributes + assert: + that: + - query_dns_domain is not changed + - query_dns_domain.current.0.dnsDomain.attributes.dn == "uni/fabric/dnsp-ansible_dns_profile/dom-example.com" + - query_dns_domain.current.0.dnsDomain.attributes.name == "example.com" + - query_dns_domain.current.0.dnsDomain.attributes.isDefault == "yes" + +# QUERY ALL DNS DOMAINS WITHIN THE PROFILE +- name: Query all DNS domains within the profile + cisco.aci.aci_dns_domain: + <<: *aci_info + dns_profile: ansible_dns_profile + state: query + delegate_to: localhost + register: query_dns_domain_all + +- name: Verify DNS domain query idempotence + assert: + that: + - query_dns_domain_all is not changed + +# DELETE DNS DOMAIN +- name: Remove DNS Domain + cisco.aci.aci_dns_domain: + <<: *aci_info + dns_profile: ansible_dns_profile + domain: example.com + state: absent + delegate_to: localhost + register: delete_dns_domain + +- name: Verify DNS domain deletion + assert: + that: + - delete_dns_domain is changed + - delete_dns_domain.current == [] + - delete_dns_domain.previous.0.dnsDomain.attributes.dn == "uni/fabric/dnsp-ansible_dns_profile/dom-example.com" + - delete_dns_domain.previous.0.dnsDomain.attributes.name == "example.com" + - delete_dns_domain.previous.0.dnsDomain.attributes.isDefault == "yes" + +# DELETE DNS DOMAIN AGAIN TO TEST IDEMPOTENCE +- name: Remove DNS Domain + cisco.aci.aci_dns_domain: + <<: *aci_info + dns_profile: ansible_dns_profile + domain: example.com + state: absent + delegate_to: localhost + register: delete_dns_domain_again + +- name: Verify DNS domain deletion idempotence + assert: + that: + - delete_dns_domain_again is not changed + +# CLEAN ENVIRONMENT +- name: Remove DNS profile if it already exists + cisco.aci.aci_dns_profile: + <<: *aci_info + profile_name: ansible_dns_profile + state: absent + delegate_to: localhost diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_profile/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_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_dns_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_profile/tasks/main.yml new file mode 100644 index 000000000..126bb27a6 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_profile/tasks/main.yml @@ -0,0 +1,107 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# ADD DNS PROFILE +- name: Add DNS profile + cisco.aci.aci_dns_profile: + <<: *aci_info + profile_name: ansible_dns_profile + state: present + register: add_dns_profile + +- name: Verify that DNS profile has been created with correct attributes + assert: + that: + - add_dns_profile is changed + - add_dns_profile.current.0.dnsProfile.attributes.annotation == 'orchestrator:ansible' + - add_dns_profile.current.0.dnsProfile.attributes.dn == "uni/fabric/dnsp-ansible_dns_profile" + - add_dns_profile.current.0.dnsProfile.attributes.name == "ansible_dns_profile" + +# ADD DNS PROFILE AGAIN TO TEST IDEMPOTENCE +- name: Add DNS profile again + cisco.aci.aci_dns_profile: + <<: *aci_info + profile_name: ansible_dns_profile + state: present + register: add_dns_profile_again + +- name: Verify that DNS profile creation idempotence + assert: + that: + - add_dns_profile_again is not changed + - add_dns_profile_again.current.0.dnsProfile.attributes.dn == "uni/fabric/dnsp-ansible_dns_profile" + - add_dns_profile_again.current.0.dnsProfile.attributes.name == "ansible_dns_profile" + +# QUERY DNS PROFILE +- name: Query the DNS profile + cisco.aci.aci_dns_profile: + <<: *aci_info + profile_name: ansible_dns_profile + state: query + register: query_dns_profile + +- name: Verify DNS profile + assert: + that: + - query_dns_profile is not changed + - query_dns_profile.current.0.dnsProfile.attributes.dn == "uni/fabric/dnsp-ansible_dns_profile" + - query_dns_profile.current.0.dnsProfile.attributes.name == "ansible_dns_profile" + +- name: Query all DNS profiles + cisco.aci.aci_dns_profile: + <<: *aci_info + state: query + register: query_dns_profile_all + +- name: Verify query idempotence + assert: + that: + - query_dns_profile_all is not changed + +# DELETE DNS PROFILE +- name: Remove the DNS profile + cisco.aci.aci_dns_profile: + <<: *aci_info + name: ansible_dns_profile + state: absent + register: remove_dns_profile + +- name: Verify DNS profile removal + assert: + that: + - remove_dns_profile is changed + - remove_dns_profile.current == [] + - remove_dns_profile.previous.0.dnsProfile.attributes.dn == "uni/fabric/dnsp-ansible_dns_profile" + - remove_dns_profile.previous.0.dnsProfile.attributes.name == "ansible_dns_profile" + +# DELETE DNS PROFILE AGAIN TO TEST IDEMPOTENCE +- name: Remove the DNS profile again + cisco.aci.aci_dns_profile: + <<: *aci_info + name: ansible_dns_profile + state: absent + register: remove_dns_profile_again + +- name: Verify DNS profile removal idempotence + assert: + that: + - remove_dns_profile_again is not changed diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_provider/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_provider/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_provider/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..8deca651c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_dns_provider/tasks/main.yml @@ -0,0 +1,169 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove DNS profile if it already exists + cisco.aci.aci_dns_profile: + <<: *aci_info + profile_name: ansible_dns_profile + state: absent + delegate_to: localhost + +# ADD DNS PROFILE +- name: Add DNS profile + cisco.aci.aci_dns_profile: + <<: *aci_info + profile_name: ansible_dns_profile + state: present + delegate_to: localhost + +# ADD DNS PROVIDER +- name: Add a new DNS provider + cisco.aci.aci_dns_provider: + <<: *aci_info + dns_profile: ansible_dns_profile + addr: 10.20.30.40 + preferred: false + state: present + delegate_to: localhost + register: add_dns_provider + +- name: Verify DNS provider creation + assert: + that: + - add_dns_provider is changed + - add_dns_provider.current.0.dnsProv.attributes.annotation == 'orchestrator:ansible' + - add_dns_provider.current.0.dnsProv.attributes.dn == "uni/fabric/dnsp-ansible_dns_profile/prov-[10.20.30.40]" + - add_dns_provider.current.0.dnsProv.attributes.addr == "10.20.30.40" + - add_dns_provider.current.0.dnsProv.attributes.preferred == "no" + +# ADD DNS PROVIDER AGAIN TO TEST IDEMPOTENCE +- name: Add a new DNS provider again + cisco.aci.aci_dns_provider: + <<: *aci_info + dns_profile: ansible_dns_profile + addr: 10.20.30.40 + preferred: false + state: present + delegate_to: localhost + register: add_dns_provider_again + +- name: Verify DNS provider creation idempotence + assert: + that: + - add_dns_provider_again is not changed + - add_dns_provider_again.current.0.dnsProv.attributes.dn == "uni/fabric/dnsp-ansible_dns_profile/prov-[10.20.30.40]" + - add_dns_provider_again.current.0.dnsProv.attributes.addr == "10.20.30.40" + - add_dns_provider_again.current.0.dnsProv.attributes.preferred == "no" + +# MODIFY DNS PROVIDER +- name: Update DNS provider + cisco.aci.aci_dns_provider: + <<: *aci_info + dns_profile: ansible_dns_profile + addr: 10.20.30.40 + preferred: true + state: present + delegate_to: localhost + register: update_dns_provider + +- name: Verify DNS provider update + assert: + that: + - update_dns_provider is changed + - update_dns_provider.current.0.dnsProv.attributes.dn == "uni/fabric/dnsp-ansible_dns_profile/prov-[10.20.30.40]" + - update_dns_provider.current.0.dnsProv.attributes.addr == "10.20.30.40" + - update_dns_provider.current.0.dnsProv.attributes.preferred == "yes" + +# QUERY DNS PROVIDER +- name: Query DNS provider + cisco.aci.aci_dns_provider: + <<: *aci_info + dns_profile: ansible_dns_profile + addr: 10.20.30.40 + state: query + delegate_to: localhost + register: query_dns_provider + +- name: Verify DNS provider attributes + assert: + that: + - query_dns_provider is not changed + - query_dns_provider.current.0.dnsProv.attributes.dn == "uni/fabric/dnsp-ansible_dns_profile/prov-[10.20.30.40]" + - query_dns_provider.current.0.dnsProv.attributes.addr == "10.20.30.40" + - query_dns_provider.current.0.dnsProv.attributes.preferred == "yes" + +# QUERY ALL DNS PROVIDERS WITHIN THE PROFILE +- name: Query all DNS providers within profile + cisco.aci.aci_dns_provider: + <<: *aci_info + dns_profile: ansible_dns_profile + state: query + delegate_to: localhost + register: query_dns_provider_all + +- name: Verify DNS provider query idempotence + assert: + that: + - query_dns_provider_all is not changed + +# DELETE DNS PROVIDER +- name: Delete DNS provider + cisco.aci.aci_dns_provider: + <<: *aci_info + dns_profile: ansible_dns_profile + addr: 10.20.30.40 + state: absent + delegate_to: localhost + register: delete_dns_provider + +- name: Verify DNS provider deletion + assert: + that: + - delete_dns_provider is changed + - delete_dns_provider.current == [] + - delete_dns_provider.previous.0.dnsProv.attributes.dn == "uni/fabric/dnsp-ansible_dns_profile/prov-[10.20.30.40]" + - delete_dns_provider.previous.0.dnsProv.attributes.addr == "10.20.30.40" + - delete_dns_provider.previous.0.dnsProv.attributes.preferred == "yes" + +# DELETE DNS PROVIDER AGAIN TO TEST IDEMPOTENCE +- name: Delete DNS provider again + cisco.aci.aci_dns_provider: + <<: *aci_info + 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 + assert: + that: + - delete_dns_provider_again is not changed + +# CLEAN ENVIRONMENT +- name: Remove DNS profile if it already exists + cisco.aci.aci_dns_profile: + <<: *aci_info + profile_name: ansible_dns_profile + state: absent + delegate_to: localhost diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/fc.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/fc.yml new file mode 100644 index 000000000..2e2a8eb0b --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/fc.yml @@ -0,0 +1,299 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + + +# CLEAN ENVIRONMENT +- name: Remove FC domain + cisco.aci.aci_domain: &domain_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") }}' + domain: fc_dom + domain_type: fc + state: absent + + +# ADD DOMAIN +- name: Add FC domain (check_mode) + cisco.aci.aci_domain: &domain_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") }}' + domain: fc_dom + domain_type: fc + state: present + check_mode: true + register: cm_add_domain + +- name: Add FC domain (normal mode) + cisco.aci.aci_domain: *domain_present + register: nm_add_domain + +- name: Verify FC add_domain + assert: + that: + - cm_add_domain is changed + - nm_add_domain is changed + - cm_add_domain.sent.fcDomP.attributes.name == nm_add_domain.sent.fcDomP.attributes.name == 'fc_dom' + - cm_add_domain.proposed.fcDomP.attributes.name == nm_add_domain.proposed.fcDomP.attributes.name == 'fc_dom' + - cm_add_domain.current == cm_add_domain.previous == nm_add_domain.previous == [] + - nm_add_domain.current.0.fcDomP.attributes.annotation == 'orchestrator:ansible' + - nm_add_domain.current.0.fcDomP.attributes.name == 'fc_dom' + - nm_add_domain.current.0.fcDomP.attributes.dn == 'uni/fc-fc_dom' + +- name: Add FC domain again (check_mode) + cisco.aci.aci_domain: *domain_present + check_mode: true + register: cm_add_domain_again + +- name: Add FC domain again (normal mode) + cisco.aci.aci_domain: *domain_present + register: nm_add_domain_again + +- name: Verify FC add_domain_again + assert: + that: + - cm_add_domain_again is not changed + - nm_add_domain_again is not changed + +- name: Update FC domain with incorrect parameter vm_provider (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + vm_provider: vmware + check_mode: true + ignore_errors: true + register: cm_incorrect_vm_provider + +- name: Update FC domain with incorrect parameter vm_provider (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + vm_provider: vmware + ignore_errors: true + register: nm_incorrect_vm_provider + +- name: Update FC domain with incorrect parameter encap_mode (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + encap_mode: vlan + check_mode: true + ignore_errors: true + register: cm_incorrect_encap_mode + +- name: Update FC domain with incorrect parameter encap_mode (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + encap_mode: vlan + ignore_errors: true + register: nm_incorrect_encap_mode + +- name: Update FC domain with incorrect parameter multicast_address (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + multicast_address: 10.10.10.0 + check_mode: true + ignore_errors: true + register: cm_incorrect_multicast_address + +- name: Update FC domain with incorrect parameter multicast_address (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + multicast_address: 10.10.10.0 + ignore_errors: true + register: nm_incorrect_multicast_address + +- name: Update FC domain with incorrect parameter vswitch (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + vswitch: avs + check_mode: true + ignore_errors: true + register: cm_incorrect_vswitch + +- name: Update FC domain with incorrect parameter vswitch (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + vswitch: avs + ignore_errors: true + register: nm_incorrect_vswitch + +- name: Update FC domain with incorrect parameter dscp (check mode) + cisco.aci.aci_domain: + <<: *domain_present + dscp: unspecified + check_mode: true + ignore_errors: true + register: cm_incorrect_dscp + +- name: Update FC domain with incorrect parameter dscp (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + dscp: unspecified + ignore_errors: true + register: nm_incorrect_dscp + +- name: Update FC domain with incorrect parameter access_mode (check mode) + cisco.aci.aci_domain: + <<: *domain_present + access_mode: read-write + check_mode: true + ignore_errors: true + register: cm_incorrect_access_mode + +- name: Update FC domain with incorrect parameter access_mode (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + access_mode: read-write + ignore_errors: true + register: nm_incorrect_access_mode + +- name: Update FC domain with incorrect parameter enable_vm_folder (check mode) + cisco.aci.aci_domain: + <<: *domain_present + enable_vm_folder: true + check_mode: true + ignore_errors: true + register: cm_incorrect_enable_vm_folder + +- name: Update FC domain with incorrect parameter enable_vm_folder (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + enable_vm_folder: true + ignore_errors: true + register: nm_incorrect_enable_vm_folder + +- name: Verify incorrect parameter + assert: + that: + - cm_incorrect_vm_provider.msg == "Domain type 'fc' cannot have parameter 'vm_provider'" + - nm_incorrect_vm_provider.msg == "Domain type 'fc' cannot have parameter 'vm_provider'" + - cm_incorrect_encap_mode.msg == "Domain type 'fc' cannot have parameter 'encap_mode'" + - nm_incorrect_encap_mode.msg == "Domain type 'fc' cannot have parameter 'encap_mode'" + - cm_incorrect_multicast_address.msg == "Domain type 'fc' cannot have parameter 'multicast_address'" + - nm_incorrect_multicast_address.msg == "Domain type 'fc' cannot have parameter 'multicast_address'" + - cm_incorrect_vswitch.msg == "Domain type 'fc' cannot have parameter 'vswitch'" + - nm_incorrect_vswitch.msg == "Domain type 'fc' cannot have parameter 'vswitch'" + - cm_incorrect_dscp.msg == "DSCP values can only be assigned to 'l2ext and 'l3ext' domains" + - nm_incorrect_dscp.msg == "DSCP values can only be assigned to 'l2ext and 'l3ext' domains" + - cm_incorrect_access_mode.msg == "Domain type 'fc' cannot have parameter 'access_mode'" + - nm_incorrect_access_mode.msg == "Domain type 'fc' cannot have parameter 'access_mode'" + - cm_incorrect_enable_vm_folder.msg == "Domain type 'fc' cannot have parameter 'enable_vm_folder'" + - nm_incorrect_enable_vm_folder.msg == "Domain type 'fc' cannot have parameter 'enable_vm_folder'" + +# QUERY ALL DOMAINS +- name: Query all FC domains (check_mode) + cisco.aci.aci_domain: &domain_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") }}' + domain_type: fc + state: query + check_mode: true + register: cm_query_all_domains + +- name: Query all FC domains (normal mode) + cisco.aci.aci_domain: *domain_query + register: nm_query_all_domains + +- name: Verify FC query_all_domains + assert: + that: + - cm_query_all_domains is not changed + - nm_query_all_domains is not changed + - cm_query_all_domains == nm_query_all_domains + - nm_query_all_domains.current|length >= 1 + + +# QUERY A DOMAIN +- name: Query our FC domain (check_mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: fc_dom + check_mode: true + register: cm_query_domain + +- name: Query our FC domain (normal mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: fc_dom + register: nm_query_domain + +- name: Verify FC query_domain + assert: + that: + - cm_query_domain is not changed + - nm_query_domain is not changed + - cm_query_domain == nm_query_domain + - nm_query_domain.current.0.fcDomP.attributes.dn == 'uni/fc-fc_dom' + - nm_query_domain.current.0.fcDomP.attributes.name == 'fc_dom' + + +# REMOVE DOMAIN +- name: Remove FC domain (check_mode) + cisco.aci.aci_domain: *domain_absent + check_mode: true + register: cm_remove_domain + +- name: Remove FC domain (normal mode) + cisco.aci.aci_domain: *domain_absent + register: nm_remove_domain + +- name: Verify FC remove_domain + assert: + that: + - cm_remove_domain is changed + - nm_remove_domain is changed + - cm_remove_domain.current.0.fcDomP.attributes.name == cm_remove_domain.previous.0.fcDomP.attributes.name == nm_remove_domain.previous.0.fcDomP.attributes.name == 'fc_dom' + - cm_remove_domain.current.0.fcDomP.attributes.dn == cm_remove_domain.previous.0.fcDomP.attributes.dn == nm_remove_domain.previous.0.fcDomP.attributes.dn == 'uni/fc-fc_dom' + - nm_remove_domain.current == [] + +- name: Remove FC domain again (check_mode) + cisco.aci.aci_domain: *domain_absent + check_mode: true + register: cm_remove_domain_again + +- name: Remove FC domain again (normal mode) + cisco.aci.aci_domain: *domain_absent + register: nm_remove_domain_again + +- name: Verify FC remove_domain_again + assert: + that: + - cm_remove_domain_again is not changed + - nm_remove_domain_again is not changed + + +# QUERY NON-EXISTING DOMAIN +- name: Query non-existing FC domain (check_mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: fc_dom + check_mode: true + register: cm_query_non_domain + +- name: Query non-existing FC domain (normal mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: fc_dom + register: nm_query_non_domain + +- name: Verify FC query_non_domain + assert: + that: + - cm_query_non_domain is not changed + - nm_query_non_domain is not changed + - cm_query_non_domain == nm_query_non_domain + - nm_query_non_domain.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/l2dom.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/l2dom.yml new file mode 100644 index 000000000..4f0084174 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/l2dom.yml @@ -0,0 +1,248 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + + +# CLEAN ENVIRONMENT +- name: Remove L2 domain + cisco.aci.aci_domain: &domain_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") }}' + domain: l2_dom + domain_type: l2dom + state: absent + + +# ADD DOMAIN +- name: Add L2 domain (check_mode) + cisco.aci.aci_domain: &domain_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") }}' + domain: l2_dom + domain_type: l2dom + state: present + check_mode: true + register: cm_add_domain + +- name: Add L2 domain (normal mode) + cisco.aci.aci_domain: *domain_present + register: nm_add_domain + +- name: Verify L2 add_domain + assert: + that: + - cm_add_domain is changed + - nm_add_domain is changed + - cm_add_domain.sent.l2extDomP.attributes.name == nm_add_domain.sent.l2extDomP.attributes.name == 'l2_dom' + - cm_add_domain.proposed.l2extDomP.attributes.name == nm_add_domain.proposed.l2extDomP.attributes.name == 'l2_dom' + - cm_add_domain.current == cm_add_domain.previous == nm_add_domain.previous == [] + - nm_add_domain.current.0.l2extDomP.attributes.annotation == 'orchestrator:ansible' + - nm_add_domain.current.0.l2extDomP.attributes.name == 'l2_dom' + - nm_add_domain.current.0.l2extDomP.attributes.dn == 'uni/l2dom-l2_dom' + +- name: Add L2 domain again (check_mode) + cisco.aci.aci_domain: *domain_present + check_mode: true + register: cm_add_domain_again + +- name: Add L2 domain again (normal mode) + cisco.aci.aci_domain: *domain_present + register: nm_add_domain_again + +- name: Verify L2 add_domain_again + assert: + that: + - cm_add_domain_again is not changed + - nm_add_domain_again is not changed + +- name: Update L2 domain with incorrect parameter vm_provider (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + vm_provider: vmware + check_mode: true + ignore_errors: true + register: cm_incorrect_vm_provider + +- name: Update L2 domain with incorrect parameter vm_provider (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + vm_provider: vmware + ignore_errors: true + register: nm_incorrect_vm_provider + +- name: Update L2 domain with incorrect parameter encap_mode (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + encap_mode: vlan + check_mode: true + ignore_errors: true + register: cm_incorrect_encap_mode + +- name: Update L2 domain with incorrect parameter encap_mode (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + encap_mode: vlan + ignore_errors: true + register: nm_incorrect_encap_mode + +- name: Update L2 domain with incorrect parameter multicast_address (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + multicast_address: 10.10.10.0 + check_mode: true + ignore_errors: true + register: cm_incorrect_multicast_address + +- name: Update L2 domain with incorrect parameter multicast_address (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + multicast_address: 10.10.10.0 + ignore_errors: true + register: nm_incorrect_multicast_address + +- name: Update L2 domain with incorrect parameter vswitch (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + vswitch: avs + check_mode: true + ignore_errors: true + register: cm_incorrect_vswitch + +- name: Update L2 domain with incorrect parameter vswitch (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + vswitch: avs + ignore_errors: true + register: nm_incorrect_vswitch + +- name: Verify incorrect parameter + assert: + that: + - cm_incorrect_vm_provider.msg == "Domain type 'l2dom' cannot have parameter 'vm_provider'" + - nm_incorrect_vm_provider.msg == "Domain type 'l2dom' cannot have parameter 'vm_provider'" + - cm_incorrect_encap_mode.msg == "Domain type 'l2dom' cannot have parameter 'encap_mode'" + - nm_incorrect_encap_mode.msg == "Domain type 'l2dom' cannot have parameter 'encap_mode'" + - cm_incorrect_multicast_address.msg == "Domain type 'l2dom' cannot have parameter 'multicast_address'" + - nm_incorrect_multicast_address.msg == "Domain type 'l2dom' cannot have parameter 'multicast_address'" + - cm_incorrect_vswitch.msg == "Domain type 'l2dom' cannot have parameter 'vswitch'" + - nm_incorrect_vswitch.msg == "Domain type 'l2dom' cannot have parameter 'vswitch'" + +# QUERY ALL DOMAINS +- name: Query all L2 domains (check_mode) + cisco.aci.aci_domain: &domain_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") }}' + domain_type: l2dom + state: query + check_mode: true + register: cm_query_all_domains + +- name: Query all L2 domains (normal mode) + cisco.aci.aci_domain: *domain_query + register: nm_query_all_domains + +- name: Verify L2 query_all_domains + assert: + that: + - cm_query_all_domains is not changed + - nm_query_all_domains is not changed + - cm_query_all_domains == nm_query_all_domains + - nm_query_all_domains.current|length >= 1 + + +# QUERY A DOMAIN +- name: Query our L2 domain (check_mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: l2_dom + check_mode: true + register: cm_query_domain + +- name: Query our L2 domain (normal mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: l2_dom + register: nm_query_domain + +- name: Verify L2 query_domain + assert: + that: + - cm_query_domain is not changed + - nm_query_domain is not changed + - cm_query_domain == nm_query_domain + - nm_query_domain.current.0.l2extDomP.attributes.dn == 'uni/l2dom-l2_dom' + - nm_query_domain.current.0.l2extDomP.attributes.name == 'l2_dom' + + +# REMOVE DOMAIN +- name: Remove L2 domain (check_mode) + cisco.aci.aci_domain: *domain_absent + check_mode: true + register: cm_remove_domain + +- name: Remove L2 domain (normal mode) + cisco.aci.aci_domain: *domain_absent + register: nm_remove_domain + +- name: Verify L2 remove_domain + assert: + that: + - cm_remove_domain is changed + - nm_remove_domain is changed + - cm_remove_domain.current.0.l2extDomP.attributes.dn == cm_remove_domain.previous.0.l2extDomP.attributes.dn == nm_remove_domain.previous.0.l2extDomP.attributes.dn == 'uni/l2dom-l2_dom' + - cm_remove_domain.current.0.l2extDomP.attributes.name == cm_remove_domain.previous.0.l2extDomP.attributes.name == nm_remove_domain.previous.0.l2extDomP.attributes.name == 'l2_dom' + - nm_remove_domain.current == [] + +- name: Remove L2 domain again (check_mode) + cisco.aci.aci_domain: *domain_absent + check_mode: true + register: cm_remove_domain_again + +- name: Remove L2 domain again (normal mode) + cisco.aci.aci_domain: *domain_absent + register: nm_remove_domain_again + +- name: Verify L2 remove_domain_again + assert: + that: + - cm_remove_domain_again is not changed + - nm_remove_domain_again is not changed + + +# QUERY NON-EXISTING DOMAIN +- name: Query non-existing L2 domain (check_mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: l2_dom + check_mode: true + register: cm_query_non_domain + +- name: Query non-existing L2 domain (normal mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: l2_dom + register: nm_query_non_domain + +- name: Verify L2 query_non_domain + assert: + that: + - cm_query_non_domain is not changed + - nm_query_non_domain is not changed + - cm_query_non_domain == nm_query_non_domain + - nm_query_non_domain.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/l3dom.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/l3dom.yml new file mode 100644 index 000000000..61677d897 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/l3dom.yml @@ -0,0 +1,249 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + + +# CLEAN ENVIRONMENT +- name: Remove L3 domain + cisco.aci.aci_domain: &domain_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") }}' + domain: l3_dom + domain_type: l3dom + state: absent + + +# ADD DOMAIN +- name: Add L3 domain (check_mode) + cisco.aci.aci_domain: &domain_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") }}' + domain: l3_dom + domain_type: l3dom + state: present + check_mode: true + register: cm_add_domain + +- name: Add L3 domain (normal mode) + cisco.aci.aci_domain: *domain_present + register: nm_add_domain + +- name: Verify L3 add_domain + assert: + that: + - cm_add_domain is changed + - nm_add_domain is changed + - cm_add_domain.sent.l3extDomP.attributes.name == nm_add_domain.sent.l3extDomP.attributes.name == 'l3_dom' + - cm_add_domain.proposed.l3extDomP.attributes.name == nm_add_domain.proposed.l3extDomP.attributes.name == 'l3_dom' + - cm_add_domain.current == cm_add_domain.previous == nm_add_domain.previous == [] + - nm_add_domain.current.0.l3extDomP.attributes.annotation == 'orchestrator:ansible' + - nm_add_domain.current.0.l3extDomP.attributes.name == 'l3_dom' + - nm_add_domain.current.0.l3extDomP.attributes.dn == 'uni/l3dom-l3_dom' + +- name: Add L3 domain again (check_mode) + cisco.aci.aci_domain: *domain_present + check_mode: true + register: cm_add_domain_again + +- name: Add L3 domain again (normal mode) + cisco.aci.aci_domain: *domain_present + register: nm_add_domain_again + +- name: Verify L3 add_domain_again + assert: + that: + - cm_add_domain_again is not changed + - nm_add_domain_again is not changed + +- name: Update L3 domain with incorrect parameter vm_provider (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + vm_provider: vmware + check_mode: true + ignore_errors: true + register: cm_incorrect_vm_provider + +- name: Update L3 domain with incorrect parameter vm_provider (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + vm_provider: vmware + ignore_errors: true + register: nm_incorrect_vm_provider + +- name: Update L3 domain with incorrect parameter encap_mode (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + encap_mode: vlan + check_mode: true + ignore_errors: true + register: cm_incorrect_encap_mode + +- name: Update L3 domain with incorrect parameter encap_mode (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + encap_mode: vlan + ignore_errors: true + register: nm_incorrect_encap_mode + +- name: Update L3 domain with incorrect parameter multicast_address (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + multicast_address: 10.10.10.0 + check_mode: true + ignore_errors: true + register: cm_incorrect_multicast_address + +- name: Update L3 domain with incorrect parameter multicast_address (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + multicast_address: 10.10.10.0 + ignore_errors: true + register: nm_incorrect_multicast_address + +- name: Update L3m domain with incorrect parameter vswitch (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + vswitch: avs + check_mode: true + ignore_errors: true + register: cm_incorrect_vswitch + +- name: Update L3 domain with incorrect parameter vswitch (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + vswitch: avs + ignore_errors: true + register: nm_incorrect_vswitch + +- name: Verify incorrect parameter + assert: + that: + - cm_incorrect_vm_provider.msg == "Domain type 'l3dom' cannot have parameter 'vm_provider'" + - nm_incorrect_vm_provider.msg == "Domain type 'l3dom' cannot have parameter 'vm_provider'" + - cm_incorrect_encap_mode.msg == "Domain type 'l3dom' cannot have parameter 'encap_mode'" + - nm_incorrect_encap_mode.msg == "Domain type 'l3dom' cannot have parameter 'encap_mode'" + - cm_incorrect_multicast_address.msg == "Domain type 'l3dom' cannot have parameter 'multicast_address'" + - nm_incorrect_multicast_address.msg == "Domain type 'l3dom' cannot have parameter 'multicast_address'" + - cm_incorrect_vswitch.msg == "Domain type 'l3dom' cannot have parameter 'vswitch'" + - nm_incorrect_vswitch.msg == "Domain type 'l3dom' cannot have parameter 'vswitch'" + + +# QUERY ALL DOMAINS +- name: Query all L3 domains (check_mode) + cisco.aci.aci_domain: &domain_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") }}' + domain_type: l3dom + state: query + check_mode: true + register: cm_query_all_domains + +- name: Query all L3 domains (normal mode) + cisco.aci.aci_domain: *domain_query + register: nm_query_all_domains + +- name: Verify query_all_domains + assert: + that: + - cm_query_all_domains is not changed + - nm_query_all_domains is not changed + - cm_query_all_domains == nm_query_all_domains + - nm_query_all_domains.current|length >= 1 + + +# QUERY A DOMAIN +- name: Query our L3 domain (check_mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: l3_dom + check_mode: true + register: cm_query_domain + +- name: Query our L3 domain (normal mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: l3_dom + register: nm_query_domain + +- name: Verify L3 query_domain + assert: + that: + - cm_query_domain is not changed + - nm_query_domain is not changed + - cm_query_domain == nm_query_domain + - nm_query_domain.current.0.l3extDomP.attributes.dn == 'uni/l3dom-l3_dom' + - nm_query_domain.current.0.l3extDomP.attributes.name == 'l3_dom' + + +# REMOVE DOMAIN +- name: Remove L3 domain (check_mode) + cisco.aci.aci_domain: *domain_absent + check_mode: true + register: cm_remove_domain + +- name: Remove L3 domain (normal mode) + cisco.aci.aci_domain: *domain_absent + register: nm_remove_domain + +- name: Verify L3 remove_domain + assert: + that: + - cm_remove_domain is changed + - nm_remove_domain is changed + - cm_remove_domain.current.0.l3extDomP.attributes.name == cm_remove_domain.previous.0.l3extDomP.attributes.name == nm_remove_domain.previous.0.l3extDomP.attributes.name == 'l3_dom' + - cm_remove_domain.current.0.l3extDomP.attributes.dn == cm_remove_domain.previous.0.l3extDomP.attributes.dn == nm_remove_domain.previous.0.l3extDomP.attributes.dn == 'uni/l3dom-l3_dom' + - nm_remove_domain.current == [] + +- name: Remove L3 domain again (check_mode) + cisco.aci.aci_domain: *domain_absent + check_mode: true + register: cm_remove_domain_again + +- name: Remove L3 domain again (normal mode) + cisco.aci.aci_domain: *domain_absent + register: nm_remove_domain_again + +- name: Verify L3 remove_domain_again + assert: + that: + - cm_remove_domain_again is not changed + - nm_remove_domain_again is not changed + + +# QUERY NON-EXISTING DOMAIN +- name: Query non-existing L3 domain (check_mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: l3_dom + check_mode: true + register: cm_query_non_domain + +- name: Query non-existing L3 domain (normal mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: l3_dom + register: nm_query_non_domain + +- name: Verify L3 query_non_domain + assert: + that: + - cm_query_non_domain is not changed + - nm_query_non_domain is not changed + - cm_query_non_domain == nm_query_non_domain + - nm_query_non_domain.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/main.yml new file mode 100644 index 000000000..be6c9712d --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/main.yml @@ -0,0 +1,24 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.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 + +- include_tasks: phys.yml + when: phys is not defined or phys + +- include_tasks: l2dom.yml + when: l2dom is not defined or l2dom + +- include_tasks: l3dom.yml + when: l3dom is not defined or l3dom + +- include_tasks: fc.yml + when: fc is not defined or fc + +- include_tasks: vmm-vmware.yml + when: vmm_vmware is not defined or vmm_vmware diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/phys.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/phys.yml new file mode 100644 index 000000000..39f87a6f0 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/phys.yml @@ -0,0 +1,248 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + + +# CLEAN ENVIRONMENT +- name: Remove physical domain + cisco.aci.aci_domain: &domain_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") }}' + domain: phys_dom + domain_type: phys + state: absent + + +# ADD DOMAIN +- name: Add physical domain (check_mode) + cisco.aci.aci_domain: &domain_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") }}' + domain: phys_dom + domain_type: phys + state: present + check_mode: true + register: cm_add_domain + +- name: Add physical domain (normal mode) + cisco.aci.aci_domain: *domain_present + register: nm_add_domain + +- name: Verify physical add_domain + assert: + that: + - cm_add_domain is changed + - nm_add_domain is changed + - cm_add_domain.sent.physDomP.attributes.name == nm_add_domain.sent.physDomP.attributes.name == 'phys_dom' + - cm_add_domain.proposed.physDomP.attributes.name == nm_add_domain.proposed.physDomP.attributes.name == 'phys_dom' + - cm_add_domain.current == cm_add_domain.previous == nm_add_domain.previous == [] + - nm_add_domain.current.0.physDomP.attributes.annotation == 'orchestrator:ansible' + - nm_add_domain.current.0.physDomP.attributes.name == 'phys_dom' + - nm_add_domain.current.0.physDomP.attributes.dn == 'uni/phys-phys_dom' + +- name: Add physical domain again (check_mode) + cisco.aci.aci_domain: *domain_present + check_mode: true + register: cm_add_domain_again + +- name: Add physical domain again (normal mode) + cisco.aci.aci_domain: *domain_present + register: nm_add_domain_again + +- name: Verify physical add_domain_again + assert: + that: + - cm_add_domain_again is not changed + - nm_add_domain_again is not changed + +- name: Update physical domain with incorrect parameter vm_provider (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + vm_provider: vmware + check_mode: true + ignore_errors: true + register: cm_incorrect_vm_provider + +- name: Update physical domain with incorrect parameter vm_provider (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + vm_provider: vmware + ignore_errors: true + register: nm_incorrect_vm_provider + +- name: Update physical domain with incorrect parameter encap_mode (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + encap_mode: vlan + check_mode: true + ignore_errors: true + register: cm_incorrect_encap_mode + +- name: Update physical domain with incorrect parameter encap_mode (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + encap_mode: vlan + ignore_errors: true + register: nm_incorrect_encap_mode + +- name: Update physical domain with incorrect parameter multicast_address (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + multicast_address: 10.10.10.0 + check_mode: true + ignore_errors: true + register: cm_incorrect_multicast_address + +- name: Update physical domain with incorrect parameter multicast_address (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + multicast_address: 10.10.10.0 + ignore_errors: true + register: nm_incorrect_multicast_address + +- name: Update physical domain with incorrect parameter vswitch (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + vswitch: avs + check_mode: true + ignore_errors: true + register: cm_incorrect_vswitch + +- name: Update physical domain with incorrect parameter vswitch (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + vswitch: avs + ignore_errors: true + register: nm_incorrect_vswitch + +- name: Verify incorrect parameter + assert: + that: + - cm_incorrect_vm_provider.msg == "Domain type 'phys' cannot have parameter 'vm_provider'" + - nm_incorrect_vm_provider.msg == "Domain type 'phys' cannot have parameter 'vm_provider'" + - cm_incorrect_encap_mode.msg == "Domain type 'phys' cannot have parameter 'encap_mode'" + - nm_incorrect_encap_mode.msg == "Domain type 'phys' cannot have parameter 'encap_mode'" + - cm_incorrect_multicast_address.msg == "Domain type 'phys' cannot have parameter 'multicast_address'" + - nm_incorrect_multicast_address.msg == "Domain type 'phys' cannot have parameter 'multicast_address'" + - cm_incorrect_vswitch.msg == "Domain type 'phys' cannot have parameter 'vswitch'" + - nm_incorrect_vswitch.msg == "Domain type 'phys' cannot have parameter 'vswitch'" + +# QUERY ALL DOMAINS +- name: Query all physical domains (check_mode) + cisco.aci.aci_domain: &domain_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") }}' + domain_type: phys + state: query + check_mode: true + register: cm_query_all_domains + +- name: Query all physical domains (normal mode) + cisco.aci.aci_domain: *domain_query + register: nm_query_all_domains + +- name: Verify physical query_all_domains + assert: + that: + - cm_query_all_domains is not changed + - nm_query_all_domains is not changed + - cm_query_all_domains == nm_query_all_domains + - nm_query_all_domains.current|length >= 1 + + +# QUERY A DOMAIN +- name: Query our physical domain (check_mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: phys_dom + check_mode: true + register: cm_query_domain + +- name: Query our physical domain (normal mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: phys_dom + register: nm_query_domain + +- name: Verify physical query_domain + assert: + that: + - cm_query_domain is not changed + - nm_query_domain is not changed + - cm_query_domain == nm_query_domain + - nm_query_domain.current.0.physDomP.attributes.dn == 'uni/phys-phys_dom' + - nm_query_domain.current.0.physDomP.attributes.name == 'phys_dom' + + +# REMOVE DOMAIN +- name: Remove physical domain (check_mode) + cisco.aci.aci_domain: *domain_absent + check_mode: true + register: cm_remove_domain + +- name: Remove physical domain (normal mode) + cisco.aci.aci_domain: *domain_absent + register: nm_remove_domain + +- name: Verify physical remove_domain + assert: + that: + - cm_remove_domain is changed + - nm_remove_domain is changed + - cm_remove_domain.current.0.physDomP.attributes.name == cm_remove_domain.previous.0.physDomP.attributes.name == nm_remove_domain.previous.0.physDomP.attributes.name == 'phys_dom' + - cm_remove_domain.current.0.physDomP.attributes.dn == cm_remove_domain.previous.0.physDomP.attributes.dn == nm_remove_domain.previous.0.physDomP.attributes.dn == 'uni/phys-phys_dom' + - nm_remove_domain.current == [] + +- name: Remove physical domain again (check_mode) + cisco.aci.aci_domain: *domain_absent + check_mode: true + register: cm_remove_domain_again + +- name: Remove physical domain again (normal mode) + cisco.aci.aci_domain: *domain_absent + register: nm_remove_domain_again + +- name: Verify physical remove_domain_again + assert: + that: + - cm_remove_domain_again is not changed + - nm_remove_domain_again is not changed + + +# QUERY NON-EXISTING DOMAIN +- name: Query non-existing physical domain (check_mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: phys_dom + check_mode: true + register: cm_query_non_domain + +- name: Query non-existing physical domain (normal mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: phys_dom + register: nm_query_non_domain + +- name: Verify physical query_non_domain + assert: + that: + - cm_query_non_domain is not changed + - nm_query_non_domain is not changed + - cm_query_non_domain == nm_query_non_domain + - nm_query_non_domain.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/vmm-vmware.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/vmm-vmware.yml new file mode 100644 index 000000000..03d82788c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain/tasks/vmm-vmware.yml @@ -0,0 +1,217 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# CLEAN ENVIRONMENT +- name: Remove VMM domain + cisco.aci.aci_domain: &domain_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") }}' + domain: vmm_dom + domain_type: vmm + vm_provider: vmware + 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 skip execution for cloud sites + block: + # ADD DOMAIN + - name: Add VMM domain (check_mode) + cisco.aci.aci_domain: &domain_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") }}' + domain: vmm_dom + domain_type: vmm + vm_provider: vmware + access_mode: read-write + enable_vm_folder: true + state: present + check_mode: true + register: cm_add_domain + + - name: Add VMM domain (normal mode) + cisco.aci.aci_domain: *domain_present + register: nm_add_domain + + - name: Verify VMM add_domain + assert: + that: + - cm_add_domain is changed + - nm_add_domain is changed + - cm_add_domain.sent.vmmDomP.attributes.name == nm_add_domain.sent.vmmDomP.attributes.name == 'vmm_dom' + - cm_add_domain.proposed.vmmDomP.attributes.name == nm_add_domain.proposed.vmmDomP.attributes.name == 'vmm_dom' + - cm_add_domain.current == cm_add_domain.previous == nm_add_domain.previous == [] + - nm_add_domain.current.0.vmmDomP.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom' + - nm_add_domain.current.0.vmmDomP.attributes.name == 'vmm_dom' + - nm_add_domain.current.0.vmmDomP.attributes.annotation == 'orchestrator:ansible' + + - name: Add VMM domain again (check_mode) + cisco.aci.aci_domain: *domain_present + check_mode: true + register: cm_add_domain_again + + - name: Add VMM domain again (normal mode) + cisco.aci.aci_domain: *domain_present + register: nm_add_domain_again + + - name: Verify VMM add_domain_again + assert: + that: + - cm_add_domain_again is not changed + - nm_add_domain_again is not changed + + - name: Update VMM domain with tag collection and infra port groups (check_mode) + cisco.aci.aci_domain: + <<: *domain_present + add_infra_pg: true + tag_collection: true + check_mode: true + register: cm_update_domain + when: version.current.0.topSystem.attributes.version is version('4.1', '>=') + + - name: Update VMM domain with tag collection and infra port groups (normal mode) + cisco.aci.aci_domain: + <<: *domain_present + add_infra_pg: true + tag_collection: true + register: nm_update_domain + when: version.current.0.topSystem.attributes.version is version('4.1', '>=') + + - name: Verify update_domain + assert: + that: + - cm_update_domain is changed + - nm_update_domain is changed + - cm_update_domain.previous.0.vmmDomP.attributes.configInfraPg == nm_update_domain.previous.0.vmmDomP.attributes.configInfraPg == 'no' + - cm_update_domain.proposed.vmmDomP.attributes.configInfraPg == nm_update_domain.current.0.vmmDomP.attributes.configInfraPg == 'yes' + - cm_update_domain.previous.0.vmmDomP.attributes.enableTag == nm_update_domain.previous.0.vmmDomP.attributes.enableTag == 'no' + - cm_update_domain.proposed.vmmDomP.attributes.enableTag == nm_update_domain.current.0.vmmDomP.attributes.enableTag == 'yes' + when: version.current.0.topSystem.attributes.version is version('4.1', '>=') + + # QUERY ALL DOMAINS + - name: Query all VMM domains (check_mode) + cisco.aci.aci_domain: &domain_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") }}' + domain_type: vmm + vm_provider: vmware + state: query + check_mode: true + register: cm_query_all_domains + + - name: Query all VMM domains (normal mode) + cisco.aci.aci_domain: *domain_query + register: nm_query_all_domains + + - name: Verify query_all_domains + assert: + that: + - cm_query_all_domains is not changed + - nm_query_all_domains is not changed + - cm_query_all_domains == nm_query_all_domains + - nm_query_all_domains.current|length >= 1 + + + # QUERY A DOMAIN + - name: Query our VMM domain (check_mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: vmm_dom + vm_provider: vmware + check_mode: true + register: cm_query_domain + + - name: Query our VMM domain (normal mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: vmm_dom + vm_provider: vmware + register: nm_query_domain + + - name: Verify VMM query_domain + assert: + that: + - cm_query_domain is not changed + - nm_query_domain is not changed + - cm_query_domain == nm_query_domain + - nm_query_domain.current.0.vmmDomP.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom' + - nm_query_domain.current.0.vmmDomP.attributes.name == 'vmm_dom' + + # REMOVE DOMAIN + - name: Remove VMM domain (check_mode) + cisco.aci.aci_domain: *domain_absent + check_mode: true + register: cm_remove_domain + + - name: Remove VMM domain (normal mode) + cisco.aci.aci_domain: *domain_absent + register: nm_remove_domain + + - name: Verify VMM remove_domain + assert: + that: + - cm_remove_domain is changed + - nm_remove_domain is changed + - cm_remove_domain.current == cm_remove_domain.previous == nm_remove_domain.previous + - nm_remove_domain.previous.0.vmmDomP.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom' + - nm_remove_domain.previous.0.vmmDomP.attributes.name == 'vmm_dom' + - nm_remove_domain.current == [] + + - name: Remove VMM domain again (check_mode) + cisco.aci.aci_domain: *domain_absent + check_mode: true + register: cm_remove_domain_again + + - name: Remove VMM domain again (normal mode) + cisco.aci.aci_domain: *domain_absent + register: nm_remove_domain_again + + - name: Verify VMM remove_domain_again + assert: + that: + - cm_remove_domain_again is not changed + - nm_remove_domain_again is not changed + + + # QUERY NON-EXISTING DOMAIN + - name: Query non-existing VMM domain (check_mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: vmm_dom + vm_provider: vmware + check_mode: true + register: cm_query_non_domain + + - name: Query non-existing VMM domain (normal mode) + cisco.aci.aci_domain: + <<: *domain_query + domain: vmm_dom + vm_provider: vmware + register: nm_query_non_domain + + - name: Verify VMM query_non_domain + assert: + that: + - cm_query_non_domain is not changed + - nm_query_non_domain is not changed + - cm_query_non_domain == nm_query_non_domain + - nm_query_non_domain.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_domain_to_encap_pool/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain_to_encap_pool/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain_to_encap_pool/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_domain_to_encap_pool/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain_to_encap_pool/tasks/main.yml new file mode 100644 index 000000000..f028e2c56 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain_to_encap_pool/tasks/main.yml @@ -0,0 +1,655 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Shreyas Srish (@shrsr) + +# 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 + +# Clean Environment +- name: Remove domains + aci_domain: + <<: *aci_info + domain: '{{ item.name }}' + domain_type: '{{ item.type }}' + state: absent + loop: + - { name: phys_dom, type: phys } + - { name: fc_dom, type: fc } + - { name: l2_dom, type: l2dom } + - { name: l3_dom, type: l3dom } + +- name: Remove domains + aci_domain: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + vm_provider: '{{ item.name }}' + state: absent + loop: + - { name: vmware } + - { name: microsoft } + - { name: cloudfoundry } + - { name: openshift } + - { name: openstack } + - { name: redhat } + - { name: kubernetes } + +- 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 + # Add + - name: Add physical domain + aci_domain: + <<: *aci_info + domain: phys_dom + domain_type: phys + state: present + register: phys_domain + + - name: Add l2 domain + aci_domain: + <<: *aci_info + domain: l2_dom + domain_type: l2dom + state: present + register: l2_domain + + - name: Add l3 domain + aci_domain: + <<: *aci_info + domain: l3_dom + domain_type: l3dom + state: present + register: l3_domain + + - name: Add FC domain + aci_domain: + <<: *aci_info + domain: fc_dom + domain_type: fc + state: present + register: fc_domain + + - name: Add vmm domain + aci_domain: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + vm_provider: vmware + state: present + register: vmm_domain + + - name: Add domain to encap pool binding (phys, pool_type=vlan) + aci_domain_to_encap_pool: + <<: *aci_info + domain: phys_dom + domain_type: phys + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + state: present + register: phys_vlan + + - name: Add domain to encap pool binding (fc, pool_type=vsan) + aci_domain_to_encap_pool: + <<: *aci_info + domain: fc_dom + domain_type: fc + pool: test_pool + pool_type: vsan + pool_allocation_mode: dynamic + state: present + register: fc_vsan + + - name: Add domain to encap pool binding (domain_type=l2dom) + aci_domain_to_encap_pool: + <<: *aci_info + domain: l2_dom + domain_type: l2dom + pool: test_pool + pool_type: vlan + pool_allocation_mode: static + state: present + register: l2dom + + - name: Add domain to encap pool binding (domain_type=l3dom) + aci_domain_to_encap_pool: + <<: *aci_info + domain: l3_dom + domain_type: l3dom + pool: test_pool + pool_type: vlan + pool_allocation_mode: static + state: present + register: l3dom + + - name: Add domain to encap pool binding (domain_type=vmm, vm_provider=cloudfoundry) + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + vm_provider: cloudfoundry + state: present + register: vmm_cloudfoundry + + - name: Add domain to encap pool binding (domain_type=vmm, vm_provider=kubernetes) + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + vm_provider: kubernetes + state: present + register: vmm_kubernetes + + - name: Add domain to encap pool binding (domain_type=vmm, vm_provider=microsoft) + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + vm_provider: microsoft + state: present + register: vmm_microsoft + + - name: Add domain to encap pool binding (domain_type=vmm, vm_provider=openshift) + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + vm_provider: openshift + state: present + register: vmm_openshift + + - name: Add domain to encap pool binding (domain_type=vmm, vm_provider=openstack) + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + vm_provider: openstack + state: present + register: vmm_openstack + + - name: Add domain to encap pool binding (domain_type=vmm, vm_provider=redhat) + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + vm_provider: redhat + state: present + register: vmm_redhat + + - name: Add domain to encap pool binding (domain_type=vmm, vm_provider=vmware) + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + vm_provider: vmware + state: present + register: vmm_vmware + + - name: Add domain to encap pool binding (domain_type=vmm, vm_provider=vmware) again + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + vm_provider: vmware + state: present + register: vmm_vmware_idemp + + - name: Add domain to encap pool binding (phys with vm_provider) + aci_domain_to_encap_pool: + <<: *aci_info + domain: phys_dom + domain_type: phys + pool: test_pool + pool_type: vlan + vm_provider: vmware + pool_allocation_mode: dynamic + state: present + ignore_errors: true + register: phys_vlan_with_vmm + + - name: Add domain to encap pool binding (phys, pool_type=vlan, no allocation mode) + aci_domain_to_encap_pool: + <<: *aci_info + domain: phys_dom + domain_type: phys + pool: test_pool + pool_type: vlan + state: present + ignore_errors: true + register: phys_vlan_no_alloc + + - name: Add domain to encap pool binding (domain_type=vmm, vm_provider=vmware, pool_type=vxlan) + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool: test_pool + pool_type: vxlan + pool_allocation_mode: dynamic + vm_provider: vmware + state: present + ignore_errors: true + register: vmm_vmware_vxlan + + - name: Add domain to encap pool binding (phys, pool_type=vlan) missing domain_type + aci_domain_to_encap_pool: + <<: *aci_info + domain: phys_dom + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + state: present + ignore_errors: true + register: phys_missing_domain_type + + - name: Add domain to encap pool binding (phys, pool_type=vlan) missing pool_type + aci_domain_to_encap_pool: + <<: *aci_info + domain: phys_dom + domain_type: phys + pool: test_pool + pool_allocation_mode: dynamic + state: present + ignore_errors: true + register: phys_missing_pool_type + + - name: Verify add operation for All Sites + assert: + that: + - phys_vlan is changed + - fc_vsan is changed + - l2dom is changed + - l3dom is changed + - vmm_kubernetes is changed + - phys_vlan.current.0.physDomP.attributes.annotation == 'orchestrator:ansible' + - phys_vlan.current.0.physDomP.children.0.infraRsVlanNs.attributes.tDn =='uni/infra/vlanns-[test_pool]-dynamic' + - fc_vsan.current.0.fcDomP.children.0.fcRsVsanNs.attributes.tDn == 'uni/infra/vsanns-[test_pool]-dynamic' + - l2dom.current.0.l2extDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-static' + - l3dom.current.0.l3extDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-static' + - vmm_kubernetes.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - phys_vlan_with_vmm.msg is match("Domain type '[0-9a-zA-Z]*' cannot have a 'vm_provider'") + - vmm_vmware_vxlan.msg is match("vxlan pools do not support setting the allocation_mode; please remove this parameter from the task") + - phys_vlan_no_alloc.msg is match("ACI requires the 'pool_allocation_mode' for 'pool_type' of 'vlan' and 'vsan' when 'pool' is provided") + - phys_missing_pool_type.msg is match("missing required arguments{{':'}} pool_type") + - phys_missing_domain_type.msg is match("missing required arguments{{':'}} domain_type") + + - name: Verify add operation for Non-Cloud Sites + assert: + that: + - vmm_cloudfoundry is changed + - vmm_openshift is changed + - vmm_openstack is changed + - vmm_redhat is changed + - vmm_vmware is changed + - vmm_vmware_idemp is not changed + - vmm_cloudfoundry.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - vmm_microsoft.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - vmm_openshift.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - vmm_openstack.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - vmm_redhat.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - vmm_vmware.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + + # QUERY + - name: Query all + aci_domain_to_encap_pool: + <<: *aci_info + domain_type: phys + pool_type: vlan + state: query + register: query_all + + - name: Query phys + aci_domain_to_encap_pool: + <<: *aci_info + domain: phys_dom + domain_type: phys + pool_type: vlan + state: query + register: query_phys + + - name: Query fc + aci_domain_to_encap_pool: + <<: *aci_info + domain: fc_dom + domain_type: fc + pool_type: vsan + state: query + register: query_fc + + - name: Query l2dom + aci_domain_to_encap_pool: + <<: *aci_info + domain: l2_dom + domain_type: l2dom + pool_type: vlan + state: query + register: query_l2dom + + - name: Query l3dom + aci_domain_to_encap_pool: + <<: *aci_info + domain: l3_dom + domain_type: l3dom + pool_type: vlan + state: query + register: query_l3dom + + - name: Query vmm + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool_type: vlan + vm_provider: microsoft + state: query + register: query_vmm_microsoft + + - name: Query vmm + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool_type: vlan + vm_provider: cloudfoundry + state: query + register: query_vmm_cloudfoundry + + - name: Query vmm + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool_type: vlan + vm_provider: kubernetes + state: query + register: query_vmm_kubernetes + + - name: Query vmm + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool_type: vlan + vm_provider: openshift + state: query + register: query_vmm_openshift + + - name: Query vmm + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool_type: vlan + vm_provider: openstack + state: query + register: query_vmm_openstack + + - name: Query vmm + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool_type: vlan + vm_provider: redhat + state: query + register: query_vmm_redhat + + - name: Query vmm + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool_type: vlan + vm_provider: vmware + state: query + register: query_vmm_vmware + + - name: Query vmm + aci_domain_to_encap_pool: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + pool_type: vlan + vm_provider: vmware + state: query + register: query_vmm_vmware + + - name: Verify Query for Non-Cloud sites + assert: + that: + - query_all | length >=1 + - query_phys.current.0.physDomP.children.0.infraRsVlanNs.attributes.tDn =='uni/infra/vlanns-[test_pool]-dynamic' + - query_fc.current.0.fcDomP.children.0.fcRsVsanNs.attributes.tDn == 'uni/infra/vsanns-[test_pool]-dynamic' + - query_l2dom.current.0.l2extDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-static' + - query_l3dom.current.0.l3extDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-static' + - query_vmm_kubernetes.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + + + - name: Verify Query for Cloud sites + assert: + that: + - query_vmm_cloudfoundry.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - query_vmm_microsoft.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - query_vmm_openshift.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - query_vmm_openstack.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - query_vmm_redhat.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - query_vmm_vmware.current.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + + # REMOVE + - name: Remove phys + aci_domain_to_encap_pool: + <<: *aci_info + domain_type: phys + domain: phys_dom + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + state: absent + register: remove_phys + + - name: Remove fc + aci_domain_to_encap_pool: + <<: *aci_info + domain_type: fc + domain: fc_dom + pool: test_pool + pool_type: vsan + pool_allocation_mode: dynamic + state: absent + register: remove_fc + + - name: Remove l2dom + aci_domain_to_encap_pool: + <<: *aci_info + domain_type: l2dom + domain: l2_dom + pool: test_pool + pool_type: vlan + pool_allocation_mode: static + state: absent + register: remove_l2dom + + - name: Remove l3dom + aci_domain_to_encap_pool: + <<: *aci_info + domain_type: l3dom + domain: l3_dom + pool: test_pool + pool_type: vlan + pool_allocation_mode: static + state: absent + register: remove_l3dom + + - name: Remove vmm cloudfoundry + aci_domain_to_encap_pool: + <<: *aci_info + domain_type: vmm + domain: vmm_dom + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + vm_provider: cloudfoundry + state: absent + register: remove_vmm_cloudfoundry + + - name: Remove vmm redhat kubernetes + aci_domain_to_encap_pool: + <<: *aci_info + domain_type: vmm + domain: vmm_dom + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + vm_provider: kubernetes + state: absent + register: remove_vmm_kubernetes + + - name: Remove vmm microsoft + aci_domain_to_encap_pool: + <<: *aci_info + domain_type: vmm + domain: vmm_dom + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + vm_provider: microsoft + state: absent + register: remove_vmm_microsoft + + - name: Remove vmm redhat + aci_domain_to_encap_pool: + <<: *aci_info + domain_type: vmm + domain: vmm_dom + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + vm_provider: redhat + state: absent + register: remove_vmm_redhat + + - name: Remove vmm openstack + aci_domain_to_encap_pool: + <<: *aci_info + domain_type: vmm + domain: vmm_dom + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + vm_provider: openstack + state: absent + register: remove_vmm_openstack + + - name: Remove vmm openshift + aci_domain_to_encap_pool: + <<: *aci_info + domain_type: vmm + domain: vmm_dom + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + vm_provider: openshift + state: absent + register: remove_vmm_openshift + + - name: Remove vmm vmware + aci_domain_to_encap_pool: + <<: *aci_info + domain_type: vmm + domain: vmm_dom + pool: test_pool + pool_type: vlan + pool_allocation_mode: dynamic + vm_provider: vmware + state: absent + register: remove_vmm_vmware + + - name: Verify Remove for All Sites + assert: + that: + - remove_phys.previous.0.physDomP.children.0.infraRsVlanNs.attributes.tDn =='uni/infra/vlanns-[test_pool]-dynamic' + - remove_fc.previous.0.fcDomP.children.0.fcRsVsanNs.attributes.tDn == 'uni/infra/vsanns-[test_pool]-dynamic' + - remove_l2dom.previous.0.l2extDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-static' + - remove_l3dom.previous.0.l3extDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-static' + - remove_vmm_kubernetes.previous.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + + - name: Verify Remove for Non-Cloud Sites + assert: + that: + - remove_vmm_cloudfoundry.previous.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - remove_vmm_microsoft.previous.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - remove_vmm_openshift.previous.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - remove_vmm_openstack.previous.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - remove_vmm_redhat.previous.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - remove_vmm_vmware.previous.0.vmmDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + + # Clean Environment Again + - name: Remove domains + aci_domain: + <<: *aci_info + domain: '{{ item.name }}' + domain_type: '{{ item.type }}' + state: absent + loop: + - { name: phys_dom, type: phys } + - { name: fc_dom, type: fc } + - { name: l2_dom, type: l2dom } + - { name: l3_dom, type: l3dom } + + - name: Remove domains + aci_domain: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + vm_provider: '{{ item.name }}' + state: absent + loop: + - { name: vmware } + - { name: microsoft } + - { name: cloudfoundry } + - { name: openshift } + - { name: openstack } + - { name: redhat } + - { name: kubernetes }
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_domain_to_vlan_pool/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain_to_vlan_pool/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain_to_vlan_pool/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..8c31fd4cc --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_domain_to_vlan_pool/tasks/main.yml @@ -0,0 +1,228 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- 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: 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") }}' + domain: phys_dom + domain_type: phys + pool: test_pool + pool_allocation_mode: dynamic + state: absent + + - name: Remove 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") }}' + domain: phys_dom + domain_type: phys + 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") }}' + pool: test_pool + pool_allocation_mode: dynamic + description: Test VLAN pool + state: present + + + # 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") }}' + domain: phys_dom + domain_type: phys + pool: test_pool + pool_allocation_mode: dynamic + state: present + check_mode: true + register: cm_add_binding + + - name: Add domain to VLAN pool binding (normal mode) + cisco.aci.aci_domain_to_vlan_pool: *binding_present + register: nm_add_binding + + - name: Verify add_binding + assert: + that: + - cm_add_binding is changed + - nm_add_binding is changed + - cm_add_binding.sent.physDomP.attributes.name == nm_add_binding.sent.physDomP.attributes.name == 'phys_dom' + - cm_add_binding.sent.physDomP.children.0.infraRsVlanNs.attributes.tDn == nm_add_binding.sent.physDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - cm_add_binding.proposed.physDomP.attributes.name == nm_add_binding.proposed.physDomP.attributes.name == 'phys_dom' + - cm_add_binding.proposed.physDomP.children.0.infraRsVlanNs.attributes.tDn == nm_add_binding.proposed.physDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - cm_add_binding.current == cm_add_binding.previous == nm_add_binding.previous == [] + - nm_add_binding.current.0.physDomP.attributes.annotation == 'orchestrator:ansible' + - nm_add_binding.current.0.physDomP.attributes.name == 'phys_dom' + - nm_add_binding.current.0.physDomP.attributes.dn == 'uni/phys-phys_dom' + - nm_add_binding.current.0.physDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + + - name: Add domain to VLAN pool binding again (check_mode) + cisco.aci.aci_domain_to_vlan_pool: *binding_present + check_mode: true + register: cm_add_binding_again + + - name: Add domain to VLAN pool binding again (normal mode) + cisco.aci.aci_domain_to_vlan_pool: *binding_present + register: nm_add_binding_again + + - name: Verify add_binding_again + assert: + that: + - cm_add_binding_again is not changed + - nm_add_binding_again is not changed + + + # 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") }}' + domain_type: phys + pool_allocation_mode: dynamic + state: query + check_mode: true + register: cm_query_all_bindings + + - name: Query all domain to VLAN pool bindings (normal mode) + cisco.aci.aci_domain_to_vlan_pool: *binding_query + register: nm_query_all_bindings + + - name: Verify query_all_bindings + assert: + that: + - cm_query_all_bindings is not changed + - nm_query_all_bindings is not changed + - cm_query_all_bindings == nm_query_all_bindings + - nm_query_all_bindings.current|length >= 1 + + + # QUERY A BINDING + - name: Query our domain to VLAN pool binding (check_mode) + cisco.aci.aci_domain_to_vlan_pool: + <<: *binding_query + domain: phys_dom + pool: test_pool + pool_allocation_mode: dynamic + check_mode: true + register: cm_query_binding + + - name: Query our domain to VLAN pool binding (normal mode) + cisco.aci.aci_domain_to_vlan_pool: + <<: *binding_query + domain: phys_dom + pool: test_pool + pool_allocation_mode: dynamic + register: nm_query_binding + + - name: Verify query_binding + assert: + that: + - cm_query_binding is not changed + - nm_query_binding is not changed + - cm_query_binding == nm_query_binding + - nm_query_binding.current.0.physDomP.attributes.dn == 'uni/phys-phys_dom' + - nm_query_binding.current.0.physDomP.attributes.name == 'phys_dom' + - nm_query_binding.current.0.physDomP.children.0.infraRsVlanNs.attributes.tCl == 'fvnsVlanInstP' + - nm_query_binding.current.0.physDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + + + # REMOVE BINDING + - name: Remove domain to VLAN pool binding (check_mode) + cisco.aci.aci_domain_to_vlan_pool: *binding_absent + check_mode: true + register: cm_remove_binding + + - name: Remove domain to VLAN pool binding (normal mode) + cisco.aci.aci_domain_to_vlan_pool: *binding_absent + register: nm_remove_binding + + - name: Verify remove_binding + assert: + that: + - cm_remove_binding is changed + - nm_remove_binding is changed + - cm_remove_binding.current.0.physDomP.attributes.dn == cm_remove_binding.previous.0.physDomP.attributes.dn == nm_remove_binding.previous.0.physDomP.attributes.dn == 'uni/phys-phys_dom' + - cm_remove_binding.current.0.physDomP.attributes.name == cm_remove_binding.previous.0.physDomP.attributes.name == nm_remove_binding.previous.0.physDomP.attributes.name == 'phys_dom' + - cm_remove_binding.current.0.physDomP.children.0.infraRsVlanNs.attributes.tDn == cm_remove_binding.previous.0.physDomP.children.0.infraRsVlanNs.attributes.tDn == nm_remove_binding.previous.0.physDomP.children.0.infraRsVlanNs.attributes.tDn == 'uni/infra/vlanns-[test_pool]-dynamic' + - nm_remove_binding.current == [] + + - name: Remove domain to VLAN pool binding again (check_mode) + cisco.aci.aci_domain_to_vlan_pool: *binding_absent + check_mode: true + register: cm_remove_binding_again + + - name: Remove domain to VLAN pool binding again (normal mode) + cisco.aci.aci_domain_to_vlan_pool: *binding_absent + register: nm_remove_binding_again + + - name: Verify remove_binding_again + assert: + that: + - cm_remove_binding_again is not changed + - nm_remove_binding_again is not changed + + + # QUERY NON-EXISTING BINDING + - name: Query non-existing domain to VLAN pool binding (check_mode) + cisco.aci.aci_domain_to_vlan_pool: + <<: *binding_query + domain: phys_dom + pool: test_pool + pool_allocation_mode: dynamic + check_mode: true + register: cm_query_non_binding + + - name: Query non-existing domain to VLAN pool binding (normal mode) + cisco.aci.aci_domain_to_vlan_pool: + <<: *binding_query + domain: phys_dom + pool: test_pool + pool_allocation_mode: dynamic + register: nm_query_non_binding + + - name: Verify query_non_binding + assert: + that: + - cm_query_non_binding is not changed + - nm_query_non_binding is not changed + - cm_query_non_binding == nm_query_non_binding + - nm_query_non_binding.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool/tasks/main.yml new file mode 100644 index 000000000..f0e61a7ef --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool/tasks/main.yml @@ -0,0 +1,24 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) + +# 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 + block: # block specifies execution of tasks within, based on conditions + - include_tasks: vlan.yml + when: vlan is not defined or vlan + + - include_tasks: vxlan.yml + when: vxlan is not defined or vxlan + + - include_tasks: vsan.yml + when: vsan is not defined or vsan diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool/tasks/vlan.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool/tasks/vlan.yml new file mode 100644 index 000000000..1354c149a --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool/tasks/vlan.yml @@ -0,0 +1,275 @@ +--- +- name: ensure vlan pool does not exist for tests to kick off + cisco.aci.aci_encap_pool: &aci_pool_absent_static + 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: absent + pool: anstest + pool_type: vlan + pool_allocation_mode: static + +- name: ensure vlan pool does not exist for tests to kick off + cisco.aci.aci_encap_pool: &aci_pool_absent_dynamic + <<: *aci_pool_absent_static + pool_allocation_mode: dynamic + +- name: create static vlan pool - check mode works + cisco.aci.aci_encap_pool: &aci_pool_present_static + <<: *aci_pool_absent_static + state: present + descr: Ansible Test + check_mode: true + register: create_check_mode + +- name: assertion test - present + assert: + that: + - create_check_mode is changed + - create_check_mode.sent.fvnsVlanInstP.attributes.allocMode == 'static' + - create_check_mode.sent.fvnsVlanInstP.attributes.descr == 'Ansible Test' + - create_check_mode.sent.fvnsVlanInstP.attributes.name == 'anstest' + +- name: create static vlan pool - creation works + cisco.aci.aci_encap_pool: + <<: *aci_pool_present_static + register: create_static + +- name: assertion test - present + assert: + that: + - create_static is changed + - create_static.previous == [] + - create_static.sent == create_check_mode.sent + +- name: create dynamic vlan pool - creation works + cisco.aci.aci_encap_pool: &aci_pool_present_dynamic + <<: *aci_pool_absent_dynamic + state: present + descr: Ansible Test + register: create_dynamic + +- name: assertion test - present + assert: + that: + - create_dynamic is changed + - create_dynamic.previous == [] + - create_dynamic.sent.fvnsVlanInstP.attributes.allocMode == 'dynamic' + - create_dynamic.sent.fvnsVlanInstP.attributes.descr == 'Ansible Test' + - create_dynamic.sent.fvnsVlanInstP.attributes.name == 'anstest' + - create_dynamic.current.0.fvnsVlanInstP.attributes.annotation == 'orchestrator:ansible' + +- name: create static vlan pool again - idempotency works + cisco.aci.aci_encap_pool: + <<: *aci_pool_present_static + register: idempotent_static + +- name: assertion test - present + assert: + that: + - idempotent_static is not changed + - idempotent_static.previous.0.fvnsVlanInstP.attributes.allocMode == 'static' + - idempotent_static.previous.0.fvnsVlanInstP.attributes.descr == 'Ansible Test' + - idempotent_static.previous.0.fvnsVlanInstP.attributes.dn == 'uni/infra/vlanns-[anstest]-static' + - idempotent_static.previous.0.fvnsVlanInstP.attributes.name == 'anstest' + - idempotent_static.sent == {} + +- name: create dynamic vlan pool again - idempotency works + cisco.aci.aci_encap_pool: + <<: *aci_pool_present_dynamic + register: idempotent_dynamic + +- name: assertion test - present + assert: + that: + - idempotent_dynamic is not changed + - idempotent_dynamic.previous.0.fvnsVlanInstP.attributes.allocMode == 'dynamic' + - idempotent_dynamic.previous.0.fvnsVlanInstP.attributes.descr == 'Ansible Test' + - idempotent_dynamic.previous.0.fvnsVlanInstP.attributes.dn == 'uni/infra/vlanns-[anstest]-dynamic' + - idempotent_dynamic.previous.0.fvnsVlanInstP.attributes.name == 'anstest' + - idempotent_dynamic.sent == {} + +- name: update static vlan pool - update works + cisco.aci.aci_encap_pool: + <<: *aci_pool_present_static + descr: Ansible Test Change + register: update_static + +- name: assertion test - present + assert: + that: + - update_static is changed + - update_static.sent.fvnsVlanInstP.attributes.descr == 'Ansible Test Change' + +- name: update dynamic vlan pool - update works + cisco.aci.aci_encap_pool: + <<: *aci_pool_present_dynamic + descr: Ansible Test Change + register: update_dynamic + +- name: assertion test - present + assert: + that: + - update_dynamic is changed + - update_dynamic.sent.fvnsVlanInstP.attributes.descr == 'Ansible Test Change' + +- name: missing param - failure message works + cisco.aci.aci_encap_pool: + <<: *aci_pool_present_dynamic + pool_allocation_mode: "{{ fake_var | default(omit) }}" + ignore_errors: true + register: vlan_alloc_fail + +- name: assertion test - present + assert: + that: + - vlan_alloc_fail is failed + - "vlan_alloc_fail.msg == 'ACI requires parameter \\'pool_allocation_mode\\' for \\'pool_type\\' of \\'vlan\\' and \\'vsan\\' when parameter \\'pool\\' is provided'" + +- name: missing param - failure message works + cisco.aci.aci_encap_pool: + <<: *aci_pool_present_dynamic + pool: "{{ fake_var | default(omit) }}" + ignore_errors: true + register: vlan_pool_fail + +- name: assertion test - present + assert: + that: + - vlan_pool_fail is failed + - 'vlan_pool_fail.msg == "state is present but all of the following are missing: pool"' + +- name: missing param - failure message works + cisco.aci.aci_encap_pool: + <<: *aci_pool_present_dynamic + pool_type: "{{ fake_var | default(omit) }}" + ignore_errors: true + register: vlan_pool_type_fail + +- name: assertion test - present + assert: + that: + - vlan_pool_type_fail is failed + - 'vlan_pool_type_fail.msg == "missing required arguments: pool_type"' + +- name: get all vlan pools - get class works + cisco.aci.aci_encap_pool: + <<: *aci_pool_absent_static + state: query + pool: "{{ fake_var | default(omit) }}" + pool_allocation_mode: "{{ fake_var | default(omit) }}" + register: get_all_pools + +- name: assertion test - query + assert: + that: + - get_all_pools is not changed + - get_all_pools.method == "GET" + - get_all_pools.current | length > 1 + +- name: get created static vlan pool - get mo works + cisco.aci.aci_encap_pool: + <<: *aci_pool_absent_static + state: query + register: get_static_pool + +- name: assertion test - query + assert: + that: + - get_static_pool is not changed + - get_static_pool.method == "GET" + - get_static_pool.current | length == 1 + - get_static_pool.current.0.fvnsVlanInstP.attributes.allocMode == "static" + - get_static_pool.current.0.fvnsVlanInstP.attributes.name == "anstest" + +- name: get created dynamic vlan pool - get mo works + cisco.aci.aci_encap_pool: + <<: *aci_pool_absent_dynamic + state: query + register: get_dynamic_pool + +- name: assertion test - query + assert: + that: + - get_dynamic_pool is not changed + - get_dynamic_pool.method == "GET" + - get_dynamic_pool.current | length == 1 + - get_dynamic_pool.current.0.fvnsVlanInstP.attributes.allocMode == "dynamic" + - get_dynamic_pool.current.0.fvnsVlanInstP.attributes.name == "anstest" + +- name: get created dynamic vlan pool - get mo works + cisco.aci.aci_encap_pool: + <<: *aci_pool_absent_dynamic + state: query + pool_type: "{{ fake_var | default(omit) }}" + ignore_errors: true + register: vlan_query_pool_type_fail + +- name: assertion test - query + assert: + that: + - vlan_query_pool_type_fail is failed + - 'vlan_query_pool_type_fail.msg == "missing required arguments: pool_type"' + +- name: delete static vlan pool - deletion works + cisco.aci.aci_encap_pool: + <<: *aci_pool_absent_static + register: delete_static + +- name: assertion test - absent + assert: + that: + - delete_static is changed + - delete_static.method == "DELETE" + - delete_static.previous.0.fvnsVlanInstP.attributes.allocMode == "static" + - delete_static.previous.0.fvnsVlanInstP.attributes.name == "anstest" + +- name: delete dynamic vlan pool - check mode works + cisco.aci.aci_encap_pool: + <<: *aci_pool_absent_dynamic + check_mode: true + register: delete_check_mode + +- name: assertion test - absent + assert: + that: + - delete_check_mode is changed + +- name: delete dynamic vlan pool - deletion works + cisco.aci.aci_encap_pool: + <<: *aci_pool_absent_dynamic + register: delete_dynamic + +- name: assertion test - absent + assert: + that: + - delete_dynamic is changed + - delete_dynamic.method == "DELETE" + - delete_dynamic.previous.0.fvnsVlanInstP.attributes.allocMode == "dynamic" + - delete_dynamic.previous.0.fvnsVlanInstP.attributes.name == "anstest" + +- name: delete static vlan pool again - idempotency works + cisco.aci.aci_encap_pool: + <<: *aci_pool_absent_static + register: idempotent_delete_static + +- name: assertion test - absent + assert: + that: + - idempotent_delete_static is not changed + - idempotent_delete_static.previous == [] + +- name: delete dynamic vlan pool again - idempotency works + cisco.aci.aci_encap_pool: + <<: *aci_pool_absent_dynamic + register: idempotent_delete_dynamic + +- name: assertion test - absent + assert: + that: + - idempotent_delete_dynamic is not changed + - idempotent_delete_dynamic.previous == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool/tasks/vsan.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool/tasks/vsan.yml new file mode 100644 index 000000000..846818731 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool/tasks/vsan.yml @@ -0,0 +1,16 @@ +--- +- name: ensure vlan pool does not exist for tests to kick off + cisco.aci.aci_encap_pool: &aci_pool_absent_static + 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") }}' + pool: anstest + pool_type: vsan + pool_allocation_mode: static + state: absent + +# FIXME: Add Test to this integration
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool/tasks/vxlan.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool/tasks/vxlan.yml new file mode 100644 index 000000000..6467af376 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool/tasks/vxlan.yml @@ -0,0 +1,179 @@ +--- +- name: ensure vxlan pool anstest does not exist for tests to kick off + cisco.aci.aci_encap_pool: &aci_vxlan_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 + state: absent + pool: anstest + pool_type: vxlan + +- name: ensure vxlan pool anstest_2 does not exist for tests to kick off + cisco.aci.aci_encap_pool: + <<: *aci_vxlan_absent + pool: anstest_2 + +- name: ensure vxlan pool anstest_3 does not exist for tests to kick off + cisco.aci.aci_encap_pool: + <<: *aci_vxlan_absent + pool: anstest_3 + +- name: create vxlan pool - check mode works + cisco.aci.aci_encap_pool: &aci_vxlan_present + <<: *aci_vxlan_absent + state: present + descr: Ansible Test + check_mode: true + register: create_vxlan_check_mode + +- name: assertion test - present + assert: + that: + - create_vxlan_check_mode is changed + - create_vxlan_check_mode.sent.fvnsVxlanInstP.attributes.descr == 'Ansible Test' + - create_vxlan_check_mode.sent.fvnsVxlanInstP.attributes.name == 'anstest' + +- name: create vxlan pool - creation works + cisco.aci.aci_encap_pool: + <<: *aci_vxlan_present + register: create_vxlan + +- name: assertion test - present + assert: + that: + - create_vxlan is changed + - create_vxlan.previous == [] + - create_vxlan.sent == create_vxlan_check_mode.sent + - create_vxlan.current.0.fvnsVxlanInstP.attributes.annotation == 'orchestrator:ansible' + +- name: create vxlan pool again - idempotency works + cisco.aci.aci_encap_pool: + <<: *aci_vxlan_present + register: idempotent_vxlan + +- name: assertion test - present + assert: + that: + - idempotent_vxlan is not changed + - idempotent_vxlan.previous.0.fvnsVxlanInstP.attributes.name == 'anstest' + - idempotent_vxlan.sent == {} + +- name: update vxlan pool - update works + cisco.aci.aci_encap_pool: + <<: *aci_vxlan_present + descr: Ansible Test Change + register: update_vxlan + +- name: assertion test - present + assert: + that: + - update_vxlan is changed + - update_vxlan.sent.fvnsVxlanInstP.attributes.descr == 'Ansible Test Change' + +- name: create vxlan pool - used for query + cisco.aci.aci_encap_pool: + <<: *aci_vxlan_present + name: anstest_2 + register: create_vxlan_2 + +- name: assertion test - present + assert: + that: + - create_vxlan_2 is changed + +- name: create vxlan pool with pool allocation mode - failure message works + cisco.aci.aci_encap_pool: + <<: *aci_vxlan_present + name: anstest_3 + pool_allocation_mode: dynamic + ignore_errors: true + register: create_vxlan_alloc_mode + +- name: assertion test - present + assert: + that: + - create_vxlan_alloc_mode is failed + - "create_vxlan_alloc_mode.msg == 'vxlan pools do not support setting the \\'pool_allocation_mode\\'; please remove this parameter from the task'" + +- name: get vxlan pool - get object works + cisco.aci.aci_encap_pool: &aci_vxlan_query + <<: *aci_vxlan_present + state: query + register: query_vxlan + +- name: assertion test - query + assert: + that: + - query_vxlan is not changed + - query_vxlan.current | length == 1 + - '"infra/vxlanns-anstest.json" in query_vxlan.url' + +- name: get created static vlan pool - get class works + cisco.aci.aci_encap_pool: + <<: *aci_vxlan_query + pool: "{{ fake_var | default(omit) }}" + register: query_vxlan_all + +- name: assertion test - query + assert: + that: + - query_vxlan_all is not changed + - query_vxlan_all.current | length > 1 + - '"class/fvnsVxlanInstP.json" in query_vxlan_all.url' + +- name: delete vxlan pool - check mode works + cisco.aci.aci_encap_pool: + <<: *aci_vxlan_absent + check_mode: true + register: delete_vxlan_check_mode + +- name: assertion test - absent + assert: + that: + - delete_vxlan_check_mode is changed + - delete_vxlan_check_mode.previous != [] + +- name: delete vxlan pool - deletion works + cisco.aci.aci_encap_pool: + <<: *aci_vxlan_absent + register: delete_vxlan + +- name: assertion test - absent + assert: + that: + - delete_vxlan is changed + - delete_vxlan.previous == delete_vxlan_check_mode.previous + - delete_vxlan.previous.0.fvnsVxlanInstP.attributes.name == "anstest" + +- name: delete vxlan pool again - idempotency works + cisco.aci.aci_encap_pool: + <<: *aci_vxlan_absent + register: delete_vxlan_idempotent + +- name: missing param - failure message works + cisco.aci.aci_encap_pool: + <<: *aci_vxlan_absent + pool: "{{ fake_var | default(omit) }}" + ignore_errors: true + register: delete_vxlan_pool_fail + +- name: assertion test - absent + assert: + that: + - delete_vxlan_idempotent is not changed + - delete_vxlan_idempotent.previous == [] + +- name: delete vxlan pool - cleanup + cisco.aci.aci_encap_pool: + <<: *aci_vxlan_absent + pool: anstest_2 + +- name: assertion test - absent + assert: + that: + - delete_vxlan_pool_fail is failed + - 'delete_vxlan_pool_fail.msg == "state is absent but all of the following are missing: pool"' diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/main.yml new file mode 100644 index 000000000..005628c5d --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/main.yml @@ -0,0 +1,24 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) + +# 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 + block: # block specifies execution of tasks within, based on conditions + - include_tasks: vlan.yml + when: "vlan is not defined or (vlan is defined and vlan == 'True')" + + - include_tasks: vxlan.yml + when: "vxlan is not defined or (vxlan is defined and vxlan == 'True')" + + - include_tasks: vsan.yml + when: "vsan is not defined or (vsan is defined and vsan == 'True')" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/vlan.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/vlan.yml new file mode 100644 index 000000000..6af58bf5d --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/vlan.yml @@ -0,0 +1,388 @@ +- name: ensure vlan pool exists for tests to kick off + cisco.aci.aci_encap_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") }}' + state: absent + pool: anstest + pool_type: vlan + allocation_mode: static + description: Ansible Test + +- name: ensure vlan pool exists for tests to kick off + 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: debug + state: present + pool: anstest + pool_type: vlan + allocation_mode: static + description: Ansible Test + register: pool_present + +- name: create vlan pool range - check mode works + cisco.aci.aci_encap_pool_range: &aci_range_present + <<: *aci_pool_present + range_name: anstest + range_start: 20 + range_end: 40 + pool: anstest + pool_allocation_mode: static + allocation_mode: inherit + description: Ansible Test + check_mode: true + register: range_present_check_mode + +- name: present assertions + assert: + that: + - range_present_check_mode is changed + - range_present_check_mode.sent.fvnsEncapBlk.attributes.allocMode == 'inherit' + - range_present_check_mode.sent.fvnsEncapBlk.attributes.descr == 'Ansible Test' + - range_present_check_mode.sent.fvnsEncapBlk.attributes.name == 'anstest' + - range_present_check_mode.sent.fvnsEncapBlk.attributes.from == 'vlan-20' + - range_present_check_mode.sent.fvnsEncapBlk.attributes.to == 'vlan-40' + +- name: create vlan pool range - creation works + cisco.aci.aci_encap_pool_range: + <<: *aci_range_present + register: range_present + +- name: present assertions + assert: + that: + - range_present is changed + - range_present.previous == [] + - range_present.sent == range_present_check_mode.sent + - range_present.sent == range_present.proposed + - range_present.current.0.fvnsEncapBlk.attributes.annotation == 'orchestrator:ansible' + +- name: create vlan pool range - idempotency works + cisco.aci.aci_encap_pool_range: + <<: *aci_range_present + register: range_present_idempotent + +- name: present assertions + assert: + that: + - range_present_idempotent is not changed + - range_present_idempotent.previous.0.fvnsEncapBlk.attributes.name == "anstest" + +- name: update vlan pool range - update works + cisco.aci.aci_encap_pool_range: + <<: *aci_range_present + description: Ansible Test Update + allocation_mode: inherit + register: range_present_update + +- name: present assertions + assert: + that: + - range_present_update is changed + - range_present_update.previous != [] + - range_present_update.sent != range_present.sent + +- name: create vlan pool range - used for query + cisco.aci.aci_encap_pool_range: &aci_range_present_2 + <<: *aci_range_present + range_name: anstest_2 + range_start: 50 + range_end: 55 + register: range_present_2 + +- name: present assertions + assert: + that: + - range_present_2 is changed + - range_present_2.previous == [] + +- name: invalid range_start - error message works + cisco.aci.aci_encap_pool_range: + <<: *aci_range_present + range_start: 0 + ignore_errors: true + register: range_start_low + +- name: present assertions + assert: + that: + - range_start_low is failed + - range_start_low.msg == 'vlan pools must have "range_start" and "range_end" values between 1 and 4094' + +- name: invalid range_start - error message works + cisco.aci.aci_encap_pool_range: + <<: *aci_range_present + range_start: 4096 + ignore_errors: true + register: range_start_high + +- name: present assertions + assert: + that: + - range_start_high is failed + - range_start_high.msg == 'vlan pools must have "range_start" and "range_end" values between 1 and 4094' + +- name: invalid range_end - error message works + cisco.aci.aci_encap_pool_range: + <<: *aci_range_present + range_end: 0 + ignore_errors: true + register: range_end_low + +- name: present assertions + assert: + that: + - range_end_low is failed + - range_end_low.msg == 'vlan pools must have "range_start" and "range_end" values between 1 and 4094' + +- name: invalid range_end - error message works + cisco.aci.aci_encap_pool_range: + <<: *aci_range_present + range_end: 4096 + ignore_errors: true + register: range_end_high + +- name: present assertions + assert: + that: + - range_end_high is failed + - range_end_high.msg == 'vlan pools must have "range_start" and "range_end" values between 1 and 4094' + +- name: range start higher than range end - error message works + cisco.aci.aci_encap_pool_range: + <<: *aci_range_present + range_start: 1000 + ignore_errors: true + register: range_start_end + +- name: present assertions + assert: + that: + - range_start_end is failed + - range_start_end.msg == 'The "range_start" must be less than or equal to the "range_end"' + +- name: missing required param - error message works + cisco.aci.aci_encap_pool_range: + <<: *aci_range_present + pool_type: '{{ omit }}' + ignore_errors: true + register: range_present_pool_type + +- name: present assertions + assert: + that: + - range_present_pool_type is failed + - "range_present_pool_type.msg == 'missing required arguments: pool_type'" + +- name: missing required param - error message works + cisco.aci.aci_encap_pool_range: + <<: *aci_pool_present + ignore_errors: true + register: range_present_missing_param + +- name: present assertions + assert: + that: + - range_present_missing_param is failed + - "range_present_missing_param.msg == 'state is present but all of the following are missing: range_end, range_start'" + +- name: missing required param - error message works + cisco.aci.aci_encap_pool_range: + <<: *aci_range_present + pool_allocation_mode: '{{ omit }}' + ignore_errors: true + register: range_present_allocation + +- name: present assertions + assert: + that: + - range_present_allocation is failed + - range_present_allocation.msg == 'ACI requires the "pool_allocation_mode" for "pool_type" of "vlan" and "vsan" when the "pool" is provided' + +- name: query specific vlan pool range + cisco.aci.aci_encap_pool_range: &aci_range_query + <<: *aci_range_present + state: query + register: range_query + +- name: query assertions + assert: + that: + - range_query is not changed + - range_query.url.endswith("infra/vlanns-[anstest]-static/from-[vlan-20]-to-[vlan-40].json") + - range_query.current | length == 1 + - range_query.current.0.fvnsEncapBlk.attributes.name == "anstest" + +- name: query vlan pool range - from, to, and name are filtered + cisco.aci.aci_encap_pool_range: &aci_range_query_filter + <<: *aci_range_query + pool: '{{ omit }}' + register: range_query_from_to_name + +- name: query assertions + assert: + that: + - range_query_from_to_name is not changed + - range_query_from_to_name.url.endswith("class/fvnsEncapBlk.json") + - '"eq(fvnsEncapBlk.from,\"vlan-20\")" in range_query_from_to_name.filter_string' + - '"eq(fvnsEncapBlk.name,\"anstest\")" in range_query_from_to_name.filter_string' + - '"eq(fvnsEncapBlk.to,\"vlan-40\")" in range_query_from_to_name.filter_string' + - range_query_from_to_name.current.0.fvnsEncapBlk.attributes.name == "anstest" + - range_query_from_to_name.current.0.fvnsEncapBlk.attributes.from == "vlan-20" + - range_query_from_to_name.current.0.fvnsEncapBlk.attributes.to == "vlan-40" + +- name: query vlan pool range - from and name are filtered + cisco.aci.aci_encap_pool_range: + <<: *aci_range_query_filter + range_end: '{{ omit }}' + register: range_query_from_name + +- name: query assertions + assert: + that: + - range_query_from_name is not changed + - range_query_from_name.url.endswith("class/fvnsEncapBlk.json") + - '"eq(fvnsEncapBlk.from,\"vlan-20\")" in range_query_from_name.filter_string' + - '"eq(fvnsEncapBlk.name,\"anstest\")" in range_query_from_name.filter_string' + - range_query_from_name.current.0.fvnsEncapBlk.attributes.name == "anstest" + - range_query_from_name.current.0.fvnsEncapBlk.attributes.from == "vlan-20" + +- name: query vlan pool range - to and name are filtered + cisco.aci.aci_encap_pool_range: + <<: *aci_range_query_filter + range_start: '{{ omit }}' + register: range_query_to_name + +- name: query assertions + assert: + that: + - range_query_to_name is not changed + - range_query_to_name.url.endswith('class/fvnsEncapBlk.json') + - '"eq(fvnsEncapBlk.name,\"anstest\")" in range_query_to_name.filter_string' + - '"eq(fvnsEncapBlk.to,\"vlan-40\")" in range_query_to_name.filter_string' + - range_query_to_name.current.0.fvnsEncapBlk.attributes.name == "anstest" + - range_query_to_name.current.0.fvnsEncapBlk.attributes.to == "vlan-40" + +- name: query vlan pool range - name is filtered + cisco.aci.aci_encap_pool_range: + <<: *aci_range_query_filter + range_start: '{{ omit }}' + range_end: '{{ omit }}' + register: range_query_name + +- name: query assertions + assert: + that: + - range_query_name is not changed + - range_query_name.url.endswith("class/fvnsEncapBlk.json") + - '"eq(fvnsEncapBlk.name,\"anstest\")" in range_query_name.filter_string' + - range_query_name.current.0.fvnsEncapBlk.attributes.name == "anstest" + +- name: query vlan pool range - from and to are filtered + cisco.aci.aci_encap_pool_range: + <<: *aci_range_query_filter + range_name: '{{ omit }}' + register: range_query_from_to + +- name: query assertions + assert: + that: + - range_query_from_to is not changed + - range_query_from_to.url.endswith("class/fvnsEncapBlk.json") + - '"eq(fvnsEncapBlk.from,\"vlan-20\")" in range_query_from_to.filter_string' + - '"eq(fvnsEncapBlk.to,\"vlan-40\")" in range_query_from_to.filter_string' + - range_query_from_to.current.0.fvnsEncapBlk.attributes.from == "vlan-20" + - range_query_from_to.current.0.fvnsEncapBlk.attributes.to == "vlan-40" + +- name: query all ranges in a vlan pool + cisco.aci.aci_encap_pool_range: + <<: *aci_pool_present + state: query + pool_allocation_mode: static + register: range_query_pool + +- name: query assertions + assert: + that: + - range_query_pool.current | length == 1 + - range_query_pool.current.0.fvnsVlanInstP.attributes.name == "anstest" + - range_query_pool.current.0.fvnsVlanInstP.children | length > 1 + - range_query_pool.url.endswith("infra/vlanns-[anstest]-static.json") + +- name: query all ranges + cisco.aci.aci_encap_pool_range: + <<: *aci_pool_present + state: query + pool: '{{ omit }}' + register: range_query_all + +- name: query assertions + assert: + that: + - range_query_all is not changed + - range_query_all.current | length > 1 + - range_query_all.current.0.fvnsEncapBlk is defined + - range_query_all.url.endswith("class/fvnsEncapBlk.json") + +- name: delete vlan pool range - deletion works + cisco.aci.aci_encap_pool_range: + <<: *aci_range_present + state: absent + register: delete_range + +- name: absent assertions + assert: + that: + - delete_range is changed + - delete_range.proposed == {} + - delete_range.previous.0.fvnsEncapBlk.attributes.name == "anstest" + +- name: delete vlan pool range - check mode works + cisco.aci.aci_encap_pool_range: &aci_range_absent + <<: *aci_range_present_2 + state: absent + check_mode: true + register: delete_check_mode + +- name: absent assertions + assert: + that: + - delete_check_mode is changed + - delete_check_mode.previous != [] + +- name: delete vlan pool range - deletion works + cisco.aci.aci_encap_pool_range: + <<: *aci_range_absent + register: delete_range_2 + +- name: absent assertions + assert: + that: + - delete_range_2 is changed + - delete_range_2.previous == delete_check_mode.previous + +- name: delete vlan pool range again - idempotency works + cisco.aci.aci_encap_pool_range: + <<: *aci_range_absent + register: delete_idempotent + +- name: absent assertions + assert: + that: + - delete_idempotent is not changed + - delete_idempotent.previous == [] + +- name: cleanup vlan pool + 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/vsan.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/vsan.yml new file mode 100644 index 000000000..7bdc332c5 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/vsan.yml @@ -0,0 +1,20 @@ +- name: ensure vsan pool exists for tests to kick off + 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") }}' + pool: anstest + pool_type: vsan + allocation_mode: static + description: Ansible Test + state: present + +- name: cleanup vsan pool + 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 new file mode 100644 index 000000000..e5e301916 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_encap_pool_range/tasks/vxlan.yml @@ -0,0 +1,19 @@ +- name: ensure vxlan pool exists for tests to kick off + 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") }}' + pool: anstest + pool_type: vxlan + description: Ansible Test + state: present + +- name: cleanup vxlan pool + 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/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg/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/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg/tasks/main.yml new file mode 100644 index 000000000..ffd3ac599 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg/tasks/main.yml @@ -0,0 +1,316 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) +# Copyright: (c) 2020, Shreyas Srish (@shrsr) + +# 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 + 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 + tenant: ansible_test + register: tenant_present + + - name: ensure monitoring policy exists + cisco.aci.aci_epg_monitoring_policy: + 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 + monitoring_policy: check + tenant: ansible_test + + - name: ensure bd exists for tests to kick off + cisco.aci.aci_bd: &aci_bd_present + <<: *aci_tenant_present + bd: anstest + register: bd_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: create epg - check mode works + cisco.aci.aci_epg: &aci_epg_present + <<: *aci_ap_present + epg: anstest + bd: anstest + description: Ansible Test + monitoring_policy: check + custom_qos_policy: check + check_mode: true + register: epg_present_check_mode + + - name: create epg - creation works + cisco.aci.aci_epg: + <<: *aci_epg_present + register: epg_present + + - name: create epg - idempotency works + cisco.aci.aci_epg: + <<: *aci_epg_present + register: epg_present_idempotent + + - name: update epg - update works + cisco.aci.aci_epg: + <<: *aci_epg_present + description: Ansible Test Update + register: epg_present_update + + - name: create epg - missing param + cisco.aci.aci_epg: + <<: *aci_epg_present + ap: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: epg_present_missing_param + + - name: create epg - used for query + cisco.aci.aci_epg: + <<: *aci_epg_present + epg: anstest2 + + - name: present assertions + assert: + that: + - epg_present_check_mode is changed + - epg_present_check_mode.previous == [] + - epg_present_check_mode.sent.fvAEPg.attributes != {} + - epg_present_check_mode.sent.fvAEPg.children.0.fvRsBd.attributes.tnFvBDName == "anstest" + - epg_present_check_mode.sent.fvAEPg.children.1.fvRsAEPgMonPol.attributes.tnMonEPGPolName == 'check' + - epg_present_check_mode.sent.fvAEPg.children.2.fvRsCustQosPol.attributes.tnQosCustomPolName == 'check' + - epg_present is changed + - epg_present.sent == epg_present_check_mode.sent + - epg_present.current.0.fvAEPg.attributes.annotation == 'orchestrator:ansible' + - epg_present_idempotent is not changed + - epg_present_idempotent.sent == {} + - epg_present_update is changed + - epg_present_update.sent.fvAEPg.attributes.descr == 'Ansible Test Update' + - epg_present_missing_param is failed + - 'epg_present_missing_param.msg == "state is present but all of the following are missing: ap"' + + - name: get specific epg + cisco.aci.aci_epg: + <<: *aci_epg_present + state: query + register: epg_query + + - name: get all epgs + cisco.aci.aci_epg: + <<: *aci_tenant_present + state: query + tenant: "{{ fakevar | default(omit) }}" + register: epg_query_all + + - name: query assertions + assert: + that: + - epg_query is not changed + - epg_query.current | length == 1 + - epg_query.current.0.fvAEPg.attributes.name == "anstest" + - epg_query.current.0.fvAEPg.children.1.fvRsCustQosPol.attributes.tnQosCustomPolName == 'check' + - epg_query.current.0.fvAEPg.children.2.fvRsAEPgMonPol.attributes.tnMonEPGPolName == 'check' + - '"tn-ansible_test/ap-anstest/epg-anstest.json" in epg_query.url' + - epg_query_all is not changed + - epg_query_all.current | length > 1 + - '"?rsp-subtree=full&rsp-subtree-class=fvRsAEPgMonPol,fvRsBd" in epg_query_all.filter_string' + - '"class/fvAEPg.json" in epg_query_all.url' + + - name: delete epg - check mode works + cisco.aci.aci_epg: &aci_epg_absent + <<: *aci_epg_present + state: absent + check_mode: true + register: delete_epg_check_mode + + - name: delete epg - delete works + cisco.aci.aci_epg: + <<: *aci_epg_absent + register: delete_epg + + - name: delete epg - idempotency works + cisco.aci.aci_epg: + <<: *aci_epg_absent + register: delete_epg_idempotent + + - name: delete epg - cleanup extra epg + cisco.aci.aci_epg: + <<: *aci_epg_absent + epg: anstest2 + + - name: delete epg - missing param fails + cisco.aci.aci_epg: + <<: *aci_epg_absent + tenant: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: delete_epg_missing_param + + - name: query assertions + assert: + that: + - delete_epg_check_mode is changed + - delete_epg_check_mode.previous != [] + - delete_epg is changed + - delete_epg.previous == delete_epg_check_mode.previous + - delete_epg_idempotent is not changed + - delete_epg_idempotent.previous == [] + - delete_epg_missing_param is failed + - 'delete_epg_missing_param.msg == "state is absent but all of the following are missing: tenant"' + + - name: create microsegmented epg with check mode + cisco.aci.aci_epg: &cm_useg_epg_present + <<: *aci_ap_present + epg: anstest_useg_epg + bd: anstest + useg: yes + description: uSeg EPG Ansible Test + check_mode: true + register: cm_useg_epg_present + + - name: Assertions check for create microsegmented epg with check mode + assert: + that: + - cm_useg_epg_present is changed + - cm_useg_epg_present.current == [] + - cm_useg_epg_present.previous == [] + - cm_useg_epg_present.sent.fvAEPg.attributes.name == 'anstest_useg_epg' + - cm_useg_epg_present.sent.fvAEPg.attributes.isAttrBasedEPg == 'yes' + - cm_useg_epg_present.sent.fvAEPg.children.0.fvRsBd.attributes.tnFvBDName == 'anstest' + + - name: create microsegmented epg with normal mode + cisco.aci.aci_epg: &nm_useg_epg_present + <<: *cm_useg_epg_present + register: nm_useg_epg_present + + - name: Assertions check for create microsegmented epg with normal mode + assert: + that: + - nm_useg_epg_present is changed + - nm_useg_epg_present.current | length == 1 + - nm_useg_epg_present.previous == [] + - nm_useg_epg_present.current.0.fvAEPg.attributes.name == 'anstest_useg_epg' + - nm_useg_epg_present.current.0.fvAEPg.attributes.isAttrBasedEPg == 'yes' + - nm_useg_epg_present.current.0.fvAEPg.children.0.fvRsBd.attributes.tnFvBDName == 'anstest' + - nm_useg_epg_present.sent.fvAEPg.attributes.name == 'anstest_useg_epg' + - nm_useg_epg_present.sent.fvAEPg.attributes.isAttrBasedEPg == 'yes' + - nm_useg_epg_present.sent.fvAEPg.children.0.fvRsBd.attributes.tnFvBDName == 'anstest' + + - name: create microsegmented epg with normal mode - idempotency works + cisco.aci.aci_epg: + <<: *cm_useg_epg_present + register: idempotency_nm_useg_epg_present + + - name: Idempotency assertions check for create microsegmented epg with normal mode + assert: + that: + - idempotency_nm_useg_epg_present is not changed + - idempotency_nm_useg_epg_present.current | length == 1 + - idempotency_nm_useg_epg_present.previous | length == 1 + - idempotency_nm_useg_epg_present.current.0.fvAEPg.attributes.name == 'anstest_useg_epg' + - idempotency_nm_useg_epg_present.previous.0.fvAEPg.attributes.name == 'anstest_useg_epg' + - idempotency_nm_useg_epg_present.current.0.fvAEPg.attributes.isAttrBasedEPg == 'yes' + - idempotency_nm_useg_epg_present.previous.0.fvAEPg.attributes.isAttrBasedEPg == 'yes' + - idempotency_nm_useg_epg_present.current.0.fvAEPg.children.0.fvRsBd.attributes.tnFvBDName == 'anstest' + - idempotency_nm_useg_epg_present.previous.0.fvAEPg.children.0.fvRsBd.attributes.tnFvBDName == 'anstest' + + - name: get anstest_useg_epg epg + cisco.aci.aci_epg: + <<: *nm_useg_epg_present + state: query + register: useg_epg_present + + - name: Assertions check for query microsegmented epg with normal mode + assert: + that: + - useg_epg_present is not changed + - useg_epg_present.current | length == 1 + - useg_epg_present.current.0.fvAEPg.attributes.name == 'anstest_useg_epg' + - useg_epg_present.current.0.fvAEPg.attributes.isAttrBasedEPg == 'yes' + - useg_epg_present.current.0.fvAEPg.children.0.fvRsBd.attributes.tnFvBDName == 'anstest' + + - name: delete microsegmented epg with check mode + cisco.aci.aci_epg: &cm_useg_epg_absent + <<: *nm_useg_epg_present + state: absent + check_mode: true + register: cm_useg_epg_absent + + - name: Assertions check for delete microsegmented epg with check mode + assert: + that: + - cm_useg_epg_absent is changed + - cm_useg_epg_absent.current | length == 1 + - cm_useg_epg_absent.previous | length == 1 + - cm_useg_epg_absent.current.0.fvAEPg.attributes.name == 'anstest_useg_epg' + - cm_useg_epg_absent.current.0.fvAEPg.attributes.isAttrBasedEPg == 'yes' + - cm_useg_epg_absent.current.0.fvAEPg.children.0.fvRsBd.attributes.tnFvBDName == 'anstest' + - cm_useg_epg_absent.previous.0.fvAEPg.attributes.name == 'anstest_useg_epg' + - cm_useg_epg_absent.previous.0.fvAEPg.attributes.isAttrBasedEPg == 'yes' + - cm_useg_epg_absent.previous.0.fvAEPg.children.0.fvRsBd.attributes.tnFvBDName == 'anstest' + + - name: delete microsegmented epg with normal mode + cisco.aci.aci_epg: &nm_useg_epg_absent + <<: *cm_useg_epg_absent + state: absent + register: nm_useg_epg_absent + + - name: Assertions check for delete microsegmented epg with normal mode + assert: + that: + - nm_useg_epg_absent is changed + - nm_useg_epg_absent.current | length == 0 + - nm_useg_epg_absent.previous | length == 1 + - nm_useg_epg_absent.previous.0.fvAEPg.attributes.name == 'anstest_useg_epg' + - nm_useg_epg_absent.previous.0.fvAEPg.attributes.isAttrBasedEPg == 'yes' + - nm_useg_epg_absent.previous.0.fvAEPg.children.0.fvRsBd.attributes.tnFvBDName == 'anstest' + + - name: delete microsegmented epg with normal mode - idempotency works + cisco.aci.aci_epg: + <<: *nm_useg_epg_absent + register: idempotency_nm_useg_epg_absent + + - name: Idempotency assertions check for delete microsegmented epg with normal mode + assert: + that: + - idempotency_nm_useg_epg_absent is not changed + - idempotency_nm_useg_epg_absent.current | length == 0 + - idempotency_nm_useg_epg_absent.previous | length == 0 + + - name: cleanup bd + cisco.aci.aci_bd: + <<: *aci_bd_present + state: absent + when: bd_present.previous == [] + + - name: cleanup ap + cisco.aci.aci_ap: + <<: *aci_ap_present + state: absent + when: ap_present.previous == [] + + - name: cleanup tenant + cisco.aci.aci_tenant: + <<: *aci_tenant_present + state: absent + when: tenant_present.previous == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_contract/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_contract/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_contract/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_to_contract/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_contract/tasks/main.yml new file mode 100644 index 000000000..ec97334ab --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_contract/tasks/main.yml @@ -0,0 +1,265 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) + +# 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: Ensure contract binding does not exist prior to testing + cisco.aci.aci_epg_to_contract: + 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 + ap: anstest + epg: anstest + contract_type: provider + contract: "anstest_http" + state: absent + +- 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 + 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 + tenant: ansible_test + state: present + register: tenant_present + + - name: ensure contracts exist for tests to kick off + cisco.aci.aci_contract: + <<: *aci_tenant_present + contract: "{{ item }}" + with_items: ["anstest_http", "anstest_https", "anstest_db"] + + - name: ensure ap exists + cisco.aci.aci_ap: &aci_ap_present + <<: *aci_tenant_present + ap: anstest + register: ap_present + + - name: ensure epg exists + cisco.aci.aci_epg: &aci_epg_present + <<: *aci_ap_present + epg: anstest + register: epg_present + + - name: bind contract to epg - check mode works + cisco.aci.aci_epg_to_contract: &aci_epg_provide_present + <<: *aci_epg_present + contract_type: provider + contract: anstest_http + contract_label: anstest_contract_label + subject_label: anstest_subject_label + check_mode: true + register: provide_present_check_mode + + - name: bind contract to epg - provide works + cisco.aci.aci_epg_to_contract: + <<: *aci_epg_provide_present + register: provide_present + + - name: bind contract to epg - consume works + cisco.aci.aci_epg_to_contract: &aci_epg_consume_present + <<: *aci_epg_provide_present + contract_type: consumer + contract: anstest_db + register: consume_present + + - name: bind contract to epg - add additional contract + cisco.aci.aci_epg_to_contract: &aci_epg_provide_present2 + <<: *aci_epg_provide_present + contract: anstest_https + provider_match: at_most_one + contract_label: "{{ fakevar | default(omit) }}" + subject_label: "{{ fakevar | default(omit) }}" + register: provide_present2 + + - name: bind contract to epg - idempotency works + cisco.aci.aci_epg_to_contract: + <<: *aci_epg_provide_present + register: idempotent_present + + - name: missing param - failure message works + cisco.aci.aci_epg_to_contract: + <<: *aci_tenant_present + contract_type: provider + ignore_errors: true + register: missing_param_present + + - name: missing required param - failure message works + cisco.aci.aci_epg_to_contract: + <<: *aci_tenant_present + ignore_errors: true + register: missing_required_present + + - name: incompatible param - failure message works + cisco.aci.aci_epg_to_contract: + <<: *aci_epg_consume_present + provider_match: all + ignore_errors: true + register: incompatible_present + + - name: present assertions + assert: + that: + - provide_present_check_mode is changed + - provide_present_check_mode.sent.fvRsProv.attributes.tnVzBrCPName == 'anstest_http' + - provide_present is changed + - provide_present.sent == provide_present_check_mode.sent + - provide_present.current.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' + - provide_present.previous == [] + - consume_present is changed + - consume_present.previous == [] + - consume_present.sent.fvRsCons.attributes.tnVzBrCPName == 'anstest_db' + - provide_present2 is changed + - provide_present2.previous == [] + - missing_param_present is failed + - 'missing_param_present.msg == "state is present but all of the following are missing: ap, contract, epg"' + - missing_required_present is failed + - 'missing_required_present.msg == "missing required arguments: contract_type"' + - incompatible_present is failed + - incompatible_present.msg == "the 'provider_match' is only configurable for Provided Contracts" + + - name: get binding + cisco.aci.aci_epg_to_contract: + <<: *aci_epg_provide_present2 + state: query + register: query_provide_contract + + - name: get binding + cisco.aci.aci_epg_to_contract: + <<: *aci_epg_consume_present + state: query + register: query_consume_contract + + - name: get all bindings + cisco.aci.aci_epg_to_contract: + <<: *aci_tenant_present + state: query + tenant: "{{ fakevar | default(omit) }}" + contract_type: provider + register: query_all + + - name: missing required param - failure message works + cisco.aci.aci_epg_to_contract: + <<: *aci_tenant_present + state: query + ignore_errors: true + register: missing_required_query + + - name: query assertions + assert: + that: + - query_provide_contract is not changed + - query_provide_contract.current != [] + - '"uni/tn-ansible_test/ap-anstest/epg-anstest/rsprov-anstest_https.json" in query_provide_contract.url' + - query_consume_contract is not changed + - query_consume_contract.current != [] + - '"uni/tn-ansible_test/ap-anstest/epg-anstest/rscons-anstest_db.json" in query_consume_contract.url' + - query_all is not changed + - '"class/fvRsProv.json" in query_all.url' + - missing_required_query is failed + - 'missing_required_query.msg == "missing required arguments: contract_type"' + + - name: delete consume binding - check mode works + cisco.aci.aci_epg_to_contract: &aci_epg_consume_absent + <<: *aci_epg_consume_present + state: absent + check_mode: true + register: consume_absent_check_mode + + - name: delete consume binding - deletion works + cisco.aci.aci_epg_to_contract: + <<: *aci_epg_consume_absent + register: consume_absent + + - name: delete provide binding - deletion works + cisco.aci.aci_epg_to_contract: + <<: *aci_epg_provide_present + state: absent + register: provide_absent + + - name: delete provide binding - deletion works + cisco.aci.aci_epg_to_contract: + <<: *aci_epg_provide_present2 + state: absent + register: provide_absent2 + + - name: delete consume binding - idempotency works + cisco.aci.aci_epg_to_contract: + <<: *aci_epg_consume_absent + register: consume_absent_idempotent + + - name: missing param - failure message works + cisco.aci.aci_epg_to_contract: + <<: *aci_epg_consume_absent + contract: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: missing_param_absent + + - name: missing required param - failure message works + cisco.aci.aci_epg_to_contract: + <<: *aci_epg_consume_absent + contract_type: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: missing_required_absent + + - name: absent assertions + assert: + that: + - consume_absent_check_mode is changed + - consume_absent_check_mode.previous.0.fvRsCons is defined + - consume_absent is changed + - consume_absent.previous == consume_absent_check_mode.previous + - provide_absent is changed + - provide_absent.previous.0.fvRsProv is defined + - provide_absent2 is changed + - consume_absent_idempotent is not changed + - consume_absent_idempotent.previous == [] + - missing_param_absent is failed + - 'missing_param_absent.msg == "state is absent but all of the following are missing: contract"' + - missing_required_absent is failed + - 'missing_required_absent.msg == "missing required arguments: contract_type"' + + - name: cleanup contracts + cisco.aci.aci_contract: + <<: *aci_tenant_present + state: absent + contract: "{{ item }}" + with_items: ["anstest_http", "anstest_https", "anstest_db"] + + - name: cleanup epg + cisco.aci.aci_epg: + <<: *aci_epg_present + state: absent + when: epg_present is changed + + - name: cleanup ap + cisco.aci.aci_ap: + <<: *aci_ap_present + state: absent + when: ap_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_epg_to_contract_interface/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_contract_interface/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_contract_interface/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_to_contract_interface/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_contract_interface/tasks/main.yml new file mode 100644 index 000000000..a7ba64768 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_contract_interface/tasks/main.yml @@ -0,0 +1,196 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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) }}' + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Ensure ansible_test does not exist prior to testing + cisco.aci.aci_tenant: &ansible_test_absent + <<: *aci_info + output_level: debug + tenant: ansible_test + state: absent + +- name: Ensure ansible_test_2 does not exist prior to testing + cisco.aci.aci_tenant: &ansible_test_2_absent + <<: *aci_info + output_level: debug + tenant: ansible_test_2 + state: absent + +- 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 ansible_test exist prior to testing + cisco.aci.aci_tenant: &ansible_test_present + <<: *ansible_test_absent + state: present + + - name: Ensure application profile exist under ansible_test tenant + cisco.aci.aci_ap: &anstest1_ap_present + <<: *ansible_test_present + ap: anstest1_ap + state: present + register: anstest1_ap_present + + - name: Ensure EPG exist under application profile - anstest1_ap + cisco.aci.aci_epg: &anstest1_epg_present + <<: *anstest1_ap_present + epg: anstest1_epg + bd: 'default' + description: Ansible Test + state: present + register: anstest1_epg_present + + - name: Ensure ansible_test_2 exists + cisco.aci.aci_tenant: &ansible_test_2_present + <<: *ansible_test_2_absent + state: present + + - name: Ensure contract exists under ansible_test_2 tenant + cisco.aci.aci_contract: + <<: *ansible_test_2_present + contract: inter_tenant_contract + description: Ansible Test + scope: global + state: present + register: inter_tenant_contract + + - name: Ensure inter_tenant_contract exported from ansible_test_2 to ansible_test + cisco.aci.aci_contract_export: + <<: *aci_info + name: inter_tenant_contract_interface + destination_tenant: ansible_test + contract: inter_tenant_contract + tenant: ansible_test_2 + state: present + register: testcif1 + + - name: Ensure inter_tenant_contract_interface binding exist in anstest1_epg + cisco.aci.aci_epg_to_contract_interface: &contract_interface_binding_present + <<: *aci_info + tenant: ansible_test + ap: anstest1_ap + epg: anstest1_epg + contract_interface: inter_tenant_contract_interface + state: present + register: inter_tenant_contract_interface_present + + - name: Ensure inter_tenant_contract_interface binding with anstest1_epg + assert: + that: + - inter_tenant_contract_interface_present is changed + - inter_tenant_contract_interface_present.current | length == 1 + - inter_tenant_contract_interface_present.current.0.fvRsConsIf.attributes.tnVzCPIfName == 'inter_tenant_contract_interface' + - inter_tenant_contract_interface_present.current.0.fvRsConsIf.attributes.prio == 'unspecified' + - inter_tenant_contract_interface_present.current.0.fvRsConsIf.attributes.annotation == 'orchestrator:ansible' + + - name: Ensure inter_tenant_contract_interface binding with anstest1_epg - idempotency works + cisco.aci.aci_epg_to_contract_interface: + <<: *contract_interface_binding_present + register: idempotency_check + + - name: Verfication of idempotency_check + assert: + that: + - idempotency_check is not changed + + - name: Query a specific consumed contract interface + cisco.aci.aci_epg_to_contract_interface: + <<: *aci_info + tenant: ansible_test + ap: anstest1_ap + epg: anstest1_epg + contract_interface: inter_tenant_contract_interface + state: query + register: single_object_query_result + + - name: Verification of single consumed contract interface + assert: + that: + - single_object_query_result is not changed + - single_object_query_result.current.0.fvRsConsIf.attributes.tnVzCPIfName == 'inter_tenant_contract_interface' + - single_object_query_result.current.0.fvRsConsIf.attributes.tDn == 'uni/tn-ansible_test/cif-inter_tenant_contract_interface' + - single_object_query_result.current.0.fvRsConsIf.attributes.prio == 'unspecified' + - single_object_query_result.current.0.fvRsConsIf.attributes.state == 'formed' + + - name: Query all consumed contract interfaces + cisco.aci.aci_epg_to_contract_interface: + <<: *aci_info + state: query + register: all_object_query_result + + - name: Verification of all consumed contract interface + assert: + that: + - all_object_query_result is not changed + - inter_tenant_contract_interface_present.current | length >= 1 + + - name: delete consumed contract interface + cisco.aci.aci_epg_to_contract_interface: + <<: *contract_interface_binding_present + state: absent + + - name: Ensure temp_contract exists under ansible_test_2 tenant + cisco.aci.aci_contract: + <<: *ansible_test_2_present + contract: temp_contract + description: Ansible Test + scope: global + state: present + + - name: Negative check with invalid consumed contract interface binding with anstest1_epg + cisco.aci.aci_epg_to_contract_interface: + <<: *aci_info + tenant: ansible_test + ap: anstest1_ap + epg: anstest1_epg + contract_interface: temp_contract # contract was not exported, test expected to fail + state: present + ignore_errors: true + + - name: check missing parameters while binding consumed contract interface with anstest1_epg + cisco.aci.aci_epg_to_contract_interface: + <<: *contract_interface_binding_present + contract_interface: "{{ fakevar | default(omit) }}" + state: present + ignore_errors: true + + # cleanup session + - name: delete anstest1_epg_present + cisco.aci.aci_epg: + <<: *anstest1_epg_present + state: absent + + - name: delete anstest1_ap_present + cisco.aci.aci_ap: + <<: *anstest1_ap_present + state: absent + + - name: delete ansible_test + cisco.aci.aci_tenant: + <<: *ansible_test_present + state: absent + + - name: delete ansible_test_2 + cisco.aci.aci_tenant: + <<: *ansible_test_2_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_contract_master/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_contract_master/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_contract_master/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_to_contract_master/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_contract_master/tasks/main.yml new file mode 100644 index 000000000..08a956f96 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_contract_master/tasks/main.yml @@ -0,0 +1,209 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Cindy Zhao (@cizhao) + +# 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 + +# CLEAN ENVIRONMENT +- 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: Ensure tenant doesn't exist + aci_tenant: + <<: *aci_info + state: absent + tenant: ansible_test + register: tenant_absent + +- 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 + aci_tenant: &aci_tenant_present + <<: *aci_info + state: present + tenant: ansible_test + register: tenant_present + + - name: ensure contracts exist for tests to kick off + cisco.aci.aci_contract: + <<: *aci_tenant_present + contract: "{{ item }}" + with_items: ["anstest_http", "anstest_https", "anstest_db"] + + - name: ensure ap exists for tests to kick off + cisco.aci.aci_ap: &aci_ap_present + <<: *aci_tenant_present + ap: "{{ item }}" + register: ap_present + loop: + - anstest + - anstest_2 + + - name: create epg + cisco.aci.aci_epg: &aci_epg_present + <<: *aci_tenant_present + ap: anstest + epg: anstest + register: epg_present + + - name: bind provider contract to epg + cisco.aci.aci_epg_to_contract: + <<: *aci_epg_present + contract_type: provider + contract: anstest_http + + - name: bind consumer contract to epg + cisco.aci.aci_epg_to_contract: &aci_epg_consume_present + <<: *aci_epg_present + contract_type: consumer + contract: anstest_https + + - name: bind consumer contract to epg + cisco.aci.aci_epg_to_contract: + <<: *aci_epg_consume_present + contract_type: consumer + contract: anstest_db + + - name: create epgs + cisco.aci.aci_epg: + <<: *aci_tenant_present + ap: "{{ item.ap }}" + epg: "{{ item.epg }}" + register: inherited_epg_present + loop: + - {ap: 'anstest', epg: 'anstest_2'} + - {ap: 'anstest_2', epg: 'anstest_4'} + - {ap: 'anstest_2', epg: 'anstest_3'} + + - name: bind provider contract to epg_4 + cisco.aci.aci_epg_to_contract: + <<: *aci_tenant_present + ap: anstest_2 + epg: anstest_4 + contract_type: provider + contract: anstest_http + + - name: add contract master + cisco.aci.aci_epg_to_contract_master: + <<: *aci_tenant_present + ap: "{{ item.ap }}" + epg: "{{ item.epg }}" + contract_master_ap: anstest + contract_master_epg: anstest + state: present + register: add_contract_master + loop: + - {ap: 'anstest', epg: 'anstest_2'} + - {ap: 'anstest_2', epg: 'anstest_3'} + + - name: Verify add_contract_master + assert: + that: + - item is changed + - item.current.0.fvRsSecInherited.attributes.tDn == "uni/tn-ansible_test/ap-anstest/epg-anstest" + loop: "{{ add_contract_master.results }}" + + - name: add another contract master + cisco.aci.aci_epg_to_contract_master: + <<: *aci_tenant_present + ap: "{{ item.ap }}" + epg: "{{ item.epg }}" + contract_master_ap: anstest_2 + contract_master_epg: anstest_4 + state: present + register: add_another_contract_master + loop: + - {ap: 'anstest', epg: 'anstest_2'} + - {ap: 'anstest_2', epg: 'anstest_3'} + - name: Verify add_another_contract_master + assert: + that: + - item is changed + - item.current.0.fvRsSecInherited.attributes.tDn == "uni/tn-ansible_test/ap-anstest_2/epg-anstest_4" + loop: "{{ add_another_contract_master.results }}" + + # Query all contract master ! does not work + - name: Query all contract master + cisco.aci.aci_epg_to_contract_master: + <<: *aci_tenant_present + ap: anstest + epg: anstest_2 + state: query + register: query_all + + # Query specific contract master + - name: Query specific contract master + cisco.aci.aci_epg_to_contract_master: + <<: *aci_tenant_present + ap: anstest + epg: anstest_2 + contract_master_ap: anstest_2 + contract_master_epg: anstest_4 + state: query + register: query_specific_contract_master + + - name: Verify query_specific_contract_master + assert: + that: + - query_specific_contract_master is not changed + - query_specific_contract_master.current.0.fvRsSecInherited.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest_2/rssecInherited-[uni/tn-ansible_test/ap-anstest_2/epg-anstest_4]" + - query_specific_contract_master.current.0.fvRsSecInherited.attributes.tDn == "uni/tn-ansible_test/ap-anstest_2/epg-anstest_4" + + # Query specific contract master + - name: Query another specific contract master + cisco.aci.aci_epg_to_contract_master: + <<: *aci_tenant_present + ap: anstest + epg: anstest_2 + contract_master_ap: anstest + contract_master_epg: anstest + state: query + register: query_another_specific_contract_master + + - name: Verify query_another_specific_contract_master + assert: + that: + - query_another_specific_contract_master is not changed + - query_another_specific_contract_master.current.0.fvRsSecInherited.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest_2/rssecInherited-[uni/tn-ansible_test/ap-anstest/epg-anstest]" + - query_another_specific_contract_master.current.0.fvRsSecInherited.attributes.annotation == 'orchestrator:ansible' + - query_another_specific_contract_master.current.0.fvRsSecInherited.attributes.tDn == "uni/tn-ansible_test/ap-anstest/epg-anstest" + + - name: Remove specific contract master + cisco.aci.aci_epg_to_contract_master: + <<: *aci_tenant_present + ap: anstest + epg: anstest_2 + contract_master_ap: anstest + contract_master_epg: anstest + state: absent + register: remove_contract_master + + - name: Verify remove_contract_master + assert: + that: + - remove_contract_master is changed + - remove_contract_master.current == [] + + # Clean up environment + - name: Ensure tenant doesn't exist + aci_tenant: + <<: *aci_info + state: absent + tenant: ansible_test + register: tenant_absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_domain/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_domain/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_domain/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_to_domain/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_domain/tasks/main.yml new file mode 100644 index 000000000..ea482f563 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_epg_to_domain/tasks/main.yml @@ -0,0 +1,735 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.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 + +# CLEAN ENVIRONMENT +- 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: 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: 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_info + tenant: ansible_test + state: present + 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: delete epg to make sure setup is clean + cisco.aci.aci_epg: + <<: *aci_ap_present + epg: anstest + state: absent + + - 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: ensure phys domain exists for tests to kick off + cisco.aci.aci_rest: &aci_rest_phys_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") }}' + method: post + path: api/mo/uni/phys-anstest.json + content: {"physDomP": {"attributes": {}}} + register: phys_domain_post + + - name: ensure vmm domain exists for tests to kick off + cisco.aci.aci_rest: &aci_rest_vmm_domain + <<: *aci_rest_phys_domain + path: api/mo/uni/vmmp-VMware/dom-anstest.json + content: {"vmmDomP": {"attributes": {}}} + register: vmm_domain_post + + - name: ensure l2dom domain exists for tests to kick off + cisco.aci.aci_rest: &aci_rest_l2dom_domain + <<: *aci_rest_phys_domain + path: api/mo/uni/l2dom-anstest.json + content: {"l2extDomP": {"attributes": {}}} + register: l2dom_domain_post + + - name: bind phys domain to epg - check mode works + cisco.aci.aci_epg_to_domain: &aci_epg_to_domain_present + <<: *aci_epg_present + domain: anstest + domain_type: phys + check_mode: true + register: phys_check_mode_present + + - name: bind phys domain to epg - creation works + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + register: phys_present + + - name: bind phys domain to epg - idempotency works + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + register: phys_idempotent + + - name: bind phys domain to epg - update works + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + deploy_immediacy: immediate + register: phys_update + + - name: bind l2dom domain to epg + cisco.aci.aci_epg_to_domain: &aci_epg_to_domain_l2dom_present + <<: *aci_epg_present + domain: anstest + domain_type: l2dom + register: l2_present + + - name: bind vmm domain to epg - creation works + cisco.aci.aci_epg_to_domain: &aci_epg_to_domain_vmm_present + <<: *aci_epg_to_domain_present + domain_type: vmm + vm_provider: vmware + resolution_immediacy: pre-provision + promiscuous: accept + register: vmm_present_promiscuous_accept + + - name: bind vmm domain to epg - creation works + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + domain_type: vmm + vm_provider: vmware + resolution_immediacy: pre-provision + promiscuous: reject + register: vmm_present_promiscuous_reject + + - name: bind vmm domain to epg - missing params + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_vmm_present + vm_provider: "{{ fake_var | default(omit) }}" + ignore_errors: true + register: present_missing_params + + - name: bind vmm domain to epg - valid vlan + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + encap: 1 + register: valid_vlan + + - name: bind vmm domain to epg - valid vlan (primary_encap) + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + primary_encap: 25 + register: valid_vlan_primary_encap + + - name: bind vmm domain to epg - invalid vlan + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + encap: 4097 + ignore_errors: true + register: invalid_vlan + + - name: bind vmm domain to epg - invalid vlan (primary_encap) + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + primary_encap: 4097 + ignore_errors: true + register: invalid_vlan_primary_encap + + - name: bind vmm domain to epg - incompatible params + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + vm_provider: vmware + ignore_errors: true + register: incompatible_params + + - name: Create enhanced lag policy + cisco.aci.aci_rest: &enhanced_lag_policy_present + <<: *aci_info + path: api/node/mo/uni/vmmp-VMware/dom-anstest/vswitchpolcont.json + method: post + content: | + { + "vmmVSwitchPolicyCont": { + "attributes": { + "dn": "uni/vmmp-VMware/dom-anstest/vswitchpolcont", + "status": "created,modified" + }, + "children": [{ + "lacpEnhancedLagPol": { + "attributes": { + "lbmode": "src-dst-ip", + "mode": "active", + "name": "enhanced", + "numLinks": "2" + } + } + }] + } + } + register: add_enhanced_lag_policy + + - name: bind vmm domain to epg - enhanced_lag_policy + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + domain_type: vmm + vm_provider: vmware + enhanced_lag_policy: enhanced + register: enhanced_lag_policy + + - name: Initialize and test active/stanby vmm uplinks + when: version.current.0.topSystem.attributes.version is version('4.2', '>=') + block: + - name: bind vmm domain to epg - vmm_uplink + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + domain_type: vmm + vm_provider: vmware + vmm_uplink_active: [ 1, 2 ] + vmm_uplink_standby: [ 3, 4 ] + register: vmm_uplink + + - name: bind vmm domain to epg - vmm_uplink change standby + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + domain_type: vmm + vm_provider: vmware + vmm_uplink_standby: [ 5, 6 ] + register: vmm_uplink_change_standby + + - name: bind vmm domain to epg - vmm_uplink change active + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + domain_type: vmm + vm_provider: vmware + vmm_uplink_active: [ 3, 4 ] + register: vmm_uplink_change_active + + - name: vmm_uplink assertions + assert: + that: + - vmm_uplink is changed + - vmm_uplink.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.active == "1,2" + - vmm_uplink.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.standby == "3,4" + - vmm_uplink_change_standby is changed + - vmm_uplink_change_standby.previous.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.active == "1,2" + - vmm_uplink_change_standby.previous.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.standby == "3,4" + - vmm_uplink_change_standby.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.active == "1,2" + - vmm_uplink_change_standby.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.standby == "5,6" + - vmm_uplink_change_active is changed + - vmm_uplink_change_active.previous.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.active == "1,2" + - vmm_uplink_change_active.previous.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.standby == "5,6" + - vmm_uplink_change_active.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.active == "3,4" + - vmm_uplink_change_active.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.standby == "5,6" + + - name: bind vmm domain to epg - vmm_uplink change standby to same as active + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + domain_type: vmm + vm_provider: vmware + vmm_uplink_standby: [ 3, 4 ] + register: vmm_uplink_change_active_same_as_standby + ignore_errors: true + + - name: bind vmm domain to epg - vmm_uplink change 0 value + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + domain_type: vmm + vm_provider: vmware + vmm_uplink_active: [ 0 ] + register: vmm_uplink_0_value + + - name: bind vmm domain to epg - vmm_uplink change 32 value + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + domain_type: vmm + vm_provider: vmware + vmm_uplink_active: [ 32 ] + register: vmm_uplink_32_value + + - name: bind vmm domain to epg - vmm_uplink change empty value standby + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + domain_type: vmm + vm_provider: vmware + vmm_uplink_standby: [] + register: vmm_uplink_empty_value_standby + + - name: vmm_uplink assertions + assert: + that: + - vmm_uplink_0_value is changed + - vmm_uplink_0_value.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.active == "0" + - vmm_uplink_32_value is changed + - vmm_uplink_32_value.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.active == "32" + - vmm_uplink_empty_value_standby is changed + - vmm_uplink_empty_value_standby.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.standby == "" + + - name: bind vmm domain to epg - vmm_uplink change empty value active + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + domain_type: vmm + vm_provider: vmware + vmm_uplink_active: [] + ignore_errors: true + register: vmm_uplink_empty_value_active + + - name: bind vmm domain to epg - vmm_uplink change string value + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + domain_type: vmm + vm_provider: vmware + vmm_uplink_active: [ testing ] + ignore_errors: true + register: vmm_uplink_string_value + + - name: bind vmm domain to epg - vmm_uplink change 33 value + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + domain_type: vmm + vm_provider: vmware + vmm_uplink_active: [ 33 ] + ignore_errors: true + register: vmm_uplink_33_value + + - name: vmm_uplink error assertions + assert: + that: + - 'vmm_uplink_change_active_same_as_standby.msg == "APIC Error 120: Invalid Configuration. Uplink Id entered more than once or delimiter was misused."' + - 'vmm_uplink_empty_value_active.msg == "APIC Error 801: property active of uni/tn-ansible_test/ap-anstest/epg-anstest/rsdomAtt-[uni/vmmp-VMware/dom-anstest]/uplinkorder failed validation for value ''''"' + - 'vmm_uplink_string_value.msg == "APIC Error 801: property active of uni/tn-ansible_test/ap-anstest/epg-anstest/rsdomAtt-[uni/vmmp-VMware/dom-anstest]/uplinkorder failed validation for value ''testing''"' + + - name: vmm_uplink error assertions for non-cloud + assert: + that: + - 'vmm_uplink_33_value.msg == "APIC Error 120: Invalid Configuration. Uplink Id can not be higher than 32."' + + - name: change custom epg name + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + domain_type: vmm + vm_provider: vmware + custom_epg_name: anstest_epg + register: custom_epg_name + + - name: Verify custom epg name + assert: + that: + - custom_epg_name.current.0.fvRsDomAtt.attributes.customEpgName == "anstest_epg" + + - name: domain with delimiter + cisco.aci.aci_epg_to_domain: &aci_delimiter + <<: *aci_epg_to_domain_present + domain: "ansdelim_{{ index }}" + domain_type: vmm + vm_provider: vmware + delimiter: "{{ item }}" + register: delimeter + loop: + - "|" + - "~" + - "!" + - "@" + - "^" + - "+" + - "=" + loop_control: + index_var: index + + - name: domain with delimiter not allowed input + cisco.aci.aci_epg_to_domain: + <<: *aci_delimiter + domain: ansdelim_not_allowed + delimiter: not_allowed + register: delimiter_not_allowed + ignore_errors: true + + - name: delete domains with delimiter + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_present + domain: "ansdelim_{{ item }}" + domain_type: vmm + vm_provider: vmware + state: absent + register: delimeter_absent + loop: "{{ range(0, 7, 1)|list }}" + + - name: domains with delimiter assertions + assert: + that: + - delimeter.results.0 is changed + - delimeter.results.0.current.0.fvRsDomAtt.attributes.delimiter == "|" + - delimeter.results.1 is changed + - delimeter.results.1.current.0.fvRsDomAtt.attributes.delimiter == "~" + - delimeter.results.2 is changed + - delimeter.results.2.current.0.fvRsDomAtt.attributes.delimiter == "!" + - delimeter.results.3 is changed + - delimeter.results.3.current.0.fvRsDomAtt.attributes.delimiter == "@" + - delimeter.results.4 is changed + - delimeter.results.4.current.0.fvRsDomAtt.attributes.delimiter == "^" + - delimeter.results.5 is changed + - delimeter.results.5.current.0.fvRsDomAtt.attributes.delimiter == "+" + - delimeter.results.6 is changed + - delimeter.results.6.current.0.fvRsDomAtt.attributes.delimiter == "=" + - delimiter_not_allowed is not changed + - 'delimiter_not_allowed.msg == "value of delimiter must be one of: |, ~, !, @, ^, +, =, got: not_allowed"' + - delimeter_absent.results.0 is changed + - delimeter_absent.results.0.current == [] + - delimeter_absent.results.1 is changed + - delimeter_absent.results.1.current == [] + - delimeter_absent.results.2 is changed + - delimeter_absent.results.2.current == [] + - delimeter_absent.results.3 is changed + - delimeter_absent.results.3.current == [] + - delimeter_absent.results.4 is changed + - delimeter_absent.results.4.current == [] + - delimeter_absent.results.5 is changed + - delimeter_absent.results.5.current == [] + - delimeter_absent.results.6 is changed + - delimeter_absent.results.6.current == [] + + - name: domain with untagged vlan true + cisco.aci.aci_epg_to_domain: &aci_untagged + <<: *aci_epg_to_domain_present + domain: ansuntagged + domain_type: vmm + vm_provider: vmware + untagged_vlan: true + register: untagged_vlan_true + + - name: domain with untagged vlan false + cisco.aci.aci_epg_to_domain: + <<: *aci_untagged + untagged_vlan: false + register: untagged_vlan_false + + - name: delete domain with untagged vlan + cisco.aci.aci_epg_to_domain: + <<: *aci_untagged + state: absent + register: untagged_vlan_absent + + - name: domains with untagged vlan assertions + assert: + that: + - untagged_vlan_true is changed + - untagged_vlan_true.current.0.fvRsDomAtt.attributes.untagged == "yes" + - untagged_vlan_false is changed + - untagged_vlan_false.current.0.fvRsDomAtt.attributes.untagged == "no" + - untagged_vlan_absent is changed + - untagged_vlan_absent.current == [] + + - name: Test domain with port binding + when: version.current.0.topSystem.attributes.version is version('4.2', '>=') + block: + - name: domain with port binding dynamic + cisco.aci.aci_epg_to_domain: &aci_port_binding + <<: *aci_epg_to_domain_present + domain: ansportbind + domain_type: vmm + vm_provider: vmware + port_binding: dynamic + register: port_binding_dynamic + + - name: change domain with port binding to static + cisco.aci.aci_epg_to_domain: + <<: *aci_port_binding + port_binding: static + register: port_binding_static + + - name: change domain with port binding to ephemeral + cisco.aci.aci_epg_to_domain: + <<: *aci_port_binding + port_binding: ephemeral + register: port_binding_ephemeral + + - name: domain with port binding not allowed input + cisco.aci.aci_epg_to_domain: + <<: *aci_port_binding + domain: ansdelim_not_allowed + port_binding: not_allowed + register: port_binding_not_allowed + ignore_errors: true + + - name: delete domain with port binding + cisco.aci.aci_epg_to_domain: + <<: *aci_port_binding + state: absent + register: port_binding_absent + + - name: domains with port binding assertions + assert: + that: + - port_binding_dynamic is changed + - port_binding_dynamic.current.0.fvRsDomAtt.attributes.bindingType == "dynamicBinding" + - port_binding_static is changed + - port_binding_static.current.0.fvRsDomAtt.attributes.bindingType == "staticBinding" + - port_binding_ephemeral is changed + - port_binding_ephemeral.current.0.fvRsDomAtt.attributes.bindingType == "ephemeral" + - port_binding_not_allowed is not changed + - 'port_binding_not_allowed.msg == "value of port_binding must be one of: dynamic, ephemeral, static, got: not_allowed"' + - port_binding_absent is changed + - port_binding_absent.current == [] + + - name: domain with port allocation elastic + cisco.aci.aci_epg_to_domain: &aci_port_allocation + <<: *aci_epg_to_domain_present + domain: ansportalloc + domain_type: vmm + vm_provider: vmware + port_allocation: elastic + register: port_allocation_elastic + + - name: change domain with port allocation to fixed + cisco.aci.aci_epg_to_domain: + <<: *aci_port_allocation + port_allocation: fixed + register: port_allocation_fixed + + - name: domain with port allocation not allowed input + cisco.aci.aci_epg_to_domain: + <<: *aci_port_allocation + domain: ansdelim_not_allowed + port_allocation: not_allowed + register: port_allocation_not_allowed + ignore_errors: true + + - name: delete domain with port allocation + cisco.aci.aci_epg_to_domain: + <<: *aci_port_allocation + state: absent + register: port_allocation_absent + + - name: domains with port allocation assertions + assert: + that: + - port_allocation_elastic is changed + - port_allocation_elastic.current.0.fvRsDomAtt.attributes.portAllocation == "elastic" + - port_allocation_fixed is changed + - port_allocation_fixed.current.0.fvRsDomAtt.attributes.portAllocation == "fixed" + - port_allocation_not_allowed is not changed + - 'port_allocation_not_allowed.msg == "value of port_allocation must be one of: elastic, fixed, got: not_allowed"' + - port_allocation_absent is changed + - port_allocation_absent.current == [] + + - name: domain with number of ports of 2 + cisco.aci.aci_epg_to_domain: &aci_number_port + <<: *aci_epg_to_domain_present + domain: ansportnum + domain_type: vmm + vm_provider: vmware + number_of_ports: 2 + register: number_of_ports_2 + + - name: change domain with number of ports to 3 + cisco.aci.aci_epg_to_domain: + <<: *aci_number_port + number_of_ports: 3 + register: number_of_ports_3 + + - name: delete domain with number of ports + cisco.aci.aci_epg_to_domain: + <<: *aci_number_port + state: absent + register: number_of_ports_absent + + - name: domains with number of ports assertions + assert: + that: + - number_of_ports_2 is changed + - number_of_ports_2.current.0.fvRsDomAtt.attributes.numPorts == "2" + - number_of_ports_3 is changed + - number_of_ports_3.current.0.fvRsDomAtt.attributes.numPorts == "3" + - number_of_ports_absent is changed + - number_of_ports_absent.current == [] + + - name: domain with forged transmits and mac changes + cisco.aci.aci_epg_to_domain: &aci_forged_transmits_and_mac_changes + <<: *aci_epg_to_domain_present + domain: ansforgedmac + domain_type: vmm + vm_provider: vmware + forged_transmits: accept + mac_changes: accept + register: forged_transmits_and_mac_changes_accept + + - name: change domain with forged transmits and mac changes to reject + cisco.aci.aci_epg_to_domain: + <<: *aci_forged_transmits_and_mac_changes + forged_transmits: reject + mac_changes: reject + register: forged_transmits_and_mac_changes_reject + + - name: delete domain with forged transmits and mac changes + cisco.aci.aci_epg_to_domain: + <<: *aci_forged_transmits_and_mac_changes + state: absent + register: forged_transmits_and_mac_changes_absent + + - name: domains with forged transmits and mac changes assertions + assert: + that: + - forged_transmits_and_mac_changes_accept is changed + - forged_transmits_and_mac_changes_accept.current.0.fvRsDomAtt.children.0.vmmSecP.attributes.forgedTransmits == "accept" + - forged_transmits_and_mac_changes_accept.current.0.fvRsDomAtt.children.0.vmmSecP.attributes.macChanges == "accept" + - forged_transmits_and_mac_changes_reject is changed + - forged_transmits_and_mac_changes_reject.current.0.fvRsDomAtt.children.0.vmmSecP.attributes.forgedTransmits == "reject" + - forged_transmits_and_mac_changes_reject.current.0.fvRsDomAtt.children.0.vmmSecP.attributes.macChanges == "reject" + - forged_transmits_and_mac_changes_absent is changed + - forged_transmits_and_mac_changes_absent.current == [] + + - name: present assertions + assert: + that: + - phys_check_mode_present is changed + - phys_present is changed + - phys_present.previous == [] + - phys_present.sent.fvRsDomAtt.attributes.switchingMode == 'native' + - phys_present.current.0.fvRsDomAtt.attributes.annotation == 'orchestrator:ansible' + - '"[uni/phys-anstest].json" in phys_present.url' + - phys_idempotent is not changed + - phys_idempotent.sent == {} + - phys_update is changed + - phys_update.sent.fvRsDomAtt.attributes.instrImedcy == 'immediate' + - vmm_present_promiscuous_accept is changed + - vmm_present_promiscuous_reject is changed + - vmm_present_promiscuous_accept.current.0.fvRsDomAtt.children.0.vmmSecP.attributes.allowPromiscuous == 'accept' + - vmm_present_promiscuous_reject.current.0.fvRsDomAtt.children.0.vmmSecP.attributes.allowPromiscuous == 'reject' + - vmm_present_promiscuous_accept.sent.fvRsDomAtt.attributes.resImedcy == 'pre-provision' + - vmm_present_promiscuous_accept.sent.fvRsDomAtt.attributes.switchingMode == 'native' + - '"[uni/vmmp-VMware/dom-anstest].json" in vmm_present_promiscuous_accept.url' + - present_missing_params is failed + - 'present_missing_params.msg == "domain_type is vmm but all of the following are missing: vm_provider"' + - invalid_vlan is failed + - invalid_vlan.msg == "Valid VLAN assignments are from 1 to 4096" + - incompatible_params is failed + - incompatible_params.msg == "Domain type 'phys' cannot have a 'vm_provider'" + - invalid_vlan_primary_encap.msg == "Valid VLAN assignments are from 1 to 4096" + - '"[uni/l2dom-anstest].json" in l2_present.url' + - valid_vlan_primary_encap.current.0.fvRsDomAtt.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest/rsdomAtt-[uni/phys-anstest]" + - enhanced_lag_policy.current.0.fvRsDomAtt.children | length == 2 + - enhanced_lag_policy.current.0.fvRsDomAtt.children.0.fvAEPgLagPolAtt.children.0.fvRsVmmVSwitchEnhancedLagPol.attributes.tDn == "uni/vmmp-VMware/dom-anstest/vswitchpolcont/enlacplagp-enhanced" + + - name: get domain epg binding + cisco.aci.aci_epg_to_domain: &aci_epg_domain_query + <<: *aci_tenant_present + state: query + tenant: "{{ fake_var | default(omit) }}" + register: binding_query + + - name: query assertions + assert: + that: + - binding_query is not changed + - binding_query.current | length > 1 + - '"class/fvRsDomAtt.json" in binding_query.url' + + - name: delete domain epg binding - check mode + cisco.aci.aci_epg_to_domain: &aci_epg_to_domain_absent + <<: *aci_epg_to_domain_present + state: absent + check_mode: true + register: epg_domain_check_mode_absent + + - name: delete phys domain epg binding - delete works + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_absent + register: epg_domain_absent + + - name: delete vmm domain epg binding - delete works + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_vmm_present + state: absent + register: epg_vmm_domain_absent + + - name: delete domain epg binding - idempotency works + cisco.aci.aci_epg_to_domain: + <<: *aci_epg_to_domain_absent + register: idempotency_absent + + - name: delete domain epg binding - missing param + cisco.aci.aci_epg_to_domain: + <<: *aci_tenant_present + state: absent + ignore_errors: true + register: absent_missing_param + + - name: absent assertions + assert: + that: + - epg_domain_check_mode_absent is changed + - epg_domain_check_mode_absent.previous != [] + - epg_domain_absent is changed + - epg_domain_absent.previous == epg_domain_check_mode_absent.previous + - epg_vmm_domain_absent is changed + - idempotency_absent is not changed + - idempotency_absent.previous == [] + - absent_missing_param is failed + - 'absent_missing_param.msg == "state is absent but all of the following are missing: ap, domain, domain_type, epg"' + + - name: remove vmm domain - cleanup + cisco.aci.aci_rest: + <<: *aci_rest_vmm_domain + method: delete + when: vmm_domain_post is changed + + - name: remove phys domain - cleanup + cisco.aci.aci_rest: + <<: *aci_rest_phys_domain + method: delete + when: phys_domain_post is changed + + - name: remove l2 domain - cleanup + cisco.aci.aci_rest: + <<: *aci_rest_l2dom_domain + method: delete + when: l2dom_domain_post is changed + + - name: remove epg - cleanup + cisco.aci.aci_epg: + <<: *aci_epg_present + state: absent + when: epg_present is changed + + - name: remove ap - cleanup + cisco.aci.aci_ap: + <<: *aci_ap_present + state: absent + when: ap_present is changed + + - name: remove tenant - cleanup + cisco.aci.aci_tenant: + <<: *aci_tenant_present + state: absent + when: tenant_present is changed
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_esg/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_esg/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg/tasks/main.yml new file mode 100644 index 000000000..34a482fa9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg/tasks/main.yml @@ -0,0 +1,306 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Ensure tenant - ansible_test does not exists before testing + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + output_level: debug + tenant: ansible_test + state: absent + +- name: Execute tasks only for ACI v5+ and non-cloud sites + when: + - version.current.0.topSystem.attributes.version is version('5', '>=') + - query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Setup part + - name: Ensure ansible_test - tenant exists + cisco.aci.aci_tenant: &tenant_present + <<: *tenant_absent + state: present + + - name: Ensure ap - application profile exists + cisco.aci.aci_ap: &anstest_ap_present + <<: *tenant_present + ap: anstest_ap + state: present + + - name: Ensure anstest_ap_1 - application profile exists + cisco.aci.aci_ap: &anstest_ap_1_present + <<: *tenant_present + ap: anstest_ap_1 + state: present + + # Test Part + - name: Ensure web_esg_0 - endpoint security group exists with check mode + cisco.aci.aci_esg: &cm_web_esg_0_present + <<: *anstest_ap_present + esg: web_esg_0 + vrf: default + state: present + check_mode: true + register: cm_web_esg_0_present + + - name: Assertions check for add web_esg_0 with check mode + assert: + that: + - cm_web_esg_0_present is changed + - cm_web_esg_0_present.current | length == 0 + - cm_web_esg_0_present.previous | length == 0 + + - name: Ensure web_esg_0 - endpoint security group exists with normal mode + cisco.aci.aci_esg: &nm_web_esg_0_present + <<: *cm_web_esg_0_present + register: nm_web_esg_0_present + + - name: Assertions check for add web_esg_0 with normal mode + assert: + that: + - nm_web_esg_0_present is changed + - nm_web_esg_0_present.current | length == 1 + - nm_web_esg_0_present.previous | length == 0 + - nm_web_esg_0_present.current.0.fvESg.attributes.name == 'web_esg_0' + - nm_web_esg_0_present.current.0.fvESg.attributes.prio == 'unspecified' + - nm_web_esg_0_present.current.0.fvESg.attributes.prefGrMemb == 'exclude' + - nm_web_esg_0_present.current.0.fvESg.attributes.pcEnfPref == 'unenforced' + - nm_web_esg_0_present.current.0.fvESg.attributes.annotation == 'orchestrator:ansible' + - nm_web_esg_0_present.current.0.fvESg.children[0].fvRsScope.attributes.tnFvCtxName == 'default' + + - name: Assertions check for add web_esg_0 with normal mode (v5.2+) + assert: + that: + - nm_web_esg_0_present.current.0.fvESg.attributes.shutdown == 'no' + when: version.current.0.topSystem.attributes.version is version('5.2', '>=') + + - name: Ensure web_esg_0 - endpoint security group exists with normal mode - idempotency works + cisco.aci.aci_esg: + <<: *nm_web_esg_0_present + register: idempotency_web_esg_0_present + + - name: Idempotency assertions check for add web_esg_0 with normal mode + assert: + that: + - idempotency_web_esg_0_present is not changed + - idempotency_web_esg_0_present.current | length == 1 + - idempotency_web_esg_0_present.previous | length == 1 + - idempotency_web_esg_0_present.current.0.fvESg.attributes.name == 'web_esg_0' + + - name: Ensure web_esg_0 - endpoint security group exists under ap(anstest_ap_1_present) + cisco.aci.aci_esg: + <<: *anstest_ap_1_present + esg: web_esg_0 + vrf: default + state: present + register: ap_1_web_esg_0_present + + - name: Assertions check for add web_esg_0 under ap(anstest_ap_1_present) + assert: + that: + - ap_1_web_esg_0_present is changed + - ap_1_web_esg_0_present.current | length == 1 + - ap_1_web_esg_0_present.previous | length == 0 + - ap_1_web_esg_0_present.current.0.fvESg.attributes.name == 'web_esg_0' + - ap_1_web_esg_0_present.current.0.fvESg.attributes.dn == "uni/tn-ansible_test/ap-anstest_ap_1/esg-web_esg_0" + + - name: Ensure web_esg_1 - endpoint security group exists with admin_state(false -> no) - 'Admin Up' on the UI side + cisco.aci.aci_esg: + <<: *anstest_ap_present + esg: web_esg_1 + vrf: default + admin_state: false + state: present + register: web_esg_1_present + when: version.current.0.topSystem.attributes.version is version('5.2', '>=') + + - name: Assertions check for add web_esg_1 + assert: + that: + - web_esg_1_present is changed + - web_esg_1_present.current | length == 1 + - web_esg_1_present.previous | length == 0 + - web_esg_1_present.current.0.fvESg.attributes.name == 'web_esg_1' + - web_esg_1_present.current.0.fvESg.children[0].fvRsScope.attributes.tnFvCtxName == 'default' + - web_esg_1_present.current.0.fvESg.attributes.shutdown == 'no' + - web_esg_1_present.sent.fvESg.attributes.shutdown == 'no' + when: version.current.0.topSystem.attributes.version is version('5.2', '>=') + + - name: Ensure web_esg_2 - endpoint security group exists with admin_state(true -> yes) - 'Admin Shut' on the UI side + cisco.aci.aci_esg: + <<: *anstest_ap_present + esg: web_esg_2 + admin_state: true + vrf: default + state: present + register: web_esg_2_present + when: version.current.0.topSystem.attributes.version is version('5.2', '>=') + + - name: Assertions check for add web_esg_2 + assert: + that: + - web_esg_2_present is changed + - web_esg_2_present.current | length == 1 + - web_esg_2_present.previous | length == 0 + - web_esg_2_present.current.0.fvESg.attributes.name == 'web_esg_2' + - web_esg_2_present.current.0.fvESg.attributes.shutdown == 'yes' + - web_esg_2_present.current.0.fvESg.children[0].fvRsScope.attributes.tnFvCtxName == 'default' + - web_esg_2_present.sent.fvESg.attributes.shutdown == 'yes' + when: version.current.0.topSystem.attributes.version is version('5.2', '>=') + + - name: Query an ESG + cisco.aci.aci_esg: + <<: *anstest_ap_present + esg: web_esg_0 + state: query + register: query_web_esg_0 + + - name: Assertions check for query an ESG(web_esg_0) under ap(anstest_ap) + assert: + that: + - query_web_esg_0 is not changed + - query_web_esg_0.current | length == 1 + - query_web_esg_0.current.0.fvESg.attributes.name == 'web_esg_0' + - query_web_esg_0.current.0.fvESg.attributes.dn == "uni/tn-ansible_test/ap-anstest_ap/esg-web_esg_0" + + - name: Assertions check for query an ESG(web_esg_0) under ap(anstest_ap) (v5.2+) + assert: + that: + - query_web_esg_0.current.0.fvESg.attributes.shutdown == 'no' + when: version.current.0.topSystem.attributes.version is version('5.2', '>=') + + - name: Query all ESGs + cisco.aci.aci_esg: + <<: *aci_info + state: query + register: query_all_esg + + - name: Assertions check for query all ESGs + assert: + that: + - query_all_esg is not changed + - query_all_esg.current | length >= 2 # Count of ESGs added in the above tasks + when: version.current.0.topSystem.attributes.version is version('5.2', '<') + + - name: Assertions check for query all ESGs + assert: + that: + - query_all_esg is not changed + - query_all_esg.current | length >= 4 # Count of ESGs added in the above tasks + when: version.current.0.topSystem.attributes.version is version('5.2', '>=') + + - name: Query all ESGs with a Specific Name + cisco.aci.aci_esg: + <<: *aci_info + esg: web_esg_0 + state: query + register: query_all_esg_with_name + + - name: Assertions check for query all ESGs with a Specific Name + assert: + that: + - query_all_esg_with_name is not changed + - query_all_esg_with_name.current | length >= 2 + + - name: Query all ESGs of an App Profile + cisco.aci.aci_esg: + <<: *aci_info + ap: anstest_ap + state: query + register: query_all_ap_esg + + - name: Assertions check for query all ESGs of an App Profile (<v5.2) + assert: + that: + - query_all_ap_esg is not changed + - query_all_ap_esg.current.0.fvAp.attributes.name == 'anstest_ap' + - query_all_ap_esg.current.0.fvAp.children | length == 1 + when: version.current.0.topSystem.attributes.version is version('5.2', '<') + + - name: Assertions check for query all ESGs of an App Profile (>=v5.2) + assert: + that: + - query_all_ap_esg is not changed + - query_all_ap_esg.current.0.fvAp.attributes.name == 'anstest_ap' + - query_all_ap_esg.current.0.fvAp.children | length == 3 + when: version.current.0.topSystem.attributes.version is version('5.2', '>=') + + - name: Remove an ESG with check mode + cisco.aci.aci_esg: &cm_web_esg_0_absent + <<: *anstest_ap_present + esg: web_esg_0 + state: absent + register: cm_web_esg_0_absent + check_mode: true + + - name: Assertions check for remove an ESG with check mode + assert: + that: + - cm_web_esg_0_absent is changed + - cm_web_esg_0_absent.current | length == 1 + - cm_web_esg_0_absent.previous | length == 1 + - cm_web_esg_0_absent.current.0.fvESg.attributes.name == 'web_esg_0' + - cm_web_esg_0_absent.previous.0.fvESg.attributes.name == 'web_esg_0' + + - name: Remove an ESG with normal mode + cisco.aci.aci_esg: &nm_web_esg_0_absent + <<: *cm_web_esg_0_absent + register: nm_web_esg_0_absent + + - name: Assertions check for remove an ESG with normal mode + assert: + that: + - nm_web_esg_0_absent is changed + - nm_web_esg_0_absent.current == [] + - nm_web_esg_0_absent.previous | length == 1 + - nm_web_esg_0_absent.previous.0.fvESg.attributes.name == 'web_esg_0' + + - name: Remove an ESG with normal mode - idempotency works + cisco.aci.aci_esg: + <<: *nm_web_esg_0_absent + register: idempotency_web_esg_0_absent + + - name: Idempotency assertions check for remove an ESG with normal mode + assert: + that: + - idempotency_web_esg_0_absent is not changed + - idempotency_web_esg_0_absent.current == [] + - idempotency_web_esg_0_absent.previous == [] + + # Cleanup part + - name: Remove ap - application profile + cisco.aci.aci_ap: + <<: *anstest_ap_present + state: absent + + - name: Remove ansible_test - tenant + cisco.aci.aci_tenant: + <<: *tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_contract_master/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_contract_master/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_contract_master/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_contract_master/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_contract_master/tasks/main.yml new file mode 100644 index 000000000..debc3ec47 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_contract_master/tasks/main.yml @@ -0,0 +1,218 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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 + +# CLEAN ENVIRONMENT +- 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: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Ensure tenant - ansible_test does not exists before testing + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + output_level: debug + tenant: ansible_test + state: absent + +- name: Execute tasks only for ACI v5+ and non-cloud sites + when: + - version.current.0.topSystem.attributes.version is version('5', '>=') + - query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Setup part + - name: Ensure ansible_test - tenant exists + cisco.aci.aci_tenant: &tenant_present + <<: *tenant_absent + state: present + + - name: Ensure ap - application profile exists + cisco.aci.aci_ap: &anstest_ap_present + <<: *tenant_present + ap: anstest_ap + state: present + + - name: Ensure contract_master_ap - application profile exists + cisco.aci.aci_ap: &contract_master_ap_present + <<: *tenant_present + ap: contract_master_ap + state: present + + - name: Ensure web_esg - endpoint security group exists + cisco.aci.aci_esg: &web_esg_present + <<: *anstest_ap_present + esg: web_esg + vrf: default + state: present + + - name: Ensure contract_esg - endpoint security group exists + cisco.aci.aci_esg: &contract_esg_present + <<: *contract_master_ap_present + esg: contract_esg + vrf: default + state: present + + # Test Part + - name: Add an ESG contract master to web_esg with check mode + cisco.aci.aci_esg_contract_master: &cm_contract_esg_present + <<: *aci_info + tenant: ansible_test + ap: anstest_ap + esg: web_esg + contract_master_ap: contract_master_ap + contract_master_esg: contract_esg + state: present + check_mode: true + register: cm_contract_esg_present + + - name: Assertions check for add an ESG contract master to web_esg with check mode + assert: + that: + - cm_contract_esg_present is changed + - cm_contract_esg_present.current == [] + - cm_contract_esg_present.previous == [] + - cm_contract_esg_present.sent.fvRsSecInherited.attributes.tDn == "uni/tn-ansible_test/ap-contract_master_ap/esg-contract_esg" + - cm_contract_esg_present.sent.fvRsSecInherited.attributes.annotation == 'orchestrator:ansible' + + - name: Add an ESG contract master to web_esg with normal mode + cisco.aci.aci_esg_contract_master: &nm_contract_esg_present + <<: *cm_contract_esg_present + register: nm_contract_esg_present + + - name: Assertions check for add an ESG contract master to web_esg with normal mode + assert: + that: + - nm_contract_esg_present is changed + - nm_contract_esg_present.current | length == 1 + - nm_contract_esg_present.previous == [] + - nm_contract_esg_present.current.0.fvRsSecInherited.attributes.tDn == "uni/tn-ansible_test/ap-contract_master_ap/esg-contract_esg" + + - name: Add an ESG contract master to web_esg with normal mode - Idempotency works + cisco.aci.aci_esg_contract_master: + <<: *nm_contract_esg_present + register: idempotency_contract_esg_present + + - name: Idempotency assertions check for add an ESG contract master to web_esg with normal mode + assert: + that: + - idempotency_contract_esg_present is not changed + - idempotency_contract_esg_present.current | length == 1 + - idempotency_contract_esg_present.current.0.fvRsSecInherited.attributes.tDn == "uni/tn-ansible_test/ap-contract_master_ap/esg-contract_esg" + + - name: Query an ESG contract master + cisco.aci.aci_esg_contract_master: + <<: *aci_info + tenant: ansible_test + ap: anstest_ap + esg: web_esg + contract_master_ap: contract_master_ap + contract_master_esg: contract_esg + state: query + register: query_result_contract_master_esg + + - name: Assertions check for query an ESG contract master + assert: + that: + - query_result_contract_master_esg is not changed + - query_result_contract_master_esg.current | length == 1 + - query_result_contract_master_esg.current.0.fvRsSecInherited.attributes.tDn == "uni/tn-ansible_test/ap-contract_master_ap/esg-contract_esg" + + - name: Query an ESG contract master + cisco.aci.aci_esg_contract_master: + <<: *aci_info + tenant: ansible_test + ap: anstest_ap + esg: web_esg + state: query + register: query_all_contract_master + + - name: Assertions check for query_all_contract_master + assert: + that: + - query_all_contract_master is not changed + - query_all_contract_master.current | length == 1 + - query_all_contract_master.current.0.fvESg.children.0.fvRsSecInherited.attributes.tDn == "uni/tn-ansible_test/ap-contract_master_ap/esg-contract_esg" + + - name: Remove an ESG contract master with check mode + cisco.aci.aci_esg_contract_master: &cm_contract_esg_absent + <<: *aci_info + tenant: ansible_test + ap: anstest_ap + esg: web_esg + contract_master_ap: contract_master_ap + contract_master_esg: contract_esg + state: absent + check_mode: true + register: cm_contract_esg_absent + + - name: Assertions check for remove an ESG contract master with check mode + assert: + that: + - cm_contract_esg_absent is changed + - cm_contract_esg_absent.current != [] + - cm_contract_esg_absent.current.0.fvRsSecInherited.attributes.tDn == "uni/tn-ansible_test/ap-contract_master_ap/esg-contract_esg" + - cm_contract_esg_absent.previous | length == 1 + - cm_contract_esg_absent.previous.0.fvRsSecInherited.attributes.tDn == "uni/tn-ansible_test/ap-contract_master_ap/esg-contract_esg" + + - name: Remove an ESG contract master with normal mode + cisco.aci.aci_esg_contract_master: &nm_contract_esg_absent + <<: *cm_contract_esg_absent + register: nm_contract_esg_absent + + - name: Assertions check for remove an ESG contract master with normal mode + assert: + that: + - nm_contract_esg_absent is changed + - nm_contract_esg_absent.current == [] + - nm_contract_esg_absent.previous | length == 1 + - nm_contract_esg_absent.previous.0.fvRsSecInherited.attributes.tDn == "uni/tn-ansible_test/ap-contract_master_ap/esg-contract_esg" + + - name: Remove an ESG contract master with normal mode - Idempotency works + cisco.aci.aci_esg_contract_master: + <<: *nm_contract_esg_absent + register: idempotency_contract_esg_absent + + - name: Idempotency assertions check for remove an ESG contract master with normal mode + assert: + that: + - idempotency_contract_esg_absent is not changed + - idempotency_contract_esg_absent.current == [] + - idempotency_contract_esg_absent.previous == [] + + # Cleanup part + - name: Remove web_esg - endpoint security group + cisco.aci.aci_esg: + <<: *web_esg_present + state: absent + + - name: Remove ap - application profile + cisco.aci.aci_ap: + <<: *anstest_ap_present + state: absent + + - name: Remove ansible_test - tenant + cisco.aci.aci_tenant: + <<: *tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_epg_selector/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_epg_selector/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_epg_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_esg_epg_selector/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_epg_selector/tasks/main.yml new file mode 100644 index 000000000..599828ae7 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_epg_selector/tasks/main.yml @@ -0,0 +1,250 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Ensure tenant - ansible_test does not exists before testing + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + output_level: debug + tenant: ansible_test + state: absent + +- name: Execute tasks only for ACI v5.2+ and non-cloud sites + when: + - version.current.0.topSystem.attributes.version is version('5.2', '>=') + - query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Setup part + - name: Ensure ansible_test - tenant exists + cisco.aci.aci_tenant: &tenant_present + <<: *tenant_absent + state: present + + - name: Ensure ap - application profile exists + cisco.aci.aci_ap: &anstest_ap_present + <<: *tenant_present + ap: anstest_ap + state: present + + - name: Ensure web_esg - endpoint security group exists + cisco.aci.aci_esg: &web_esg_present + <<: *anstest_ap_present + esg: web_esg + vrf: default + state: present + + - name: Ensure epg_ap - application profile exists under the same tenant + cisco.aci.aci_ap: &epg_ap_present + <<: *tenant_present + ap: epg_ap + state: present + + - name: Ensure anstest_epg - exists under epg_ap - application profile + cisco.aci.aci_epg: + <<: *epg_ap_present + epg: anstest_epg + bd: default + description: Ansible Test + + - name: Add an EPG selector with check mode + cisco.aci.aci_esg_epg_selector: &cm_epg_selector_present + <<: *aci_info + tenant: ansible_test + ap: anstest_ap + esg: web_esg + epg_ap: epg_ap + epg: anstest_epg + description: Ans Test EPG Selector + state: present + check_mode: true + register: cm_epg_selector_present + + - name: Assertions check for add an EPG selector with check mode + assert: + that: + - cm_epg_selector_present is changed + - cm_epg_selector_present.current | length == 0 + - cm_epg_selector_present.sent.fvEPgSelector.attributes.matchEpgDn == "uni/tn-ansible_test/ap-epg_ap/epg-anstest_epg" + - cm_epg_selector_present.sent.fvEPgSelector.attributes.annotation == 'orchestrator:ansible' + + - name: Add an EPG selector with normal mode + cisco.aci.aci_esg_epg_selector: + <<: *cm_epg_selector_present + register: nm_epg_selector_present + + - name: Assertions check for add an EPG selector with normal mode + assert: + that: + - nm_epg_selector_present is changed + - nm_epg_selector_present.current | length == 1 + - nm_epg_selector_present.current.0.fvEPgSelector.attributes.matchEpgDn == "uni/tn-ansible_test/ap-epg_ap/epg-anstest_epg" + + - name: Add an EPG selector with check mode - idempotency works + cisco.aci.aci_esg_epg_selector: &cm_idempotency_epg_selector_present + <<: *cm_epg_selector_present + check_mode: true + register: cm_idempotency_epg_selector_present + + - name: Idempotency assertions check for add an EPG selector with check mode + assert: + that: + - cm_idempotency_epg_selector_present is not changed + - cm_idempotency_epg_selector_present.current | length == 1 + + - name: Add an EPG selector with normal mode - idempotency works + cisco.aci.aci_esg_epg_selector: + <<: *cm_idempotency_epg_selector_present + register: nm_idempotency_epg_selector_present + + - name: Idempotency assertions check for add an EPG selector with normal mode + assert: + that: + - nm_idempotency_epg_selector_present is not changed + - nm_idempotency_epg_selector_present.current | length == 1 + + - name: Query a EPG selector with esg and epg name + cisco.aci.aci_esg_epg_selector: + <<: *aci_info + tenant: ansible_test + ap: anstest_ap + esg: web_esg + epg_ap: epg_ap + epg: anstest_epg + state: query + register: query_single_epg_selector + + - name: Assertions check for query an EPG selector with esg and epg name + assert: + that: + - query_single_epg_selector is not changed + - query_single_epg_selector.current | length == 1 + - query_single_epg_selector.current.0.fvEPgSelector.attributes.matchEpgDn == "uni/tn-ansible_test/ap-epg_ap/epg-anstest_epg" + - query_single_epg_selector.current.0.fvEPgSelector.attributes.descr == "Ans Test EPG Selector" + + - name: Query all EPG selectors under an application profile + cisco.aci.aci_esg_epg_selector: + <<: *aci_info + tenant: ansible_test + ap: anstest_ap + state: query + register: query_all_epg_selectors_under_ap + + - name: Assertions check for query all EPG selectors under an application profile + assert: + that: + - query_all_epg_selectors_under_ap is not changed + - query_all_epg_selectors_under_ap.current | length == 1 + - query_all_epg_selectors_under_ap.current.0.fvAp.attributes.name == 'anstest_ap' + - query_all_epg_selectors_under_ap.current.0.fvAp.children.0.fvESg.attributes.name == 'web_esg' + - query_all_epg_selectors_under_ap.current.0.fvAp.children.0.fvESg.children[0].fvEPgSelector.attributes.matchEpgDn == "uni/tn-ansible_test/ap-epg_ap/epg-anstest_epg" + + - name: Query all EPG selectors + cisco.aci.aci_esg_epg_selector: + <<: *aci_info + state: query + register: query_all_epg_selectors + + - name: Assertions check for query all EPG selectors + assert: + that: + - query_all_epg_selectors is not changed + - query_all_epg_selectors.current | length >= 1 + + - name: Remove an EPG selector with check mode + cisco.aci.aci_esg_epg_selector: &cm_epg_selector_absent + <<: *aci_info + tenant: ansible_test + ap: anstest_ap + esg: web_esg + epg_ap: epg_ap + epg: anstest_epg + state: absent + check_mode: true + register: cm_epg_selector_absent + + - name: Assertions check for remove an EPG selector with check mode + assert: + that: + - cm_epg_selector_absent is changed + - cm_epg_selector_absent.current != [] + - cm_epg_selector_absent.current.0.fvEPgSelector.attributes.matchEpgDn == "uni/tn-ansible_test/ap-epg_ap/epg-anstest_epg" + - cm_epg_selector_absent.previous.0.fvEPgSelector.attributes.matchEpgDn == "uni/tn-ansible_test/ap-epg_ap/epg-anstest_epg" + + - name: Remove an EPG selector with normal mode + cisco.aci.aci_esg_epg_selector: + <<: *cm_epg_selector_absent + register: nm_epg_selector_absent + + - name: Assertions check for remove an EPG selector with normal mode + assert: + that: + - nm_epg_selector_absent is changed + - nm_epg_selector_absent.current == [] + - nm_epg_selector_absent.previous.0.fvEPgSelector.attributes.matchEpgDn == "uni/tn-ansible_test/ap-epg_ap/epg-anstest_epg" + + - name: Remove a EPG selector with check mode - idempotency works + cisco.aci.aci_esg_epg_selector: &cm_idempotency_epg_selector_absent + <<: *cm_epg_selector_absent + check_mode: true + register: cm_idempotency_epg_selector_absent + + - name: Idempotency assertions check for EPG selector with check mode + assert: + that: + - cm_idempotency_epg_selector_absent is not changed + - cm_idempotency_epg_selector_absent.current == [] + + - name: Remove a EPG selector with normal mode - idempotency works + cisco.aci.aci_esg_epg_selector: + <<: *cm_idempotency_epg_selector_absent + register: nm_idempotency_epg_selector_absent + + - name: Idempotency assertions check for EPG selector with normal mode + assert: + that: + - nm_idempotency_epg_selector_absent is not changed + - nm_idempotency_epg_selector_absent.current == [] + + # Cleanup part + - name: Remove web_esg - endpoint security group + cisco.aci.aci_esg: + <<: *web_esg_present + state: absent + + - name: Remove ap - application profile + cisco.aci.aci_ap: + <<: *anstest_ap_present + state: absent + + - name: Remove ansible_test - tenant + cisco.aci.aci_tenant: + <<: *tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_ip_subnet_selector/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_ip_subnet_selector/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_ip_subnet_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_esg_ip_subnet_selector/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_ip_subnet_selector/tasks/main.yml new file mode 100644 index 000000000..f96391704 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_ip_subnet_selector/tasks/main.yml @@ -0,0 +1,181 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Ensure tenant - ansible_test does not exists before testing + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + output_level: debug + tenant: ansible_test + state: absent + +- name: Execute tasks only for ACI v5+ and non-cloud sites + when: + - version.current.0.topSystem.attributes.version is version('5', '>=') + - query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Setup part + - name: Ensure ansible_test - tenant exists + cisco.aci.aci_tenant: &tenant_present + <<: *tenant_absent + state: present + + - name: Ensure ap - application profile exists + cisco.aci.aci_ap: &anstest_ap_present + <<: *tenant_present + ap: anstest_ap + state: present + + - name: Ensure web_esg - endpoint security group exists + cisco.aci.aci_esg: &web_esg_present + <<: *anstest_ap_present + esg: web_esg + vrf: default + state: present + + # Test Part + - name: Add IP Subnet selector with check mode + cisco.aci.aci_esg_ip_subnet_selector: &cm_subnet_ip_present + <<: *aci_info + <<: *web_esg_present + vrf: "{{ fake_var | default(omit) }}" + ip: "10.0.0.1" + description: "IP Subnet Selector" + state: present + check_mode: true + register: cm_subnet_ip_present + + - name: Assertions check for add IP Subnet selector with check mode + assert: + that: + - cm_subnet_ip_present is changed + - cm_subnet_ip_present.current == [] + - cm_subnet_ip_present.previous == [] + - cm_subnet_ip_present.sent.fvEPSelector.attributes.matchExpression == "ip=='10.0.0.1'" + + - name: Add IP Subnet selector with normal mode + cisco.aci.aci_esg_ip_subnet_selector: &nm_subnet_ip_present + <<: *cm_subnet_ip_present + register: nm_subnet_ip_present + + - name: Assertions check for add IP Subnet selector with normal mode + assert: + that: + - nm_subnet_ip_present is changed + - nm_subnet_ip_present.current | length == 1 + - nm_subnet_ip_present.current.0.fvEPSelector.attributes.matchExpression == "ip=='10.0.0.1'" + - nm_subnet_ip_present.current.0.fvEPSelector.attributes.dn == "uni/tn-ansible_test/ap-anstest_ap/esg-web_esg/epselector-[ip=='10.0.0.1']" + - nm_subnet_ip_present.current.0.fvEPSelector.attributes.annotation == 'orchestrator:ansible' + - nm_subnet_ip_present.previous == [] + - nm_subnet_ip_present.sent.fvEPSelector.attributes.matchExpression == "ip=='10.0.0.1'" + + - name: Add IP Subnet selector with normal mode - idempotency works + cisco.aci.aci_esg_ip_subnet_selector: + <<: *nm_subnet_ip_present + register: idempotency_nm_subnet_ip_present + + - name: Idempotency assertions check for add IP Subnet selectors with normal mode + assert: + that: + - idempotency_nm_subnet_ip_present is not changed + - idempotency_nm_subnet_ip_present.current.0.fvEPSelector.attributes.matchExpression == "ip=='10.0.0.1'" + - idempotency_nm_subnet_ip_present.current.0.fvEPSelector.attributes.descr == "IP Subnet Selector" + - idempotency_nm_subnet_ip_present.previous.0.fvEPSelector.attributes.matchExpression == "ip=='10.0.0.1'" + - idempotency_nm_subnet_ip_present.proposed.fvEPSelector.attributes.matchExpression == "ip=='10.0.0.1'" + + - name: Query all IP Subnet selectors + cisco.aci.aci_esg_ip_subnet_selector: + <<: *aci_info + state: query + register: query_result + + - name: Assertions check for query all IP Subnet selectors + assert: + that: + - query_result is not changed + - query_result.current | length >= 1 + + - name: Remove IP Subnet selector with check mode + cisco.aci.aci_esg_ip_subnet_selector: &cm_subnet_ip_absent + <<: *cm_subnet_ip_present + state: absent + check_mode: true + register: cm_subnet_ip_absent + + - name: Assertions check for remove IP Subnet selector with check mode + assert: + that: + - cm_subnet_ip_absent is changed + - cm_subnet_ip_absent.current != [] + - cm_subnet_ip_absent.previous.0.fvEPSelector.attributes.matchExpression == "ip=='10.0.0.1'" + - cm_subnet_ip_absent.previous.0.fvEPSelector.attributes.descr == "IP Subnet Selector" + - cm_subnet_ip_absent.current.0.fvEPSelector.attributes.matchExpression == "ip=='10.0.0.1'" + - cm_subnet_ip_absent.current.0.fvEPSelector.attributes.descr == "IP Subnet Selector" + + - name: Remove IP Subnet selector with normal mode + cisco.aci.aci_esg_ip_subnet_selector: &nm_subnet_ip_absent + <<: *cm_subnet_ip_absent + register: nm_subnet_ip_absent + + - name: Assertions check for remove IP Subnet selector with normal mode + assert: + that: + - nm_subnet_ip_absent is changed + - nm_subnet_ip_absent.current == [] + - nm_subnet_ip_absent.previous.0.fvEPSelector.attributes.matchExpression == "ip=='10.0.0.1'" + - nm_subnet_ip_absent.previous.0.fvEPSelector.attributes.descr == "IP Subnet Selector" + + - name: Remove IP Subnet selector with normal mode - idempotency works + cisco.aci.aci_esg_ip_subnet_selector: + <<: *nm_subnet_ip_absent + register: idempotency_nm_subnet_ip_absent + + - name: Idempotency assertions check for remove IP Subnet selector with normal mode + assert: + that: + - idempotency_nm_subnet_ip_absent is not changed + - idempotency_nm_subnet_ip_absent.current == [] + + # Cleanup part + - name: Remove web_esg - endpoint security group + cisco.aci.aci_esg: + <<: *web_esg_present + state: absent + + - name: Remove ap - application profile + cisco.aci.aci_ap: + <<: *anstest_ap_present + state: absent + + - name: Remove ansible_test - tenant + cisco.aci.aci_tenant: + <<: *tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_tag_selector/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_tag_selector/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_tag_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_esg_tag_selector/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_tag_selector/tasks/main.yml new file mode 100644 index 000000000..5df3b0754 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_esg_tag_selector/tasks/main.yml @@ -0,0 +1,188 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Ensure tenant - ansible_test does not exists before testing + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + output_level: debug + tenant: ansible_test + state: absent + +- name: Execute tasks only for ACI v5.2+ and non-cloud sites + when: + - version.current.0.topSystem.attributes.version is version('5.2', '>=') + - query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # Setup part + - name: Ensure ansible_test - tenant exists + cisco.aci.aci_tenant: &tenant_present + <<: *tenant_absent + state: present + + - name: Ensure ap - application profile exists + cisco.aci.aci_ap: &anstest_ap_present + <<: *tenant_present + ap: anstest_ap + state: present + + - name: Ensure web_esg - endpoint security group exists + cisco.aci.aci_esg: &web_esg_present + <<: *anstest_ap_present + esg: web_esg + vrf: default + state: present + + # Test Part + - name: Add a tag selector under web_esg with name and value(check_mode) + cisco.aci.aci_esg_tag_selector: &selector_0_cm_present + <<: *anstest_ap_present + esg: web_esg + name: tag-selector-0 + match_value: tag-value-0 + description: tag-selector-description + state: present + register: selector_0_cm_present + check_mode: true + + - name: Add a tag selector under web_esg with name and value(normal_mode) + cisco.aci.aci_esg_tag_selector: + <<: *selector_0_cm_present + register: selector_0_nm_present + + - name: present assertions for Tag Selector - tag-selector-0 + assert: + that: + - selector_0_cm_present is changed + - selector_0_nm_present is changed + - selector_0_cm_present.sent.fvTagSelector.attributes.matchKey == 'tag-selector-0' + - selector_0_cm_present.sent.fvTagSelector.attributes.matchValue == 'tag-value-0' + - selector_0_nm_present.current.0.fvTagSelector.attributes.matchKey == 'tag-selector-0' + - selector_0_nm_present.current.0.fvTagSelector.attributes.matchValue == 'tag-value-0' + - selector_0_nm_present.current.0.fvTagSelector.attributes.valueOperator == 'equals' + - selector_0_nm_present.current.0.fvTagSelector.attributes.annotation == 'orchestrator:ansible' + + - name: Query all Tag Selectors + cisco.aci.aci_esg_tag_selector: + <<: *aci_info + state: query + register: query_result + + - name: Verification of query all Tag Selectors - query_result + assert: + that: + - query_result is not changed + - query_result.current | length >= 1 + + - name: Query all Tag Selectors with a name and value + cisco.aci.aci_esg_tag_selector: + <<: *aci_info + name: tag-selector-0 + match_value: tag-value-0 + state: query + register: result_with_name_and_value + + - name: Verification of query - Tag Selectors with a name and value + assert: + that: + - result_with_name_and_value is not changed + - result_with_name_and_value.current | length == 1 + - result_with_name_and_value.current.0.fvTagSelector.attributes.matchKey == 'tag-selector-0' + - result_with_name_and_value.current.0.fvTagSelector.attributes.matchValue == 'tag-value-0' + - result_with_name_and_value.current.0.fvTagSelector.attributes.valueOperator == 'equals' + + - name: Query all Tag Selectors with only name + cisco.aci.aci_esg_tag_selector: + <<: *aci_info + name: tag-selector-0 + state: query + register: result_with_name + + - name: Verification of query - Tag Selectors with only name + assert: + that: + - result_with_name is not changed + - result_with_name.current | length == 1 + - result_with_name.current.0.fvTagSelector.attributes.matchKey == 'tag-selector-0' + - result_with_name.current.0.fvTagSelector.attributes.matchValue == 'tag-value-0' + - result_with_name.current.0.fvTagSelector.attributes.valueOperator == 'equals' + + - name: Remove a Tag Selector with name and value(check_mode) + cisco.aci.aci_esg_tag_selector: &selector_0_cm_absent_with_name_and_value + <<: *anstest_ap_present + esg: web_esg + name: tag-selector-0 + match_value: tag-value-0 + state: absent + register: selector_0_cm_absent_with_name_and_value + check_mode: true + + - name: Remove a Tag Selector with name and value(normal_mode) + cisco.aci.aci_esg_tag_selector: + <<: *selector_0_cm_absent_with_name_and_value + register: selector_0_nm_absent_with_name_and_value + + - name: Verification of selector_0_nm_absent_with_name - Tag Selectors under web_esg + assert: + that: + - selector_0_cm_absent_with_name_and_value is changed + - selector_0_cm_absent_with_name_and_value.current | length == 1 + - selector_0_nm_absent_with_name_and_value is changed + - selector_0_nm_absent_with_name_and_value.current | length == 0 + - selector_0_nm_absent_with_name_and_value.previous.0.fvTagSelector.attributes.matchKey == 'tag-selector-0' + - selector_0_nm_absent_with_name_and_value.previous.0.fvTagSelector.attributes.matchValue == 'tag-value-0' + + - name: Remove a Tag Selector with name and value(normal_mode) - idempotency works + cisco.aci.aci_esg_tag_selector: + <<: *selector_0_cm_absent_with_name_and_value + register: idempotency_selector_0_nm_absent_with_name_and_value + + - name: Verification of idempotency_selector_0_nm_absent_with_name_and_value - Tag Selectors under web_esg + assert: + that: + - idempotency_selector_0_nm_absent_with_name_and_value is not changed + - idempotency_selector_0_nm_absent_with_name_and_value.current | length == 0 + + # Cleanup part + - name: Remove web_esg - endpoint security group + cisco.aci.aci_esg: + <<: *web_esg_present + state: absent + + - name: Remove ap - application profile + cisco.aci.aci_ap: + <<: *anstest_ap_present + state: absent + + - name: Remove ansible_test - tenant + cisco.aci.aci_tenant: + <<: *tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_leaf_profile/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_leaf_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_leaf_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_fabric_leaf_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_leaf_profile/tasks/main.yml new file mode 100644 index 000000000..d4bf60dd5 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_leaf_profile/tasks/main.yml @@ -0,0 +1,122 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_leaf_switch_prf if it already exists + aci_fabric_leaf_profile: + <<: *aci_info + name: ansible_leaf_switch_prf + state: absent + +# CREATE SPINE SWITCH POLICY +- name: Create ansible_leaf_switch_prf + aci_fabric_leaf_profile: + <<: *aci_info + name: ansible_leaf_switch_prf + state: present + register: add_switch_prf + +- name: Verify profile creation + assert: + that: + - add_switch_prf.current.0.fabricLeafP.attributes.dn == "uni/fabric/leprof-ansible_leaf_switch_prf" + - add_switch_prf.current.0.fabricLeafP.attributes.name == "ansible_leaf_switch_prf" + - add_switch_prf.current.0.fabricLeafP.attributes.annotation == 'orchestrator:ansible' + +# CREATE SPINE SWITCH POLICY AGAIN TO TEST IDEMPOTENCE +- name: Create ansible_leaf_switch_prf again + aci_fabric_leaf_profile: + <<: *aci_info + name: ansible_leaf_switch_prf + state: present + register: add_switch_prf_again + +- name: Verify profile creation idempotence + assert: + that: + - add_switch_prf_again is not changed + - add_switch_prf_again.current.0.fabricLeafP.attributes.dn == "uni/fabric/leprof-ansible_leaf_switch_prf" + - add_switch_prf_again.current.0.fabricLeafP.attributes.name == "ansible_leaf_switch_prf" + +# QUERY SPINE SWITCH POLICY +- name: query leaf switch profile + aci_fabric_leaf_profile: + <<: *aci_info + name: ansible_leaf_switch_prf + state: query + register: query_switch_prf + +- name: Verify profile query + assert: + that: + - query_switch_prf is not changed + - query_switch_prf.current.0.fabricLeafP.attributes.dn == "uni/fabric/leprof-ansible_leaf_switch_prf" + - query_switch_prf.current.0.fabricLeafP.attributes.name == "ansible_leaf_switch_prf" + +# QUERY ALL SPINE SWITCH POLICIES +- name: query all leaf switch profiles + aci_fabric_leaf_profile: + <<: *aci_info + state: query + register: query_switch_prf_all + +- name: Verify profile query idempotence + assert: + that: + - query_switch_prf_all is not changed + +# DELETE SPINE SWITCH PROFILE +- name: Delete ansible_leaf_switch_prf + aci_fabric_leaf_profile: + <<: *aci_info + name: ansible_leaf_switch_prf + state: absent + register: delete_switch_prf + +- name: Verify profile deletion + assert: + that: + - delete_switch_prf is changed + - delete_switch_prf.current == [] + - delete_switch_prf.previous.0.fabricLeafP.attributes.dn == "uni/fabric/leprof-ansible_leaf_switch_prf" + - delete_switch_prf.previous.0.fabricLeafP.attributes.name == "ansible_leaf_switch_prf" + +# DELETE SPINE SWITCH PROFILE AGAIN TO TEST IDEMPOTENCE +- name: Delete ansible_leaf_switch_prf again + aci_fabric_leaf_profile: + <<: *aci_info + name: ansible_leaf_switch_prf + state: absent + register: delete_switch_prf_again + +- name: Verify profile deletion idempotence + assert: + that: + - delete_switch_prf_again is not changed + - delete_switch_prf_again.current == [] + +# CLEAN UP ENVIRONMENT +- name: Remove ansible_leaf_switch_prf + aci_fabric_leaf_profile: + <<: *aci_info + name: ansible_leaf_switch_prf + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_leaf_switch_assoc/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_leaf_switch_assoc/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_leaf_switch_assoc/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_leaf_switch_assoc/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_leaf_switch_assoc/tasks/main.yml new file mode 100644 index 000000000..35caafdb3 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_leaf_switch_assoc/tasks/main.yml @@ -0,0 +1,194 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_leaf_switch_prf if it already exists + aci_fabric_leaf_profile: + <<: *aci_info + name: ansible_leaf_switch_prf + state: absent + +# CREATE SPINE SWITCH POLICY +- name: Create ansible_leaf_switch_prf + aci_fabric_leaf_profile: + <<: *aci_info + name: ansible_leaf_switch_prf + state: present + +# CREATE SPINE SWITCH ASSOCIATION +- name: Create a leaf switch profile association + aci_fabric_leaf_switch_assoc: + <<: *aci_info + profile: ansible_leaf_switch_prf + name: ansible_leaf_switch_assoc + policy_group: ansible_leaf_pol_grp1 + state: present + register: add_association + +- name: Verify association creation + assert: + that: + - add_association.current.0.fabricLeafS.attributes.dn == "uni/fabric/leprof-ansible_leaf_switch_prf/leaves-ansible_leaf_switch_assoc-typ-range" + - add_association.current.0.fabricLeafS.attributes.name == "ansible_leaf_switch_assoc" + - add_association.current.0.fabricLeafS.attributes.type == "range" + - add_association.current.0.fabricLeafS.attributes.annotation == 'orchestrator:ansible' + +- name: Verify Policy Group association + assert: + that: + - add_association.current.0.fabricLeafS.children.0.fabricRsLeNodePGrp.attributes.tDn == "uni/fabric/funcprof/lenodepgrp-ansible_leaf_pol_grp1" + +# CREATE SPINE SWITCH ASSOCIATION AGAIN TO TEST IDEMPOTENCE +- name: Create a leaf switch profile association again + aci_fabric_leaf_switch_assoc: + <<: *aci_info + profile: ansible_leaf_switch_prf + name: ansible_leaf_switch_assoc + policy_group: ansible_leaf_pol_grp1 + state: present + register: add_association_again + +- name: Verify association creation idempotence + assert: + that: + - add_association_again is not changed + - add_association_again.current.0.fabricLeafS.attributes.dn == "uni/fabric/leprof-ansible_leaf_switch_prf/leaves-ansible_leaf_switch_assoc-typ-range" + - add_association_again.current.0.fabricLeafS.attributes.name == "ansible_leaf_switch_assoc" + - add_association_again.current.0.fabricLeafS.attributes.type == "range" + +- name: Verify Policy Group association idempotence + assert: + that: + - add_association_again.current.0.fabricLeafS.children.0.fabricRsLeNodePGrp.attributes.tDn == "uni/fabric/funcprof/lenodepgrp-ansible_leaf_pol_grp1" + +# CREATE SPINE SWITCH ASSOCIATION WITHOUT POLICY GROUP +- name: Create a leaf switch profile association without a policy group + aci_fabric_leaf_switch_assoc: + <<: *aci_info + profile: ansible_leaf_switch_prf + name: ansible_leaf_switch_assoc2 + state: present + register: add_association_without_policy_group + +- name: Verify association creation + assert: + that: + - add_association_without_policy_group.current.0.fabricLeafS.attributes.dn == "uni/fabric/leprof-ansible_leaf_switch_prf/leaves-ansible_leaf_switch_assoc2-typ-range" + - add_association_without_policy_group.current.0.fabricLeafS.attributes.name == "ansible_leaf_switch_assoc2" + - add_association_without_policy_group.current.0.fabricLeafS.attributes.type == "range" + +# UPDATE SPINE SWITCH POLICY GROUP ASSOCIATION +- name: Update a leaf switch profile association + aci_fabric_leaf_switch_assoc: + <<: *aci_info + profile: ansible_leaf_switch_prf + name: ansible_leaf_switch_assoc + policy_group: ansible_leaf_pol_grp2 + state: present + register: update_association + +- name: Verify association update + assert: + that: + - update_association is changed + - update_association.current.0.fabricLeafS.attributes.dn == "uni/fabric/leprof-ansible_leaf_switch_prf/leaves-ansible_leaf_switch_assoc-typ-range" + - update_association.current.0.fabricLeafS.attributes.name == "ansible_leaf_switch_assoc" + - update_association.current.0.fabricLeafS.attributes.type == "range" + +- name: Verify Policy Group association update + assert: + that: + - update_association.current.0.fabricLeafS.children.0.fabricRsLeNodePGrp.attributes.tDn == "uni/fabric/funcprof/lenodepgrp-ansible_leaf_pol_grp2" + +# QUERY SPINE SWITCH ASSOCIATION +- name: Query leaf switch profile association + aci_fabric_leaf_switch_assoc: + <<: *aci_info + profile: ansible_leaf_switch_prf + name: ansible_leaf_switch_assoc + state: query + register: query_association + +- name: Verify query data + assert: + that: + - query_association is not changed + - query_association.current.0.fabricLeafS.attributes.dn == "uni/fabric/leprof-ansible_leaf_switch_prf/leaves-ansible_leaf_switch_assoc-typ-range" + - query_association.current.0.fabricLeafS.attributes.name == "ansible_leaf_switch_assoc" + - query_association.current.0.fabricLeafS.attributes.type == "range" + +- name: Verify Policy Group association + assert: + that: + - query_association.current.0.fabricLeafS.children.0.fabricRsLeNodePGrp.attributes.tDn == "uni/fabric/funcprof/lenodepgrp-ansible_leaf_pol_grp2" + +# QUERY ALL SPINE SWITCH ASSOCIATIONS +- name: Query leaf switch profile association + aci_fabric_leaf_switch_assoc: + <<: *aci_info + state: query + register: query_association_all + +- name: Verify query all idempotence + assert: + that: + - query_association_all is not changed + +# DELETE SPINE SWITCH ASSOCIATION +- name: Delete leaf switch profile association + aci_fabric_leaf_switch_assoc: + <<: *aci_info + profile: ansible_leaf_switch_prf + name: ansible_leaf_switch_assoc + state: absent + register: delete_association + +- name: Verify association removal + assert: + that: + - delete_association is changed + - delete_association.current == [] + - delete_association.previous.0.fabricLeafS.attributes.dn == "uni/fabric/leprof-ansible_leaf_switch_prf/leaves-ansible_leaf_switch_assoc-typ-range" + - delete_association.previous.0.fabricLeafS.attributes.name == "ansible_leaf_switch_assoc" + - delete_association.previous.0.fabricLeafS.attributes.type == "range" + +# DELETE SPINE SWITCH ASSOCIATION AGAIN TO TEST IDEMPOTENCE +- name: Delete leaf switch profile association again + aci_fabric_leaf_switch_assoc: + <<: *aci_info + profile: ansible_leaf_switch_prf + name: ansible_leaf_switch_assoc + state: absent + register: delete_association_again + +- name: Verify association removal idempotence + assert: + that: + - delete_association_again is not changed + - delete_association_again.current == [] + +# CLEAN UP ENVIRONMENT +- name: Remove ansible_leaf_switch_prf + aci_fabric_leaf_profile: + <<: *aci_info + name: ansible_leaf_switch_prf + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_node/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_node/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_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_node/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_node/tasks/main.yml new file mode 100644 index 000000000..36e065e5b --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_node/tasks/main.yml @@ -0,0 +1,218 @@ +# Test code for the ACI modules +# 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) + +- 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 + + +# 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") }}' + serial: ansible_test + node_id: 105 + state: absent + + +# ADD FABRIC NODE +- name: Add fabric node (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 + switch: anstest + state: present + check_mode: true + register: cm_add_fabric_node + +- name: Add fabric node (normal mode) + cisco.aci.aci_fabric_node: *aci_fabric_node_present + register: nm_add_fabric_node + +- name: Add fabric node again (check_mode) + cisco.aci.aci_fabric_node: *aci_fabric_node_present + check_mode: true + register: cm_add_fabric_node_again + +- name: Add fabric node again (normal mode) + cisco.aci.aci_fabric_node: *aci_fabric_node_present + register: nm_add_fabric_node_again + +- name: Verify add_fabric_node + assert: + that: + - cm_add_fabric_node is changed + - nm_add_fabric_node is changed + - nm_add_fabric_node.current.0.fabricNodeIdentP.attributes.annotation == 'orchestrator:ansible' + # FIXME: Module is not idempotent + - cm_add_fabric_node_again is not changed + - nm_add_fabric_node_again is not changed + + +# CHANGE FABRIC NODE +- name: Change description of fabric node (check_mode) + cisco.aci.aci_fabric_node: + <<: *aci_fabric_node_present + description: Ansible test fabric node + check_mode: true + register: cm_add_fabric_node_descr + +- name: Change description of fabric node (normal mode) + cisco.aci.aci_fabric_node: + <<: *aci_fabric_node_present + description: Ansible test fabric node + register: nm_add_fabric_node_descr + +- name: Change description of fabric nodeagain (check_mode) + cisco.aci.aci_fabric_node: + <<: *aci_fabric_node_present + description: Ansible test fabric node + check_mode: true + register: cm_add_fabric_node_descr_again + +- name: Change description of fabric node again (normal mode) + cisco.aci.aci_fabric_node: + <<: *aci_fabric_node_present + description: Ansible test fabric node + register: nm_add_fabric_node_descr_again + +- name: Verify add_fabric_node_descr + assert: + that: + - cm_add_fabric_node_descr is changed + - nm_add_fabric_node_descr is changed + # FIXME: Module is not idempotent + - cm_add_fabric_node_descr_again is not changed + - nm_add_fabric_node_descr_again is not changed + + +# ADD FABRIC NODE AGAIN +- name: Add fabric node again with no description (check_mode) + cisco.aci.aci_fabric_node: *aci_fabric_node_present + check_mode: true + register: cm_add_fabric_node_again_no_descr + +- name: Add fabric node again with no description (normal mode) + cisco.aci.aci_fabric_node: *aci_fabric_node_present + register: nm_add_fabric_node_again_no_descr + +- name: Verify add_fabric_node_again_no_descr + assert: + that: + # FIXME: Module is not idempotent + - cm_add_fabric_node_again_no_descr is not changed + - nm_add_fabric_node_again_no_descr is not changed + + +# QUERY ALL FABRIC NODES +- name: Query fabric nodes (check_mode) + cisco.aci.aci_fabric_node: &aci_fabric_node_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") }}' + state: query + check_mode: true + register: cm_query_all_fabric_nodes + +- name: Query all fabric nodes (normal mode) + cisco.aci.aci_fabric_node: *aci_fabric_node_query + register: nm_query_all_fabric_nodes + +- name: Verify query_all_fabric_nodes + assert: + that: + - cm_query_all_fabric_nodes is not changed + - nm_query_all_fabric_nodes is not changed + - cm_query_all_fabric_nodes == nm_query_all_fabric_nodes + + +# QUERY A FABRIC NODE +- name: Query our fabric_node + cisco.aci.aci_fabric_node: + <<: *aci_fabric_node_query + serial: ansible_test # might need node_id too + check_mode: true + register: cm_query_fabric_node + +- name: Query our fabric_node + cisco.aci.aci_fabric_node: + <<: *aci_fabric_node_query + serial: ansible_test + register: nm_query_fabric_node + +- name: Verify query_fabric_node + assert: + that: + - cm_query_fabric_node is not changed + - nm_query_fabric_node is not changed + - cm_query_fabric_node == nm_query_fabric_node + + +# REMOVE FABRIC NODE +- name: Remove fabric_node (check_mode) + cisco.aci.aci_fabric_node: *aci_fabric_node_absent + check_mode: true + register: cm_remove_fabric_node + +- name: Remove fabric_node (normal mode) + cisco.aci.aci_fabric_node: *aci_fabric_node_absent + register: nm_remove_fabric_node + +- name: Remove fabric_node again (check_mode) + cisco.aci.aci_fabric_node: *aci_fabric_node_absent + check_mode: true + register: cm_remove_fabric_node_again + +- name: Remove fabric_node again (normal mode) + cisco.aci.aci_fabric_node: *aci_fabric_node_absent + register: nm_remove_fabric_node_again + +- name: Verify remove_fabric_node + assert: + that: + - cm_remove_fabric_node is changed + - nm_remove_fabric_node is changed + - cm_remove_fabric_node_again is not changed + - nm_remove_fabric_node_again is not changed + + +# QUERY NON-EXISTING LEAF PROFILE +- name: Query non-existing fabric_node (check_mode) + cisco.aci.aci_fabric_node: + <<: *aci_fabric_node_query + serial: ansible_test + check_mode: true + register: cm_query_non_fabric_node + +- name: Query non-existing fabric_node (normal mode) + cisco.aci.aci_fabric_node: + <<: *aci_fabric_node_query + serial: ansible_test + register: nm_query_non_fabric_node + +- name: Verify query_non_fabric_node + assert: + that: + - cm_query_non_fabric_node is not changed + - nm_query_non_fabric_node is not changed + - cm_query_non_fabric_node == nm_query_non_fabric_node diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_pod_policy_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_pod_policy_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_pod_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_pod_policy_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_pod_policy_group/tasks/main.yml new file mode 100644 index 000000000..282fe15d3 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_pod_policy_group/tasks/main.yml @@ -0,0 +1,264 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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 any pre-existing pod policy group + cisco.aci.aci_fabric_pod_policy_group: + <<: *aci_info + name: '{{ item }}' + state: absent + loop: + - "ansible_pod_policy_group" + - "ansible_empty_pod_policy_group" + +# ADD POD POLICY GROUP +- name: Add pod policy group (check mode) + cisco.aci.aci_fabric_pod_policy_group: &group_present + <<: *aci_info + name: ansible_pod_policy_group + date_time_policy: default + isis_policy: default + coop_group_policy: default + bgp_rr_policy: default + management_access_policy: default + snmp_policy: default + macsec_policy: default + state: present + check_mode: true + register: cm_add_group + +- name: Add pod policy group (normal mode) + cisco.aci.aci_fabric_pod_policy_group: + <<: *group_present + register: nm_add_group + +- name: Add pod policy group again (check mode) + cisco.aci.aci_fabric_pod_policy_group: + <<: *group_present + check_mode: true + register: cm_add_group_again + +- name: Add pod policy group again (normal mode) + cisco.aci.aci_fabric_pod_policy_group: + <<: *group_present + register: nm_add_group_again + +- name: Verify add policy group + assert: + that: + - cm_add_group is changed + - nm_add_group is changed + - nm_add_group.current.0.fabricPodPGrp.attributes.dn == 'uni/fabric/funcprof/podpgrp-ansible_pod_policy_group' + - nm_add_group.current.0.fabricPodPGrp.attributes.name == 'ansible_pod_policy_group' + - nm_add_group.current.0.fabricPodPGrp.children.0.fabricRsSnmpPol.attributes.tnSnmpPolName == 'default' + - nm_add_group.current.0.fabricPodPGrp.children.1.fabricRsPodPGrpCoopP.attributes.tnCoopPolName == 'default' + - nm_add_group.current.0.fabricPodPGrp.children.2.fabricRsCommPol.attributes.tnCommPolName == 'default' + - nm_add_group.current.0.fabricPodPGrp.children.3.fabricRsMacsecPol.attributes.tnMacsecFabIfPolName == 'default' + - nm_add_group.current.0.fabricPodPGrp.children.4.fabricRsTimePol.attributes.tnDatetimePolName == 'default' + - nm_add_group.current.0.fabricPodPGrp.children.5.fabricRsPodPGrpBGPRRP.attributes.tnBgpInstPolName == 'default' + - nm_add_group.current.0.fabricPodPGrp.children.6.fabricRsPodPGrpIsisDomP.attributes.tnIsisDomPolName == 'default' + - cm_add_group_again is not changed + - nm_add_group_again is not changed + - nm_add_group_again.current.0.fabricPodPGrp.attributes.dn == 'uni/fabric/funcprof/podpgrp-ansible_pod_policy_group' + - nm_add_group_again.current.0.fabricPodPGrp.attributes.name == 'ansible_pod_policy_group' + - nm_add_group_again.current.0.fabricPodPGrp.children.0.fabricRsSnmpPol.attributes.tnSnmpPolName == 'default' + - nm_add_group_again.current.0.fabricPodPGrp.children.1.fabricRsPodPGrpCoopP.attributes.tnCoopPolName == 'default' + - nm_add_group_again.current.0.fabricPodPGrp.children.2.fabricRsCommPol.attributes.tnCommPolName == 'default' + - nm_add_group_again.current.0.fabricPodPGrp.children.3.fabricRsMacsecPol.attributes.tnMacsecFabIfPolName == 'default' + - nm_add_group_again.current.0.fabricPodPGrp.children.4.fabricRsTimePol.attributes.tnDatetimePolName == 'default' + - nm_add_group_again.current.0.fabricPodPGrp.children.5.fabricRsPodPGrpBGPRRP.attributes.tnBgpInstPolName == 'default' + - nm_add_group_again.current.0.fabricPodPGrp.children.6.fabricRsPodPGrpIsisDomP.attributes.tnIsisDomPolName == 'default' + +- name: Add empty pod policy group (normal mode) + cisco.aci.aci_fabric_pod_policy_group: + <<: *aci_info + name: ansible_empty_pod_policy_group + state: present + register: nm_add_empty_group + +- name: Verify add empty policy group + assert: + that: + - nm_add_empty_group is changed + - nm_add_empty_group.current.0.fabricPodPGrp.attributes.dn == 'uni/fabric/funcprof/podpgrp-ansible_empty_pod_policy_group' + - nm_add_empty_group.current.0.fabricPodPGrp.attributes.name == 'ansible_empty_pod_policy_group' + - nm_add_empty_group.current.0.fabricPodPGrp.children.0.fabricRsSnmpPol.attributes.tnSnmpPolName == '' + - nm_add_empty_group.current.0.fabricPodPGrp.children.1.fabricRsPodPGrpCoopP.attributes.tnCoopPolName == '' + - nm_add_empty_group.current.0.fabricPodPGrp.children.2.fabricRsCommPol.attributes.tnCommPolName == '' + - nm_add_empty_group.current.0.fabricPodPGrp.children.3.fabricRsMacsecPol.attributes.tnMacsecFabIfPolName == '' + - nm_add_empty_group.current.0.fabricPodPGrp.children.4.fabricRsTimePol.attributes.tnDatetimePolName == '' + - nm_add_empty_group.current.0.fabricPodPGrp.children.5.fabricRsPodPGrpBGPRRP.attributes.tnBgpInstPolName == '' + - nm_add_empty_group.current.0.fabricPodPGrp.children.6.fabricRsPodPGrpIsisDomP.attributes.tnIsisDomPolName == '' + +# MODIFY POLICY GROUP +- name: Modify pod policy group (check mode) + cisco.aci.aci_fabric_pod_policy_group: &group_changed + <<: *aci_info + name: ansible_pod_policy_group + date_time_policy: '' + isis_policy: '' + coop_group_policy: '' + bgp_rr_policy: '' + management_access_policy: '' + snmp_policy: '' + macsec_policy: '' + state: present + check_mode: true + register: cm_modify_group + +- name: Modify pod policy group (normal mode) + cisco.aci.aci_fabric_pod_policy_group: + <<: *group_changed + register: nm_modify_group + +- name: Modify policy group again (check mode) + cisco.aci.aci_fabric_pod_policy_group: + <<: *group_changed + check_mode: true + register: cm_modify_group_again + +- name: Modify policy group again (normal mode) + cisco.aci.aci_fabric_pod_policy_group: + <<: *group_changed + register: nm_modify_group_again + +- name: Verify modify policy + assert: + that: + - cm_modify_group is changed + - nm_modify_group is changed + - nm_modify_group.current.0.fabricPodPGrp.attributes.dn == 'uni/fabric/funcprof/podpgrp-ansible_pod_policy_group' + - nm_modify_group.current.0.fabricPodPGrp.attributes.name == 'ansible_pod_policy_group' + - nm_modify_group.current.0.fabricPodPGrp.children.0.fabricRsSnmpPol.attributes.tnSnmpPolName == '' + - nm_modify_group.current.0.fabricPodPGrp.children.1.fabricRsPodPGrpCoopP.attributes.tnCoopPolName == '' + - nm_modify_group.current.0.fabricPodPGrp.children.2.fabricRsCommPol.attributes.tnCommPolName == '' + - nm_modify_group.current.0.fabricPodPGrp.children.3.fabricRsMacsecPol.attributes.tnMacsecFabIfPolName == '' + - nm_modify_group.current.0.fabricPodPGrp.children.4.fabricRsTimePol.attributes.tnDatetimePolName == '' + - nm_modify_group.current.0.fabricPodPGrp.children.5.fabricRsPodPGrpBGPRRP.attributes.tnBgpInstPolName == '' + - nm_modify_group.current.0.fabricPodPGrp.children.6.fabricRsPodPGrpIsisDomP.attributes.tnIsisDomPolName == '' + - cm_modify_group_again is not changed + - nm_modify_group_again is not changed + - nm_modify_group_again.current.0.fabricPodPGrp.attributes.dn == 'uni/fabric/funcprof/podpgrp-ansible_pod_policy_group' + - nm_modify_group_again.current.0.fabricPodPGrp.attributes.name == 'ansible_pod_policy_group' + - nm_modify_group_again.current.0.fabricPodPGrp.children.0.fabricRsSnmpPol.attributes.tnSnmpPolName == '' + - nm_modify_group_again.current.0.fabricPodPGrp.children.1.fabricRsPodPGrpCoopP.attributes.tnCoopPolName == '' + - nm_modify_group_again.current.0.fabricPodPGrp.children.2.fabricRsCommPol.attributes.tnCommPolName == '' + - nm_modify_group_again.current.0.fabricPodPGrp.children.3.fabricRsMacsecPol.attributes.tnMacsecFabIfPolName == '' + - nm_modify_group_again.current.0.fabricPodPGrp.children.4.fabricRsTimePol.attributes.tnDatetimePolName == '' + - nm_modify_group_again.current.0.fabricPodPGrp.children.5.fabricRsPodPGrpBGPRRP.attributes.tnBgpInstPolName == '' + - nm_modify_group_again.current.0.fabricPodPGrp.children.6.fabricRsPodPGrpIsisDomP.attributes.tnIsisDomPolName == '' + +# QUERY ALL POLICY GROUPS +- name: Query all policy groups (check_mode) + cisco.aci.aci_fabric_pod_policy_group: &group_query_all + 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") }}' + state: query + check_mode: true + register: cm_query_all_groups + +- name: Query all groups (normal mode) + cisco.aci.aci_fabric_pod_policy_group: + <<: *group_query_all + register: nm_query_all_groups + +- name: Verify query_all_groups + assert: + that: + - cm_query_all_groups is not changed + - nm_query_all_groups is not changed + +# QUERY A POD POLICY GROUP +- name: Query a specific pod policy (check_mode) + cisco.aci.aci_fabric_pod_policy_group: + <<: *group_query_all + name: ansible_pod_policy_group + check_mode: true + register: cm_query_group + +- name: Query a specific pod policy (normal mode) + cisco.aci.aci_fabric_pod_policy_group: + <<: *group_query_all + name: ansible_pod_policy_group + register: nm_query_group + +- name: Verify query_group + assert: + that: + - cm_query_group is not changed + - nm_query_group is not changed + - cm_query_group == nm_query_group + - nm_query_group.current.0.fabricPodPGrp.attributes.dn == 'uni/fabric/funcprof/podpgrp-ansible_pod_policy_group' + - nm_query_group.current.0.fabricPodPGrp.attributes.name == 'ansible_pod_policy_group' + - nm_query_group.current.0.fabricPodPGrp.children.0.fabricRsSnmpPol.attributes.tnSnmpPolName == '' + - nm_query_group.current.0.fabricPodPGrp.children.1.fabricRsPodPGrpCoopP.attributes.tnCoopPolName == '' + - nm_query_group.current.0.fabricPodPGrp.children.2.fabricRsCommPol.attributes.tnCommPolName == '' + - nm_query_group.current.0.fabricPodPGrp.children.3.fabricRsMacsecPol.attributes.tnMacsecFabIfPolName == '' + - nm_query_group.current.0.fabricPodPGrp.children.4.fabricRsTimePol.attributes.tnDatetimePolName == '' + - nm_query_group.current.0.fabricPodPGrp.children.5.fabricRsPodPGrpBGPRRP.attributes.tnBgpInstPolName == '' + - nm_query_group.current.0.fabricPodPGrp.children.6.fabricRsPodPGrpIsisDomP.attributes.tnIsisDomPolName == '' + +# REMOVE POLICY GROUP +- name: Remove policy group (check mode) + cisco.aci.aci_fabric_pod_policy_group: &group_absent + <<: *group_present + state: absent + check_mode: true + register: cm_remove_group + +- name: Remove policy group (normal mode) + cisco.aci.aci_fabric_pod_policy_group: + <<: *group_absent + register: nm_remove_group + +- name: Remove policy group again (check mode) + cisco.aci.aci_fabric_pod_policy_group: + <<: *group_absent + check_mode: true + register: cm_remove_group_again + +- name: Remove policy group again (normal mode) + cisco.aci.aci_fabric_pod_policy_group: + <<: *group_absent + register: nm_remove_group_again + +- name: Verify remove_group and remove_group_again + assert: + that: + - cm_remove_group is changed + - nm_remove_group is changed + - nm_remove_group.current == [] + - nm_remove_group.previous.0.fabricPodPGrp.attributes.dn == 'uni/fabric/funcprof/podpgrp-ansible_pod_policy_group' + - nm_remove_group.previous.0.fabricPodPGrp.attributes.name == 'ansible_pod_policy_group' + - nm_remove_group.previous.0.fabricPodPGrp.children.0.fabricRsSnmpPol.attributes.tnSnmpPolName == '' + - nm_remove_group.previous.0.fabricPodPGrp.children.1.fabricRsPodPGrpCoopP.attributes.tnCoopPolName == '' + - nm_remove_group.previous.0.fabricPodPGrp.children.2.fabricRsCommPol.attributes.tnCommPolName == '' + - nm_remove_group.previous.0.fabricPodPGrp.children.3.fabricRsMacsecPol.attributes.tnMacsecFabIfPolName == '' + - nm_remove_group.previous.0.fabricPodPGrp.children.4.fabricRsTimePol.attributes.tnDatetimePolName == '' + - nm_remove_group.previous.0.fabricPodPGrp.children.5.fabricRsPodPGrpBGPRRP.attributes.tnBgpInstPolName == '' + - nm_remove_group.previous.0.fabricPodPGrp.children.6.fabricRsPodPGrpIsisDomP.attributes.tnIsisDomPolName == '' + - cm_remove_group_again is not changed + - nm_remove_group_again is not changed diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_spine_profile/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_spine_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_spine_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_fabric_spine_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_spine_profile/tasks/main.yml new file mode 100644 index 000000000..684a9a874 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_spine_profile/tasks/main.yml @@ -0,0 +1,122 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_spine_switch_prf if it already exists + aci_fabric_spine_profile: + <<: *aci_info + name: ansible_spine_switch_prf + state: absent + +# CREATE SPINE SWITCH POLICY +- name: Create ansible_spine_switch_prf + aci_fabric_spine_profile: + <<: *aci_info + name: ansible_spine_switch_prf + state: present + register: add_switch_prf + +- name: Verify profile creation + assert: + that: + - add_switch_prf.current.0.fabricSpineP.attributes.dn == "uni/fabric/spprof-ansible_spine_switch_prf" + - add_switch_prf.current.0.fabricSpineP.attributes.name == "ansible_spine_switch_prf" + - add_switch_prf.current.0.fabricSpineP.attributes.annotation == 'orchestrator:ansible' + +# CREATE SPINE SWITCH POLICY AGAIN TO TEST IDEMPOTENCE +- name: Create ansible_spine_switch_prf again + aci_fabric_spine_profile: + <<: *aci_info + name: ansible_spine_switch_prf + state: present + register: add_switch_prf_again + +- name: Verify profile creation idempotence + assert: + that: + - add_switch_prf_again is not changed + - add_switch_prf_again.current.0.fabricSpineP.attributes.dn == "uni/fabric/spprof-ansible_spine_switch_prf" + - add_switch_prf_again.current.0.fabricSpineP.attributes.name == "ansible_spine_switch_prf" + +# QUERY SPINE SWITCH POLICY +- name: query spine switch profile + aci_fabric_spine_profile: + <<: *aci_info + name: ansible_spine_switch_prf + state: query + register: query_switch_prf + +- name: Verify profile query + assert: + that: + - query_switch_prf is not changed + - query_switch_prf.current.0.fabricSpineP.attributes.dn == "uni/fabric/spprof-ansible_spine_switch_prf" + - query_switch_prf.current.0.fabricSpineP.attributes.name == "ansible_spine_switch_prf" + +# QUERY ALL SPINE SWITCH POLICIES +- name: query all spine switch profiles + aci_fabric_spine_profile: + <<: *aci_info + state: query + register: query_switch_prf_all + +- name: Verify profile query idempotence + assert: + that: + - query_switch_prf_all is not changed + +# DELETE SPINE SWITCH PROFILE +- name: Delete ansible_spine_switch_prf + aci_fabric_spine_profile: + <<: *aci_info + name: ansible_spine_switch_prf + state: absent + register: delete_switch_prf + +- name: Verify profile deletion + assert: + that: + - delete_switch_prf is changed + - delete_switch_prf.current == [] + - delete_switch_prf.previous.0.fabricSpineP.attributes.dn == "uni/fabric/spprof-ansible_spine_switch_prf" + - delete_switch_prf.previous.0.fabricSpineP.attributes.name == "ansible_spine_switch_prf" + +# DELETE SPINE SWITCH PROFILE AGAIN TO TEST IDEMPOTENCE +- name: Delete ansible_spine_switch_prf again + aci_fabric_spine_profile: + <<: *aci_info + name: ansible_spine_switch_prf + state: absent + register: delete_switch_prf_again + +- name: Verify profile deletion idempotence + assert: + that: + - delete_switch_prf_again is not changed + - delete_switch_prf_again.current == [] + +# CLEAN UP ENVIRONMENT +- name: Remove ansible_spine_switch_prf + aci_fabric_spine_profile: + <<: *aci_info + name: ansible_spine_switch_prf + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_spine_switch_assoc/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_spine_switch_assoc/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_spine_switch_assoc/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_spine_switch_assoc/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_spine_switch_assoc/tasks/main.yml new file mode 100644 index 000000000..697590fae --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_spine_switch_assoc/tasks/main.yml @@ -0,0 +1,194 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_spine_switch_prf if it already exists + aci_fabric_spine_profile: + <<: *aci_info + name: ansible_spine_switch_prf + state: absent + +# CREATE SPINE SWITCH POLICY +- name: Create ansible_spine_switch_prf + aci_fabric_spine_profile: + <<: *aci_info + name: ansible_spine_switch_prf + state: present + +# CREATE SPINE SWITCH ASSOCIATION +- name: Create a spine switch profile association + aci_fabric_spine_switch_assoc: + <<: *aci_info + profile: ansible_spine_switch_prf + name: ansible_spine_switch_assoc + policy_group: ansible_spine_pol_grp1 + state: present + register: add_association + +- name: Verify association creation + assert: + that: + - add_association.current.0.fabricSpineS.attributes.dn == "uni/fabric/spprof-ansible_spine_switch_prf/spines-ansible_spine_switch_assoc-typ-range" + - add_association.current.0.fabricSpineS.attributes.name == "ansible_spine_switch_assoc" + - add_association.current.0.fabricSpineS.attributes.type == "range" + - add_association.current.0.fabricSpineS.attributes.annotation == 'orchestrator:ansible' + +- name: Verify Policy Group association + assert: + that: + - add_association.current.0.fabricSpineS.children.0.fabricRsSpNodePGrp.attributes.tDn == "uni/fabric/funcprof/spnodepgrp-ansible_spine_pol_grp1" + +# CREATE SPINE SWITCH ASSOCIATION AGAIN TO TEST IDEMPOTENCE +- name: Create a spine switch profile association again + aci_fabric_spine_switch_assoc: + <<: *aci_info + profile: ansible_spine_switch_prf + name: ansible_spine_switch_assoc + policy_group: ansible_spine_pol_grp1 + state: present + register: add_association_again + +- name: Verify association creation idempotence + assert: + that: + - add_association_again is not changed + - add_association_again.current.0.fabricSpineS.attributes.dn == "uni/fabric/spprof-ansible_spine_switch_prf/spines-ansible_spine_switch_assoc-typ-range" + - add_association_again.current.0.fabricSpineS.attributes.name == "ansible_spine_switch_assoc" + - add_association_again.current.0.fabricSpineS.attributes.type == "range" + +- name: Verify Policy Group association idempotence + assert: + that: + - add_association_again.current.0.fabricSpineS.children.0.fabricRsSpNodePGrp.attributes.tDn == "uni/fabric/funcprof/spnodepgrp-ansible_spine_pol_grp1" + +# CREATE SPINE SWITCH ASSOCIATION WITHOUT POLICY GROUP +- name: Create a spine switch profile association without a policy group + aci_fabric_spine_switch_assoc: + <<: *aci_info + profile: ansible_spine_switch_prf + name: ansible_spine_switch_assoc2 + state: present + register: add_association_without_policy_group + +- name: Verify association creation + assert: + that: + - add_association_without_policy_group.current.0.fabricSpineS.attributes.dn == "uni/fabric/spprof-ansible_spine_switch_prf/spines-ansible_spine_switch_assoc2-typ-range" + - add_association_without_policy_group.current.0.fabricSpineS.attributes.name == "ansible_spine_switch_assoc2" + - add_association_without_policy_group.current.0.fabricSpineS.attributes.type == "range" + +# UPDATE SPINE SWITCH POLICY GROUP ASSOCIATION +- name: Update a spine switch profile association + aci_fabric_spine_switch_assoc: + <<: *aci_info + profile: ansible_spine_switch_prf + name: ansible_spine_switch_assoc + policy_group: ansible_spine_pol_grp2 + state: present + register: update_association + +- name: Verify association update + assert: + that: + - update_association is changed + - update_association.current.0.fabricSpineS.attributes.dn == "uni/fabric/spprof-ansible_spine_switch_prf/spines-ansible_spine_switch_assoc-typ-range" + - update_association.current.0.fabricSpineS.attributes.name == "ansible_spine_switch_assoc" + - update_association.current.0.fabricSpineS.attributes.type == "range" + +- name: Verify Policy Group association update + assert: + that: + - update_association.current.0.fabricSpineS.children.0.fabricRsSpNodePGrp.attributes.tDn == "uni/fabric/funcprof/spnodepgrp-ansible_spine_pol_grp2" + +# QUERY SPINE SWITCH ASSOCIATION +- name: Query spine switch profile association + aci_fabric_spine_switch_assoc: + <<: *aci_info + profile: ansible_spine_switch_prf + name: ansible_spine_switch_assoc + state: query + register: query_association + +- name: Verify query data + assert: + that: + - query_association is not changed + - query_association.current.0.fabricSpineS.attributes.dn == "uni/fabric/spprof-ansible_spine_switch_prf/spines-ansible_spine_switch_assoc-typ-range" + - query_association.current.0.fabricSpineS.attributes.name == "ansible_spine_switch_assoc" + - query_association.current.0.fabricSpineS.attributes.type == "range" + +- name: Verify Policy Group association + assert: + that: + - query_association.current.0.fabricSpineS.children.0.fabricRsSpNodePGrp.attributes.tDn == "uni/fabric/funcprof/spnodepgrp-ansible_spine_pol_grp2" + +# QUERY ALL SPINE SWITCH ASSOCIATIONS +- name: Query spine switch profile association + aci_fabric_spine_switch_assoc: + <<: *aci_info + state: query + register: query_association_all + +- name: Verify query all idempotence + assert: + that: + - query_association_all is not changed + +# DELETE SPINE SWITCH ASSOCIATION +- name: Delete spine switch profile association + aci_fabric_spine_switch_assoc: + <<: *aci_info + profile: ansible_spine_switch_prf + name: ansible_spine_switch_assoc + state: absent + register: delete_association + +- name: Verify association removal + assert: + that: + - delete_association is changed + - delete_association.current == [] + - delete_association.previous.0.fabricSpineS.attributes.dn == "uni/fabric/spprof-ansible_spine_switch_prf/spines-ansible_spine_switch_assoc-typ-range" + - delete_association.previous.0.fabricSpineS.attributes.name == "ansible_spine_switch_assoc" + - delete_association.previous.0.fabricSpineS.attributes.type == "range" + +# DELETE SPINE SWITCH ASSOCIATION AGAIN TO TEST IDEMPOTENCE +- name: Delete spine switch profile association again + aci_fabric_spine_switch_assoc: + <<: *aci_info + profile: ansible_spine_switch_prf + name: ansible_spine_switch_assoc + state: absent + register: delete_association_again + +- name: Verify association removal idempotence + assert: + that: + - delete_association_again is not changed + - delete_association_again.current == [] + +# CLEAN UP ENVIRONMENT +- name: Remove ansible_spine_switch_prf + aci_fabric_spine_profile: + <<: *aci_info + name: ansible_spine_switch_prf + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_switch_block/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_switch_block/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_switch_block/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_switch_block/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_switch_block/tasks/main.yml new file mode 100644 index 000000000..5bd4ce68b --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_switch_block/tasks/main.yml @@ -0,0 +1,268 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_spine_switch_prf if it already exists + aci_fabric_spine_profile: + <<: *aci_info + name: ansible_spine_switch_prf + state: absent + +- name: Remove ansible_leaf_switch_prf if it already exists + aci_fabric_leaf_profile: + <<: *aci_info + name: ansible_leaf_switch_prf + state: absent + +# TODO: Add testing for Fabric Leaf Blocks + +# CREATE SPINE SWITCH POLICY +- name: Create ansible_spine_switch_prf + aci_fabric_spine_profile: + <<: *aci_info + name: ansible_spine_switch_prf + state: present + +# CREATE LEAF SWITCH POLICY +- name: Create ansible_leaf_switch_prf + aci_fabric_leaf_profile: + <<: *aci_info + name: ansible_leaf_switch_prf + state: present + +# CREATE SPINE SWITCH ASSOCIATION +- name: Create a spine switch profile association + aci_fabric_spine_switch_assoc: + <<: *aci_info + profile: ansible_spine_switch_prf + name: ansible_spine_switch_assoc + policy_group: ansible_spine_pol_grp1 + state: present + +# CREATE LEAF SWITCH ASSOCIATION +- name: Create a leaf switch profile association + aci_fabric_leaf_switch_assoc: + <<: *aci_info + profile: ansible_leaf_switch_prf + name: ansible_leaf_switch_assoc + policy_group: ansible_leaf_pol_grp1 + state: present + +# CREATE SPINE SWITCH BLOCK +- name: Create a spine switch association block + aci_fabric_switch_block: + <<: *aci_info + switch_type: spine + profile: ansible_spine_switch_prf + association: ansible_spine_switch_assoc + name: ansible_spine_block + from_: 103 + to_: 103 + state: present + register: add_switch_block + +- name: Verify spine block creation + assert: + that: + - add_switch_block.current.0.fabricNodeBlk.attributes.dn == "uni/fabric/spprof-ansible_spine_switch_prf/spines-ansible_spine_switch_assoc-typ-range/nodeblk-ansible_spine_block" + - add_switch_block.current.0.fabricNodeBlk.attributes.name == "ansible_spine_block" + - add_switch_block.current.0.fabricNodeBlk.attributes.annotation == 'orchestrator:ansible' + +# ADD SPINE SWITCH BLOCK AGAIN TO TEST IDEMPOTENCE +- name: Create a spine switch association block again + aci_fabric_switch_block: + <<: *aci_info + switch_type: spine + profile: ansible_spine_switch_prf + association: ansible_spine_switch_assoc + name: ansible_spine_block + from_: 103 + to_: 103 + state: present + register: add_switch_block_again + +- name: Verify spine block creation idempotence + assert: + that: + - add_switch_block_again is not changed + - add_switch_block_again.current.0.fabricNodeBlk.attributes.dn == "uni/fabric/spprof-ansible_spine_switch_prf/spines-ansible_spine_switch_assoc-typ-range/nodeblk-ansible_spine_block" + - add_switch_block_again.current.0.fabricNodeBlk.attributes.name == "ansible_spine_block" + +# CREATE LEAF SWITCH BLOCK +- name: Create a leaf switch association block + aci_fabric_switch_block: + <<: *aci_info + switch_type: leaf + profile: ansible_leaf_switch_prf + association: ansible_leaf_switch_assoc + name: ansible_leaf_block + from_: 103 + to_: 103 + state: present + register: add_leaf_switch_block + +- name: Verify leaf block creation + assert: + that: + - add_leaf_switch_block.current.0.fabricNodeBlk.attributes.dn == "uni/fabric/leprof-ansible_leaf_switch_prf/leaves-ansible_leaf_switch_assoc-typ-range/nodeblk-ansible_leaf_block" + - add_leaf_switch_block.current.0.fabricNodeBlk.attributes.name == "ansible_leaf_block" + +# ADD LEAF SWITCH BLOCK AGAIN TO TEST IDEMPOTENCE +- name: Create a leaf switch association block again + aci_fabric_switch_block: + <<: *aci_info + switch_type: leaf + profile: ansible_leaf_switch_prf + association: ansible_leaf_switch_assoc + name: ansible_leaf_block + from_: 103 + to_: 103 + state: present + register: add_leaf_switch_block_again + +- name: Verify leaf block creation idempotence + assert: + that: + - add_leaf_switch_block_again is not changed + - add_leaf_switch_block_again.current.0.fabricNodeBlk.attributes.dn == "uni/fabric/leprof-ansible_leaf_switch_prf/leaves-ansible_leaf_switch_assoc-typ-range/nodeblk-ansible_leaf_block" + - add_leaf_switch_block_again.current.0.fabricNodeBlk.attributes.name == "ansible_leaf_block" + +# QUERY SPINE SWITCH BLOCK +- name: Query spine switch association block + aci_fabric_switch_block: + <<: *aci_info + switch_type: spine + profile: ansible_spine_switch_prf + association: ansible_spine_switch_assoc + name: ansible_spine_block + state: query + register: query_switch_block + +- name: Verify block query + assert: + that: + - query_switch_block is not changed + - query_switch_block.current.0.fabricNodeBlk.attributes.dn == "uni/fabric/spprof-ansible_spine_switch_prf/spines-ansible_spine_switch_assoc-typ-range/nodeblk-ansible_spine_block" + - query_switch_block.current.0.fabricNodeBlk.attributes.name == "ansible_spine_block" + +# QUERY LEAF SWITCH BLOCK +- name: Query leaf switch association block + aci_fabric_switch_block: + <<: *aci_info + switch_type: leaf + profile: ansible_leaf_switch_prf + association: ansible_leaf_switch_assoc + name: ansible_leaf_block + state: query + register: query_leaf_switch_block + +- name: Verify leaf block query + assert: + that: + - query_leaf_switch_block is not changed + - query_leaf_switch_block.current.0.fabricNodeBlk.attributes.dn == "uni/fabric/leprof-ansible_leaf_switch_prf/leaves-ansible_leaf_switch_assoc-typ-range/nodeblk-ansible_leaf_block" + - query_leaf_switch_block.current.0.fabricNodeBlk.attributes.name == "ansible_leaf_block" + +# REMOVE SPINE SWITCH BLOCK +- name: Remove spine switch association block + aci_fabric_switch_block: + <<: *aci_info + switch_type: spine + profile: ansible_spine_switch_prf + association: ansible_spine_switch_assoc + name: ansible_spine_block + state: absent + register: delete_switch_block + +- name: Verify spine switch block removal + assert: + that: + - delete_switch_block is changed + - delete_switch_block.current == [] + - delete_switch_block.previous.0.fabricNodeBlk.attributes.dn == "uni/fabric/spprof-ansible_spine_switch_prf/spines-ansible_spine_switch_assoc-typ-range/nodeblk-ansible_spine_block" + - delete_switch_block.previous.0.fabricNodeBlk.attributes.name == "ansible_spine_block" + +# REMOVE SPINE SWITCH BLOCK AGAIN TO TEST IDEMPOTENCE +- name: Remove spine switch association block + aci_fabric_switch_block: + <<: *aci_info + switch_type: spine + profile: ansible_spine_switch_prf + association: ansible_spine_switch_assoc + name: ansible_spine_block + state: absent + register: delete_switch_block + +- name: Verify spine switch block removal idempotence + assert: + that: + - delete_switch_block is not changed + - delete_switch_block.current == [] + +# REMOVE LEAF SWITCH BLOCK +- name: Remove leaf switch association block + aci_fabric_switch_block: + <<: *aci_info + switch_type: leaf + profile: ansible_leaf_switch_prf + association: ansible_leaf_switch_assoc + name: ansible_leaf_block + state: absent + register: delete_leaf_switch_block + +- name: Verify leaf switch block removal + assert: + that: + - delete_leaf_switch_block is changed + - delete_leaf_switch_block.current == [] + - delete_leaf_switch_block.previous.0.fabricNodeBlk.attributes.dn == "uni/fabric/leprof-ansible_leaf_switch_prf/leaves-ansible_leaf_switch_assoc-typ-range/nodeblk-ansible_leaf_block" + - delete_leaf_switch_block.previous.0.fabricNodeBlk.attributes.name == "ansible_leaf_block" + +# REMOVE LEAF SWITCH BLOCK AGAIN TO TEST IDEMPOTENCE +- name: Remove leaf switch association block + aci_fabric_switch_block: + <<: *aci_info + switch_type: leaf + profile: ansible_leaf_switch_prf + association: ansible_leaf_switch_assoc + name: ansible_leaf_block + state: absent + register: delete_leaf_switch_block + +- name: Verify leaf switch block removal idempotence + assert: + that: + - delete_leaf_switch_block is not changed + - delete_leaf_switch_block.current == [] + +# CLEAN UP ENVIRONMENT +- name: Remove ansible_spine_switch_prf + aci_fabric_spine_profile: + <<: *aci_info + name: ansible_spine_switch_prf + state: absent + +- name: Remove ansible_leaf_switch_prf + aci_fabric_leaf_profile: + <<: *aci_info + name: ansible_leaf_switch_prf + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_switch_policy_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_switch_policy_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_switch_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_switch_policy_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_switch_policy_group/tasks/main.yml new file mode 100644 index 000000000..83f5355a6 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_fabric_switch_policy_group/tasks/main.yml @@ -0,0 +1,344 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_fabric_leaf_policy_group if it already exists + cisco.aci.aci_fabric_switch_policy_group: + <<: *aci_info + name: ansible_fabric_leaf_policy_group + switch_type: leaf + state: absent + +- name: Remove ansible_fabric_spine_policy_group if it already exists + cisco.aci.aci_fabric_switch_policy_group: + <<: *aci_info + name: ansible_fabric_spine_policy_group + switch_type: spine + state: absent + +# ADD Fabric Leaf Policy Group +- name: Add ansible_fabric_leaf_policy_group + cisco.aci.aci_fabric_switch_policy_group: &aci_fabric_leaf_policy_group_present + <<: *aci_info + name: ansible_fabric_leaf_policy_group + switch_type: leaf + monitoring_policy: default + tech_support_export_policy: default + core_export_policy: default + inventory_policy: default + power_redundancy_policy: default + analytics_cluster: ansible_test + analytics_name: ansible_test + state: present + register: add_fabric_leaf_policy_group + +- name: Verify that ansible_fabric_leaf_policy_group has been created with correct attributes + assert: + that: + - add_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.attributes.dn == "uni/fabric/funcprof/lenodepgrp-ansible_fabric_leaf_policy_group" + - add_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.attributes.name == "ansible_fabric_leaf_policy_group" + - add_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.attributes.annotation == 'orchestrator:ansible' + +- name: Verify that ansible_fabric_leaf_policy_group children have correct attributes + assert: + that: + - add_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.0.fabricRsNodeCfgSrv.attributes.tDn == "uni/fabric/analytics/cluster-ansible_test/cfgsrv-ansible_test" + - add_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.1.fabricRsCallhomeInvPol.attributes.tnCallhomeInvPName == "default" + - add_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.2.fabricRsTwampResponderPol.attributes.tnTwampResponderPolName == "" + - add_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.3.fabricRsPsuInstPol.attributes.tnPsuInstPolName == "default" + - add_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.4.fabricRsTwampServerPol.attributes.tnTwampServerPolName == "" + - add_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.5.fabricRsNodeCtrl.attributes.tnFabricNodeControlName == "" + - add_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.6.fabricRsMonInstFabricPol.attributes.tnMonFabricPolName == "default" + - add_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.7.fabricRsNodeCoreP.attributes.tnDbgexpCorePName == "default" + - add_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.8.fabricRsNodeTechSupP.attributes.tnDbgexpTechSupPName == "default" + +# ADD Fabric Leaf Policy Group again to check idempotency +- name: Add ansible_fabric_leaf_policy_group again to test idempotence + cisco.aci.aci_fabric_switch_policy_group: + <<: *aci_fabric_leaf_policy_group_present + register: add_fabric_leaf_policy_group_again + +- name: Verify that ansible_fabric_leaf_policy_group has not been changed + assert: + that: + - add_fabric_leaf_policy_group_again is not changed + - add_fabric_leaf_policy_group_again.current.0.fabricLeNodePGrp.attributes.dn == "uni/fabric/funcprof/lenodepgrp-ansible_fabric_leaf_policy_group" + - add_fabric_leaf_policy_group_again.current.0.fabricLeNodePGrp.attributes.name == "ansible_fabric_leaf_policy_group" + +- name: Verify that ansible_fabric_leaf_policy_group children are still correct + assert: + that: + - add_fabric_leaf_policy_group_again.current.0.fabricLeNodePGrp.children.0.fabricRsNodeCfgSrv.attributes.tDn == "uni/fabric/analytics/cluster-ansible_test/cfgsrv-ansible_test" + - add_fabric_leaf_policy_group_again.current.0.fabricLeNodePGrp.children.1.fabricRsCallhomeInvPol.attributes.tnCallhomeInvPName == "default" + - add_fabric_leaf_policy_group_again.current.0.fabricLeNodePGrp.children.2.fabricRsTwampResponderPol.attributes.tnTwampResponderPolName == "" + - add_fabric_leaf_policy_group_again.current.0.fabricLeNodePGrp.children.3.fabricRsPsuInstPol.attributes.tnPsuInstPolName == "default" + - add_fabric_leaf_policy_group_again.current.0.fabricLeNodePGrp.children.4.fabricRsTwampServerPol.attributes.tnTwampServerPolName == "" + - add_fabric_leaf_policy_group_again.current.0.fabricLeNodePGrp.children.5.fabricRsNodeCtrl.attributes.tnFabricNodeControlName == "" + - add_fabric_leaf_policy_group_again.current.0.fabricLeNodePGrp.children.6.fabricRsMonInstFabricPol.attributes.tnMonFabricPolName == "default" + - add_fabric_leaf_policy_group_again.current.0.fabricLeNodePGrp.children.7.fabricRsNodeCoreP.attributes.tnDbgexpCorePName == "default" + - add_fabric_leaf_policy_group_again.current.0.fabricLeNodePGrp.children.8.fabricRsNodeTechSupP.attributes.tnDbgexpTechSupPName == "default" + +# ADD Fabric Spine Policy Group +- name: Add ansible_fabric_spine_policy_group + cisco.aci.aci_fabric_switch_policy_group: &aci_fabric_spine_policy_group_present + <<: *aci_info + name: ansible_fabric_spine_policy_group + switch_type: spine + monitoring_policy: default + tech_support_export_policy: default + core_export_policy: default + inventory_policy: default + power_redundancy_policy: default + state: present + register: add_fabric_spine_policy_group + +- name: Verify that ansible_fabric_spine_policy_group has been created with correct attributes + assert: + that: + - add_fabric_spine_policy_group.current.0.fabricSpNodePGrp.attributes.dn == "uni/fabric/funcprof/spnodepgrp-ansible_fabric_spine_policy_group" + - add_fabric_spine_policy_group.current.0.fabricSpNodePGrp.attributes.name == "ansible_fabric_spine_policy_group" + +- name: Verify that ansible_fabric_spine_policy_group children have correct attributes + assert: + that: + - add_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.0.fabricRsCallhomeInvPol.attributes.tnCallhomeInvPName == "default" + - add_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.1.fabricRsTwampResponderPol.attributes.tnTwampResponderPolName == "" + - add_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.2.fabricRsPsuInstPol.attributes.tnPsuInstPolName == "default" + - add_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.3.fabricRsTwampServerPol.attributes.tnTwampServerPolName == "" + - add_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.4.fabricRsNodeCtrl.attributes.tnFabricNodeControlName == "" + - add_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.5.fabricRsMonInstFabricPol.attributes.tnMonFabricPolName == "default" + - add_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.6.fabricRsNodeCoreP.attributes.tnDbgexpCorePName == "default" + - add_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.7.fabricRsNodeTechSupP.attributes.tnDbgexpTechSupPName == "default" + +# ADD Fabric Spine Policy Group again to check idempotency +- name: Add ansible_fabric_spine_policy_group again to test idempotence + cisco.aci.aci_fabric_switch_policy_group: + <<: *aci_fabric_spine_policy_group_present + register: add_fabric_spine_policy_group_again + +- name: Verify that ansible_fabric_spine_policy_group has not been changed + assert: + that: + - add_fabric_spine_policy_group_again is not changed + - add_fabric_spine_policy_group_again.current.0.fabricSpNodePGrp.attributes.dn == "uni/fabric/funcprof/spnodepgrp-ansible_fabric_spine_policy_group" + - add_fabric_spine_policy_group_again.current.0.fabricSpNodePGrp.attributes.name == "ansible_fabric_spine_policy_group" + +- name: Verify that ansible_fabric_spine_policy_group children are still correct + assert: + that: + - add_fabric_spine_policy_group_again.current.0.fabricSpNodePGrp.children.0.fabricRsCallhomeInvPol.attributes.tnCallhomeInvPName == "default" + - add_fabric_spine_policy_group_again.current.0.fabricSpNodePGrp.children.1.fabricRsTwampResponderPol.attributes.tnTwampResponderPolName == "" + - add_fabric_spine_policy_group_again.current.0.fabricSpNodePGrp.children.2.fabricRsPsuInstPol.attributes.tnPsuInstPolName == "default" + - add_fabric_spine_policy_group_again.current.0.fabricSpNodePGrp.children.3.fabricRsTwampServerPol.attributes.tnTwampServerPolName == "" + - add_fabric_spine_policy_group_again.current.0.fabricSpNodePGrp.children.4.fabricRsNodeCtrl.attributes.tnFabricNodeControlName == "" + - add_fabric_spine_policy_group_again.current.0.fabricSpNodePGrp.children.5.fabricRsMonInstFabricPol.attributes.tnMonFabricPolName == "default" + - add_fabric_spine_policy_group_again.current.0.fabricSpNodePGrp.children.6.fabricRsNodeCoreP.attributes.tnDbgexpCorePName == "default" + - add_fabric_spine_policy_group_again.current.0.fabricSpNodePGrp.children.7.fabricRsNodeTechSupP.attributes.tnDbgexpTechSupPName == "default" + +# MODIFY Fabric Leaf Policy Group +- name: Update ansible_fabric_leaf_policy_group + cisco.aci.aci_fabric_switch_policy_group: + <<: *aci_info + name: ansible_fabric_leaf_policy_group + switch_type: leaf + twamp_server_policy: default + twamp_responder_policy: default + node_control_policy: default + register: update_fabric_leaf_policy_group + +- name: Verify ansible_fabric_leaf_policy_group is changed + assert: + that: + - update_fabric_leaf_policy_group is changed + - update_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.attributes.dn == "uni/fabric/funcprof/lenodepgrp-ansible_fabric_leaf_policy_group" + - update_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.attributes.name == "ansible_fabric_leaf_policy_group" + +- name: Verify ansible_fabric_leaf_policy_group children are updated + assert: + that: + - update_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.0.fabricRsNodeCfgSrv.attributes.tDn == "uni/fabric/analytics/cluster-ansible_test/cfgsrv-ansible_test" + - update_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.1.fabricRsCallhomeInvPol.attributes.tnCallhomeInvPName == "default" + - update_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.2.fabricRsTwampResponderPol.attributes.tnTwampResponderPolName == "default" + - update_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.3.fabricRsPsuInstPol.attributes.tnPsuInstPolName == "default" + - update_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.4.fabricRsTwampServerPol.attributes.tnTwampServerPolName == "default" + - update_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.5.fabricRsNodeCtrl.attributes.tnFabricNodeControlName == "default" + - update_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.6.fabricRsMonInstFabricPol.attributes.tnMonFabricPolName == "default" + - update_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.7.fabricRsNodeCoreP.attributes.tnDbgexpCorePName == "default" + - update_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.8.fabricRsNodeTechSupP.attributes.tnDbgexpTechSupPName == "default" + +# MODIFY Fabric Spine Policy Group +- name: Update ansible_fabric_spine_policy_group + cisco.aci.aci_fabric_switch_policy_group: + <<: *aci_info + name: ansible_fabric_spine_policy_group + switch_type: spine + twamp_server_policy: default + twamp_responder_policy: default + node_control_policy: default + register: update_fabric_spine_policy_group + +- name: Verify ansible_fabric_spine_policy_group is changed + assert: + that: + - update_fabric_spine_policy_group is changed + - update_fabric_spine_policy_group.current.0.fabricSpNodePGrp.attributes.dn == "uni/fabric/funcprof/spnodepgrp-ansible_fabric_spine_policy_group" + - update_fabric_spine_policy_group.current.0.fabricSpNodePGrp.attributes.name == "ansible_fabric_spine_policy_group" + +- name: Verify ansible_fabric_spine_policy_group children are updated + assert: + that: + - update_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.0.fabricRsCallhomeInvPol.attributes.tnCallhomeInvPName == "default" + - update_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.1.fabricRsTwampResponderPol.attributes.tnTwampResponderPolName == "default" + - update_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.2.fabricRsPsuInstPol.attributes.tnPsuInstPolName == "default" + - update_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.3.fabricRsTwampServerPol.attributes.tnTwampServerPolName == "default" + - update_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.4.fabricRsNodeCtrl.attributes.tnFabricNodeControlName == "default" + - update_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.5.fabricRsMonInstFabricPol.attributes.tnMonFabricPolName == "default" + - update_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.6.fabricRsNodeCoreP.attributes.tnDbgexpCorePName == "default" + - update_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.7.fabricRsNodeTechSupP.attributes.tnDbgexpTechSupPName == "default" + +# QUERY Fabric Leaf Policy Group +- name: Query ansible_fabric_leaf_policy_group + cisco.aci.aci_fabric_switch_policy_group: + <<: *aci_info + name: ansible_fabric_leaf_policy_group + switch_type: leaf + state: query + register: query_fabric_leaf_policy_group + +- name: Verify attributes + assert: + that: + - query_fabric_leaf_policy_group is not changed + - query_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.attributes.dn == "uni/fabric/funcprof/lenodepgrp-ansible_fabric_leaf_policy_group" + - query_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.attributes.name == "ansible_fabric_leaf_policy_group" + +- name: Verify children + assert: + that: + - query_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.0.fabricRsNodeCfgSrv.attributes.tDn == "uni/fabric/analytics/cluster-ansible_test/cfgsrv-ansible_test" + - query_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.1.fabricRsCallhomeInvPol.attributes.tnCallhomeInvPName == "default" + - query_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.2.fabricRsTwampResponderPol.attributes.tnTwampResponderPolName == "default" + - query_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.3.fabricRsPsuInstPol.attributes.tnPsuInstPolName == "default" + - query_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.4.fabricRsTwampServerPol.attributes.tnTwampServerPolName == "default" + - query_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.5.fabricRsNodeCtrl.attributes.tnFabricNodeControlName == "default" + - query_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.6.fabricRsMonInstFabricPol.attributes.tnMonFabricPolName == "default" + - query_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.7.fabricRsNodeCoreP.attributes.tnDbgexpCorePName == "default" + - query_fabric_leaf_policy_group.current.0.fabricLeNodePGrp.children.8.fabricRsNodeTechSupP.attributes.tnDbgexpTechSupPName == "default" + +- name: Query all Fabric Leaf Policy Groups + cisco.aci.aci_fabric_switch_policy_group: + <<: *aci_info + switch_type: leaf + state: query + register: query_fabric_leaf_policy_group_all + +- name: Verify query all is idempotent + assert: + that: + - query_fabric_leaf_policy_group_all is not changed + +# QUERY Fabric Spine Policy Group +- name: Query ansible_fabric_spine_policy_group + cisco.aci.aci_fabric_switch_policy_group: + <<: *aci_info + name: ansible_fabric_spine_policy_group + switch_type: spine + state: query + register: query_fabric_spine_policy_group + +- name: Verify attributes + assert: + that: + - query_fabric_spine_policy_group is not changed + - query_fabric_spine_policy_group.current.0.fabricSpNodePGrp.attributes.dn == "uni/fabric/funcprof/spnodepgrp-ansible_fabric_spine_policy_group" + - query_fabric_spine_policy_group.current.0.fabricSpNodePGrp.attributes.name == "ansible_fabric_spine_policy_group" + +- name: Verify children + assert: + that: + - query_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.0.fabricRsCallhomeInvPol.attributes.tnCallhomeInvPName == "default" + - query_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.1.fabricRsTwampResponderPol.attributes.tnTwampResponderPolName == "default" + - query_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.2.fabricRsPsuInstPol.attributes.tnPsuInstPolName == "default" + - query_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.3.fabricRsTwampServerPol.attributes.tnTwampServerPolName == "default" + - query_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.4.fabricRsNodeCtrl.attributes.tnFabricNodeControlName == "default" + - query_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.5.fabricRsMonInstFabricPol.attributes.tnMonFabricPolName == "default" + - query_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.6.fabricRsNodeCoreP.attributes.tnDbgexpCorePName == "default" + - query_fabric_spine_policy_group.current.0.fabricSpNodePGrp.children.7.fabricRsNodeTechSupP.attributes.tnDbgexpTechSupPName == "default" + +- name: Query all Fabric Spine Policy Groups + cisco.aci.aci_fabric_switch_policy_group: + <<: *aci_info + switch_type: spine + state: query + register: query_fabric_spine_policy_group_all + +- name: Verify query all is idempotent + assert: + that: + - query_fabric_spine_policy_group_all is not changed + +# DELETE Fabric Leaf Policy Group +- name: Remove ansible_fabric_leaf_policy_group + cisco.aci.aci_fabric_switch_policy_group: + <<: *aci_info + name: ansible_fabric_leaf_policy_group + switch_type: leaf + state: absent + register: delete_fabric_leaf_policy_group + +- name: Verify Fabric Leaf Policy Group deletion + assert: + that: + - delete_fabric_leaf_policy_group is changed + - delete_fabric_leaf_policy_group.current == [] + - delete_fabric_leaf_policy_group.previous.0.fabricLeNodePGrp.children.0.fabricRsNodeCfgSrv.attributes.tDn == "uni/fabric/analytics/cluster-ansible_test/cfgsrv-ansible_test" + - delete_fabric_leaf_policy_group.previous.0.fabricLeNodePGrp.children.1.fabricRsCallhomeInvPol.attributes.tnCallhomeInvPName == "default" + - delete_fabric_leaf_policy_group.previous.0.fabricLeNodePGrp.children.2.fabricRsTwampResponderPol.attributes.tnTwampResponderPolName == "default" + - delete_fabric_leaf_policy_group.previous.0.fabricLeNodePGrp.children.3.fabricRsPsuInstPol.attributes.tnPsuInstPolName == "default" + - delete_fabric_leaf_policy_group.previous.0.fabricLeNodePGrp.children.4.fabricRsTwampServerPol.attributes.tnTwampServerPolName == "default" + - delete_fabric_leaf_policy_group.previous.0.fabricLeNodePGrp.children.5.fabricRsNodeCtrl.attributes.tnFabricNodeControlName == "default" + - delete_fabric_leaf_policy_group.previous.0.fabricLeNodePGrp.children.6.fabricRsMonInstFabricPol.attributes.tnMonFabricPolName == "default" + - delete_fabric_leaf_policy_group.previous.0.fabricLeNodePGrp.children.7.fabricRsNodeCoreP.attributes.tnDbgexpCorePName == "default" + - delete_fabric_leaf_policy_group.previous.0.fabricLeNodePGrp.children.8.fabricRsNodeTechSupP.attributes.tnDbgexpTechSupPName == "default" + +# DELETE Fabric Spine Policy Group +- name: Remove ansible_fabric_spine_policy_group + cisco.aci.aci_fabric_switch_policy_group: + <<: *aci_info + name: ansible_fabric_spine_policy_group + switch_type: spine + state: absent + register: delete_fabric_spine_policy_group + +- name: Verify Fabric Spine Policy Group deletion + assert: + that: + - delete_fabric_spine_policy_group is changed + - delete_fabric_spine_policy_group.current == [] + - delete_fabric_spine_policy_group.previous.0.fabricSpNodePGrp.children.0.fabricRsCallhomeInvPol.attributes.tnCallhomeInvPName == "default" + - delete_fabric_spine_policy_group.previous.0.fabricSpNodePGrp.children.1.fabricRsTwampResponderPol.attributes.tnTwampResponderPolName == "default" + - delete_fabric_spine_policy_group.previous.0.fabricSpNodePGrp.children.2.fabricRsPsuInstPol.attributes.tnPsuInstPolName == "default" + - delete_fabric_spine_policy_group.previous.0.fabricSpNodePGrp.children.3.fabricRsTwampServerPol.attributes.tnTwampServerPolName == "default" + - delete_fabric_spine_policy_group.previous.0.fabricSpNodePGrp.children.4.fabricRsNodeCtrl.attributes.tnFabricNodeControlName == "default" + - delete_fabric_spine_policy_group.previous.0.fabricSpNodePGrp.children.5.fabricRsMonInstFabricPol.attributes.tnMonFabricPolName == "default" + - delete_fabric_spine_policy_group.previous.0.fabricSpNodePGrp.children.6.fabricRsNodeCoreP.attributes.tnDbgexpCorePName == "default" + - delete_fabric_spine_policy_group.previous.0.fabricSpNodePGrp.children.7.fabricRsNodeTechSupP.attributes.tnDbgexpTechSupPName == "default" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_filter/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_filter/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_filter/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_filter/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_filter/tasks/main.yml new file mode 100644 index 000000000..a8928de57 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_filter/tasks/main.yml @@ -0,0 +1,224 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.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 + +# CLEAN ENVIRONMENT +- name: Add 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") }}' + tenant: ansible_test + state: present + +- name: Remove filter + cisco.aci.aci_filter: &filter_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 + filter: filter_test + state: absent + +# ADD FILTER +- name: Add filter (check_mode) + cisco.aci.aci_filter: &filter_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 + filter: filter_test + state: present + check_mode: true + register: cm_add_filter + +- name: Add filter again (check_mode) + cisco.aci.aci_filter: *filter_present + check_mode: true + register: cm_add_filter_again + +- name: Add filter (normal mode) + cisco.aci.aci_filter: *filter_present + register: nm_add_filter + +- name: Add filter again (normal mode) + cisco.aci.aci_filter: *filter_present + register: nm_add_filter_again + +- name: Verify add_filter + assert: + that: + - cm_add_filter is changed + - cm_add_filter_again is changed + - nm_add_filter is changed + - nm_add_filter.current.0.vzFilter.attributes.annotation == 'orchestrator:ansible' + - nm_add_filter_again is not changed + +# CHANGE FILTER +- name: Change description of filter (check_mode) + cisco.aci.aci_filter: + <<: *filter_present + description: Ansible test filter + check_mode: true + register: cm_add_filter_descr + +- name: Change description of filter again (check_mode) + cisco.aci.aci_filter: + <<: *filter_present + description: Ansible test filter + check_mode: true + register: cm_add_filter_descr_again + +- name: Change description of filter (normal mode) + cisco.aci.aci_filter: + <<: *filter_present + description: Ansible test filter + register: nm_add_filter_descr + +- name: Change description of filter again (normal mode) + cisco.aci.aci_filter: + <<: *filter_present + description: Ansible test filter + register: nm_add_filter_descr_again + +- name: Verify add_filter_descr + assert: + that: + - cm_add_filter_descr is changed + - cm_add_filter_descr_again is changed + - nm_add_filter_descr is changed + - nm_add_filter_descr_again is not changed + +# ADD FILTER AGAIN +- name: Add filter again with no description (check_mode) + cisco.aci.aci_filter: *filter_present + check_mode: true + register: cm_add_filter_again_no_descr + +- name: Add filter again with no description (normal mode) + cisco.aci.aci_filter: *filter_present + register: nm_add_filter_again_no_descr + +- name: Verify add_filter_again_no_descr + assert: + that: + - cm_add_filter_again_no_descr is not changed + - nm_add_filter_again_no_descr is not changed + +# QUERY ALL FILTERS +- name: Query all filters (check_mode) + cisco.aci.aci_filter: &filter_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") }}' + state: query + check_mode: true + register: cm_query_all_filters + +- name: Query all filters (normal mode) + cisco.aci.aci_filter: *filter_query + register: nm_query_all_filters + +- name: Verify query_all_filters + assert: + that: + - cm_query_all_filters is not changed + - nm_query_all_filters is not changed + # NOTE: Order of filters is not stable between calls + #- cm_query_all_filters == nm_query_all_filters + +# QUERY A FILTER +- name: Query our filter + cisco.aci.aci_filter: + <<: *filter_query + tenant: ansible_test + filter: filter_test + check_mode: true + register: cm_query_filter + +- name: Query our filter + cisco.aci.aci_filter: + <<: *filter_query + tenant: ansible_test + filter: filter_test + register: nm_query_filter + +- name: Verify query_filter + assert: + that: + - cm_query_filter is not changed + - nm_query_filter is not changed + - cm_query_filter == nm_query_filter + +# REMOVE FILTER +- name: Remove filter (check_mode) + cisco.aci.aci_filter: *filter_absent + check_mode: true + register: cm_remove_filter + +- name: Remove filter again (check_mode) + cisco.aci.aci_filter: *filter_absent + check_mode: true + register: cm_remove_filter_again + +- name: Remove filter (normal mode) + cisco.aci.aci_filter: *filter_absent + register: nm_remove_filter + +- name: Remove filter again (normal mode) + cisco.aci.aci_filter: *filter_absent + register: nm_remove_filter_again + +- name: Verify remove_filter + assert: + that: + - cm_remove_filter is changed + - cm_remove_filter_again is changed + - nm_remove_filter is changed + - nm_remove_filter_again is not changed + +# QUERY NON-EXISTING FILTER +# FIXME: Should this fail or return empty values ? +- name: Query non-existing filter (check_mode) + cisco.aci.aci_filter: + <<: *filter_query + tenant: ansible_test + filter: filter_test + check_mode: true + register: cm_query_non_filter + +- name: Query non-existing filter (normal mode) + cisco.aci.aci_filter: + <<: *filter_query + tenant: ansible_test + filter: filter_test + register: nm_query_non_filter + +- name: Verify query_non_filter + assert: + that: + - cm_query_non_filter is not changed + - nm_query_non_filter is not changed + - cm_query_non_filter == nm_query_non_filter diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_filter_entry/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_filter_entry/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_filter_entry/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..77093a670 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_filter_entry/tasks/main.yml @@ -0,0 +1,315 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) + +# 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 + +# CLEAN ENVIRONMENT +- 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: 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 diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_source/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_source/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_source/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_source/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_source/tasks/main.yml new file mode 100644 index 000000000..d9287506c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_firmware_source/tasks/main.yml @@ -0,0 +1,208 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.com> +# Copyright: (c) 2020, Cindy Zhao (@cizhao) <cizhao@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# CLEAN ENVIRONMENT +- name: Remove firmware source + cisco.aci.aci_firmware_source: &source_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") }}' + source: '{{ item }}' + state: absent + loop: + - ansible_test_1 + - ansible_test_2 + +# ADD SOURCE +- name: Add source (check_mode) + aci_firmware_source: &source_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") }}' + source: ansible_test_1 + url: foobar.cisco.com/download/cisco/aci/aci-msft-pkg-3.1.1i.zip + url_protocol: http + state: present + check_mode: true + register: cm_add_source + +- name: Add source (normal mode) + aci_firmware_source: + <<: *source_present + register: nm_add_source + +- name: Verify add_source + assert: + that: + - cm_add_source is changed + - nm_add_source is changed + - cm_add_source.sent.firmwareOSource.attributes.name == nm_add_source.sent.firmwareOSource.attributes.name == 'ansible_test_1' + - cm_add_source.sent.firmwareOSource.attributes.proto == nm_add_source.sent.firmwareOSource.attributes.proto == 'http' + - cm_add_source.sent.firmwareOSource.attributes.url == nm_add_source.sent.firmwareOSource.attributes.url == 'foobar.cisco.com/download/cisco/aci/aci-msft-pkg-3.1.1i.zip' + - cm_add_source.proposed.firmwareOSource.attributes.name == nm_add_source.proposed.firmwareOSource.attributes.name == 'ansible_test_1' + - cm_add_source.proposed.firmwareOSource.attributes.proto == nm_add_source.proposed.firmwareOSource.attributes.proto == 'http' + - cm_add_source.proposed.firmwareOSource.attributes.url == nm_add_source.proposed.firmwareOSource.attributes.url == 'foobar.cisco.com/download/cisco/aci/aci-msft-pkg-3.1.1i.zip' + - cm_add_source.current == cm_add_source.previous == nm_add_source.previous == [] + - nm_add_source.current.0.firmwareOSource.attributes.name == 'ansible_test_1' + - nm_add_source.current.0.firmwareOSource.attributes.proto == 'http' + - nm_add_source.current.0.firmwareOSource.attributes.url == 'foobar.cisco.com/download/cisco/aci/aci-msft-pkg-3.1.1i.zip' + - nm_add_source.current.0.firmwareOSource.attributes.annotation == 'orchestrator:ansible' + +- name: Add source again (check_mode) + aci_firmware_source: *source_present + check_mode: true + register: cm_add_source_again + +- name: Add source again (normal mode) + aci_firmware_source: + <<: *source_present + register: nm_add_source_again + +- name: Verify add_source_again + assert: + that: + - cm_add_source_again is not changed + +- name: Add another source (normal mode) + aci_firmware_source: + <<: *source_present + source: ansible_test_2 + register: nm_add_source + +# QUERY ALL SOURCES +- name: Query all sources (check_mode) + cisco.aci.aci_firmware_source: &source_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") }}' + state: query + check_mode: true + register: cm_query_all_sources + +- name: Query all sources (normal mode) + cisco.aci.aci_firmware_source: *source_query + register: nm_query_all_sources + +- name: Verify query_all_sources + assert: + that: + - cm_query_all_sources is not changed + - nm_query_all_sources is not changed + - cm_query_all_sources == nm_query_all_sources + - nm_query_all_sources.current.0.firmwareRepoP.children | length >= 2 + +# QUERY A SOURCE +- name: Query our source (check_mode) + aci_firmware_source: + <<: *source_query + source: ansible_test_1 + check_mode: true + register: cm_query_source + +- name: Query our source (normal mode) + aci_firmware_source: + <<: *source_query + source: ansible_test_1 + register: nm_query_source + +- name: Verify query_source + assert: + that: + - cm_query_source is not changed + - nm_query_source is not changed + - cm_query_source == nm_query_source + - nm_query_source.current.0.firmwareOSource.attributes.dn == 'uni/fabric/fwrepop/osrc-ansible_test_1' + - nm_query_source.current.0.firmwareOSource.attributes.name == 'ansible_test_1' + +# REMOVE SOURCE +- name: Remove source (check_mode) + aci_firmware_source: &source_remove + <<: *source_query + source: ansible_test_1 + state: absent + check_mode: true + register: cm_remove_source + +- name: Remove source (normal mode) + aci_firmware_source: *source_remove + register: nm_remove_source + +- name: Verify remove_source + assert: + that: + - cm_remove_source is changed + - nm_remove_source is changed + - cm_remove_source.current.0.firmwareOSource.attributes.dn == cm_remove_source.previous.0.firmwareOSource.attributes.dn == nm_remove_source.previous.0.firmwareOSource.attributes.dn == 'uni/fabric/fwrepop/osrc-ansible_test_1' + - nm_remove_source.current == [] + +- name: Remove source again (check_mode) + aci_firmware_source: *source_remove + check_mode: true + register: cm_remove_source_again + +- name: Remove source again (normal mode) + aci_firmware_source: *source_remove + register: nm_remove_source_again + +- name: Verify remove_source_again + assert: + that: + - cm_remove_source_again is not changed + - nm_remove_source_again is not changed + +# QUERY NON-EXISTING SOURCE +- name: Query non-existing source (check_mode) + aci_firmware_source: + <<: *source_query + source: non_existing_source + check_mode: true + register: cm_query_non_source + +- name: Query non-existing source (normal mode) + aci_firmware_source: + <<: *source_query + source: non_existing_source + register: nm_query_non_source + +- name: Verify query_non_source + assert: + that: + - cm_query_non_source is not changed + - nm_query_non_source is not changed + - cm_query_non_source == nm_query_non_source + - nm_query_non_source.current == [] + +# PROVOKE ERRORS +- name: Error when required parameter is missing + cisco.aci.aci_firmware_source: + 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") }}' + state: present + ignore_errors: true + register: error_on_missing_required_param + +- name: Verify error_on_missing_required_param + assert: + that: + - error_on_missing_required_param is failed + - 'error_on_missing_required_param.msg == "state is present but all of the following are missing: source, url"' diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_igmp_interface_policy/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_igmp_interface_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_igmp_interface_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_igmp_interface_policy/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_igmp_interface_policy/tasks/main.yml new file mode 100644 index 000000000..eac9daf6b --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_igmp_interface_policy/tasks/main.yml @@ -0,0 +1,239 @@ +# 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 }}" + port: "{{ aci_port | default(omit) }}" + 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_tenant + cisco.aci.aci_tenant: + <<: *aci_info + name: ansible_tenant + state: absent + +# CREATE IGMP INTERFACE POLICY +- name: Create the ansible_tenant + cisco.aci.aci_tenant: + <<: *aci_info + name: ansible_tenant + state: present + +- name: Create an IGMP interface policy (check mode) + cisco.aci.aci_igmp_interface_policy: &aci_igmp + <<: *aci_info + name: ansible_igmp_intf_policy + tenant: ansible_tenant + description: Test IGMP Interface Policy + group_timeout: 300 + query_interval: 100 + query_response_interval: 8 + last_member_count: 3 + last_member_response: 5 + startup_query_count: 3 + startup_query_interval: 5 + querier_timeout: 200 + robustness_variable: 3 + igmp_version: v3 + allow_v3_asm: true + fast_leave: true + report_link_local_groups: false + check_mode: yes + register: cm_create_igmp_intf_policy + +- name: Create an IGMP interface policy + cisco.aci.aci_igmp_interface_policy: + <<: *aci_igmp + register: nm_create_igmp_intf_policy + +- name: Create IGMP interface policy again to test idempotence + cisco.aci.aci_igmp_interface_policy: + <<: *aci_igmp + register: nm_create_igmp_intf_policy_again + +- name: Create IGMP interface policy with default parameters + cisco.aci.aci_igmp_interface_policy: + <<: *aci_info + name: ansible_igmp_dflt_intf_policy + tenant: ansible_tenant + register: default_igmp_intf_policy + +- name: Verify creation of IGMP interface policy + ansible.builtin.assert: + that: + - cm_create_igmp_intf_policy is changed + - nm_create_igmp_intf_policy is changed + - nm_create_igmp_intf_policy_again is not changed + - nm_create_igmp_intf_policy.current.0.igmpIfPol.attributes.dn == "uni/tn-ansible_tenant/igmpIfPol-ansible_igmp_intf_policy" + - nm_create_igmp_intf_policy.current.0.igmpIfPol.attributes.descr == "Test IGMP Interface Policy" + - nm_create_igmp_intf_policy.current.0.igmpIfPol.attributes.name == "ansible_igmp_intf_policy" + - nm_create_igmp_intf_policy.current.0.igmpIfPol.attributes.grpTimeout == "300" + - nm_create_igmp_intf_policy.current.0.igmpIfPol.attributes.queryIntvl == "100" + - nm_create_igmp_intf_policy.current.0.igmpIfPol.attributes.rspIntvl == "8" + - nm_create_igmp_intf_policy.current.0.igmpIfPol.attributes.lastMbrCnt == "3" + - nm_create_igmp_intf_policy.current.0.igmpIfPol.attributes.lastMbrRespTime == "5" + - nm_create_igmp_intf_policy.current.0.igmpIfPol.attributes.startQueryCnt == "3" + - nm_create_igmp_intf_policy.current.0.igmpIfPol.attributes.startQueryIntvl == "5" + - nm_create_igmp_intf_policy.current.0.igmpIfPol.attributes.querierTimeout == "200" + - nm_create_igmp_intf_policy.current.0.igmpIfPol.attributes.robustFac == "3" + - nm_create_igmp_intf_policy.current.0.igmpIfPol.attributes.ver == "v3" + - nm_create_igmp_intf_policy.current.0.igmpIfPol.attributes.ifCtrl == "allow-v3-asm,fast-leave" + - nm_create_igmp_intf_policy_again.current.0.igmpIfPol.attributes.dn == "uni/tn-ansible_tenant/igmpIfPol-ansible_igmp_intf_policy" + - nm_create_igmp_intf_policy_again.current.0.igmpIfPol.attributes.descr == "Test IGMP Interface Policy" + - nm_create_igmp_intf_policy_again.current.0.igmpIfPol.attributes.name == "ansible_igmp_intf_policy" + - nm_create_igmp_intf_policy_again.current.0.igmpIfPol.attributes.grpTimeout == "300" + - nm_create_igmp_intf_policy_again.current.0.igmpIfPol.attributes.queryIntvl == "100" + - nm_create_igmp_intf_policy_again.current.0.igmpIfPol.attributes.rspIntvl == "8" + - nm_create_igmp_intf_policy_again.current.0.igmpIfPol.attributes.lastMbrCnt == "3" + - nm_create_igmp_intf_policy_again.current.0.igmpIfPol.attributes.lastMbrRespTime == "5" + - nm_create_igmp_intf_policy_again.current.0.igmpIfPol.attributes.startQueryCnt == "3" + - nm_create_igmp_intf_policy_again.current.0.igmpIfPol.attributes.startQueryIntvl == "5" + - nm_create_igmp_intf_policy_again.current.0.igmpIfPol.attributes.querierTimeout == "200" + - nm_create_igmp_intf_policy_again.current.0.igmpIfPol.attributes.robustFac == "3" + - nm_create_igmp_intf_policy_again.current.0.igmpIfPol.attributes.ver == "v3" + - nm_create_igmp_intf_policy_again.current.0.igmpIfPol.attributes.ifCtrl == "allow-v3-asm,fast-leave" + +- name: Verify default values + ansible.builtin.assert: + that: + - default_igmp_intf_policy.current.0.igmpIfPol.attributes.grpTimeout == "260" + - default_igmp_intf_policy.current.0.igmpIfPol.attributes.queryIntvl == "125" + - default_igmp_intf_policy.current.0.igmpIfPol.attributes.rspIntvl == "10" + - default_igmp_intf_policy.current.0.igmpIfPol.attributes.lastMbrCnt == "2" + - default_igmp_intf_policy.current.0.igmpIfPol.attributes.lastMbrRespTime == "1" + - default_igmp_intf_policy.current.0.igmpIfPol.attributes.startQueryCnt == "2" + - default_igmp_intf_policy.current.0.igmpIfPol.attributes.startQueryIntvl == "31" + - default_igmp_intf_policy.current.0.igmpIfPol.attributes.querierTimeout == "255" + - default_igmp_intf_policy.current.0.igmpIfPol.attributes.robustFac == "2" + - default_igmp_intf_policy.current.0.igmpIfPol.attributes.ver == "v2" + - default_igmp_intf_policy.current.0.igmpIfPol.attributes.ifCtrl == "" + +# UPDATE IGMP INTERFACE POLICY +- name: Update IGMP Interface Policy + cisco.aci.aci_igmp_interface_policy: + <<: *aci_igmp + description: Updated IGMP Interface Policy + group_timeout: 250 + query_interval: 150 + query_response_interval: 7 + last_member_count: 4 + last_member_response: 6 + startup_query_count: 4 + startup_query_interval: 6 + querier_timeout: 180 + robustness_variable: 5 + igmp_version: v2 + allow_v3_asm: false + fast_leave: false + report_link_local_groups: true + register: update_igmp_intf_policy + +- name: Update IGMP Interface Policy without ifCtrl options + cisco.aci.aci_igmp_interface_policy: + <<: *aci_info + name: ansible_igmp_intf_policy + tenant: ansible_tenant + igmp_version: v3 + register: update_igmp_no_ifctrl + +- name: Verify update of IGMP Interface Policy + ansible.builtin.assert: + that: + - update_igmp_intf_policy is changed + - update_igmp_intf_policy.current.0.igmpIfPol.attributes.dn == "uni/tn-ansible_tenant/igmpIfPol-ansible_igmp_intf_policy" + - update_igmp_intf_policy.current.0.igmpIfPol.attributes.descr == "Updated IGMP Interface Policy" + - update_igmp_intf_policy.current.0.igmpIfPol.attributes.name == "ansible_igmp_intf_policy" + - update_igmp_intf_policy.current.0.igmpIfPol.attributes.grpTimeout == "250" + - update_igmp_intf_policy.current.0.igmpIfPol.attributes.queryIntvl == "150" + - update_igmp_intf_policy.current.0.igmpIfPol.attributes.rspIntvl == "7" + - update_igmp_intf_policy.current.0.igmpIfPol.attributes.lastMbrCnt == "4" + - update_igmp_intf_policy.current.0.igmpIfPol.attributes.lastMbrRespTime == "6" + - update_igmp_intf_policy.current.0.igmpIfPol.attributes.startQueryCnt == "4" + - update_igmp_intf_policy.current.0.igmpIfPol.attributes.startQueryIntvl == "6" + - update_igmp_intf_policy.current.0.igmpIfPol.attributes.querierTimeout == "180" + - update_igmp_intf_policy.current.0.igmpIfPol.attributes.robustFac == "5" + - update_igmp_intf_policy.current.0.igmpIfPol.attributes.ver == "v2" + - update_igmp_intf_policy.current.0.igmpIfPol.attributes.ifCtrl == "rep-ll" + +- name: Verify an update without ifCtrl options present leaves existing ifCtrl in place + ansible.builtin.assert: + that: + - update_igmp_no_ifctrl is changed + - update_igmp_no_ifctrl.current.0.igmpIfPol.attributes.ver == "v3" + - update_igmp_no_ifctrl.current.0.igmpIfPol.attributes.ifCtrl == "rep-ll" + +# QUERY IGMP INTERFACE POLICY +- name: Query an IGMP Interface Policy + cisco.aci.aci_igmp_interface_policy: + <<: *aci_igmp + state: query + register: query_one + +- name: Query all IGMP Interface Policies + cisco.aci.aci_igmp_interface_policy: + <<: *aci_info + state: query + register: query_all + +- name: Verify IGMP Interface Policy queries + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current.0.igmpIfPol.attributes.dn == "uni/tn-ansible_tenant/igmpIfPol-ansible_igmp_intf_policy" + - query_one.current.0.igmpIfPol.attributes.descr == "Updated IGMP Interface Policy" + - query_one.current.0.igmpIfPol.attributes.name == "ansible_igmp_intf_policy" + - query_one.current.0.igmpIfPol.attributes.grpTimeout == "250" + - query_one.current.0.igmpIfPol.attributes.queryIntvl == "150" + - query_one.current.0.igmpIfPol.attributes.rspIntvl == "7" + - query_one.current.0.igmpIfPol.attributes.lastMbrCnt == "4" + - query_one.current.0.igmpIfPol.attributes.lastMbrRespTime == "6" + - query_one.current.0.igmpIfPol.attributes.startQueryCnt == "4" + - query_one.current.0.igmpIfPol.attributes.startQueryIntvl == "6" + - query_one.current.0.igmpIfPol.attributes.querierTimeout == "180" + - query_one.current.0.igmpIfPol.attributes.robustFac == "5" + - query_one.current.0.igmpIfPol.attributes.ver == "v3" + - query_one.current.0.igmpIfPol.attributes.ifCtrl == "rep-ll" + - query_all is not changed + - query_all.current | length > 1 + +# REMOVE IGMP INTERFACE POLICY +- name: Delete an IGMP Interface Policy + cisco.aci.aci_igmp_interface_policy: + <<: *aci_igmp + state: absent + register: delete + +- name: Delete IGMP Interface Policy again + cisco.aci.aci_igmp_interface_policy: + <<: *aci_igmp + state: absent + register: delete_again + +- name: Verify deletion of IGMP Interface Policy + ansible.builtin.assert: + that: + - delete is changed + - delete_again is not changed + - delete.current == [] + +# CLEAN UP +- name: Remove the ansible_tenant + cisco.aci.aci_tenant: + <<: *aci_info + name: ansible_tenant + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_blacklist/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_blacklist/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_blacklist/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_blacklist/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_blacklist/tasks/main.yml new file mode 100644 index 000000000..d7b125267 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_blacklist/tasks/main.yml @@ -0,0 +1,464 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) + +# 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 + test_vars_leaf: &test_vars_leaf + pod_id: 1 + node_id: 1101 + interface: 1/33 + test_vars_spine: &test_vars_spine + pod_id: 1 + node_id: 1201 + interface: 1/33 + test_vars_fex: &test_vars_fex + pod_id: 1 + node_id: 1101 + interface: 1/33 + fex_id: 123 + +- 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: 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: Spine - Clean test environment with enabled interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_spine + state: absent + + - name: Fex - Clean test environment with enabled interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_fex + state: absent + + - name: Leaf - Clean test environment with enabled interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_leaf + state: absent + + - name: Leaf - Query outofsvc_interface_blacklist + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_leaf + state: query + register: query_leaf_int_enabled + + - name: Leaf - Verify that outofsvc_interface_blacklist is not present + assert: + that: + - query_leaf_int_enabled.current.0.fabricOOServicePol.children is not defined + + - name: Leaf - Disable interface in check mode + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_leaf + state: present + check_mode: true + register: disable_leaf_int_check + + - name: Leaf - Verify that outofsvc_interface_blacklist is not created after check mode + assert: + that: + - disable_leaf_int_check.current.0.fabricOOServicePol.children is not defined + + - name: Leaf - Disable interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_leaf + state: present + register: disable_leaf_int + + - name: Leaf - Verify that outofsvc_interface_blacklist is created + assert: + that: + - disable_leaf_int.current|length == 1 + - disable_leaf_int.current.0.fabricRsOosPath.attributes.tDn == "topology/pod-1/paths-1101/pathep-[eth1/33]" + - disable_leaf_int.current.0.fabricRsOosPath.attributes.lc == "blacklist" + - disable_leaf_int.current.0.fabricRsOosPath.attributes.annotation == 'orchestrator:ansible' + + - name: Leaf - Disable interface again + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_leaf + state: present + register: disable_leaf_int_again + + - name: Leaf - Verify that outofsvc_interface_blacklist remains created after disabling again + assert: + that: + - disable_leaf_int_again is not changed + - disable_leaf_int_again.current|length == 1 + - disable_leaf_int_again.current.0.fabricRsOosPath.attributes.tDn == "topology/pod-1/paths-1101/pathep-[eth1/33]" + - disable_leaf_int_again.current.0.fabricRsOosPath.attributes.lc == "blacklist" + + - name: Leaf - Query interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_leaf + state: query + register: query_leaf_int_disabled + + - name: Leaf - Verify that outofsvc_interface_blacklist remains created after query + assert: + that: + - query_leaf_int_disabled is not changed + - query_leaf_int_disabled.current|length == 1 + - query_leaf_int_disabled.current.0.fabricOOServicePol.children.0.fabricRsOosPath.attributes.tDn == "topology/pod-1/paths-1101/pathep-[eth1/33]" + - query_leaf_int_disabled.current.0.fabricOOServicePol.children.0.fabricRsOosPath.attributes.lc == "blacklist" + + - name: Leaf - Enable interface in check mode + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_leaf + state: absent + check_mode: true + register: enable_leaf_int_check + + - name: Leaf - Verify that outofsvc_interface_blacklist remains created after check mode + assert: + that: + - enable_leaf_int_check.current|length == 1 + - enable_leaf_int_check.current.0.fabricRsOosPath.attributes.tDn == "topology/pod-1/paths-1101/pathep-[eth1/33]" + - enable_leaf_int_check.current.0.fabricRsOosPath.attributes.lc == "blacklist" + + - name: Leaf - Enable interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_leaf + state: absent + register: enable_leaf_int + + - name: Leaf - Verify that outofsvc_interface_blacklist is deleted + assert: + that: + - enable_leaf_int.current.0.fabricOOServicePol.children is not defined + + - name: Leaf - Enable interface again + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_leaf + state: absent + register: enable_leaf_int_again + + - name: Leaf - Verify that outofsvc_interface_blacklist remains deleted after enabling again + assert: + that: + - enable_leaf_int_again is not changed + - enable_leaf_int_again.current.0.fabricOOServicePol.children is not defined + + - name: Spine - Clean test environment with enabled interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_spine + state: absent + + - name: Spine - Query outofsvc_interface_blacklist + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_spine + state: query + register: query_spine_int_enabled + + - name: Spine - Verify that outofsvc_interface_blacklist is not present + assert: + that: + - query_spine_int_enabled.current.0.fabricOOServicePol.children is not defined + + - name: Spine - Disable interface in check mode + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_spine + state: present + check_mode: true + register: disable_spine_int_check + + - name: Spine - Verify that outofsvc_interface_blacklist is not created after check mode + assert: + that: + - disable_spine_int_check.current.0.fabricOOServicePol.children is not defined + + - name: Spine - Disable interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_spine + state: present + register: disable_spine_int + + - name: Spine - Verify that outofsvc_interface_blacklist is created + assert: + that: + - disable_spine_int.current|length == 1 + - disable_spine_int.current.0.fabricRsOosPath.attributes.tDn == "topology/pod-1/paths-1201/pathep-[eth1/33]" + - disable_spine_int.current.0.fabricRsOosPath.attributes.lc == "blacklist" + + - name: Spine - Disable interface again + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_spine + state: present + register: disable_spine_int_again + + - name: Spine - Verify that outofsvc_interface_blacklist remains created after disabling again + assert: + that: + - disable_spine_int_again is not changed + - disable_spine_int_again.current|length == 1 + - disable_spine_int_again.current.0.fabricRsOosPath.attributes.tDn == "topology/pod-1/paths-1201/pathep-[eth1/33]" + - disable_spine_int_again.current.0.fabricRsOosPath.attributes.lc == "blacklist" + + - name: Spine - Query interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_spine + state: query + register: query_spine_int_disabled + + - name: Spine - Verify that outofsvc_interface_blacklist remains created after query + assert: + that: + - query_spine_int_disabled is not changed + - query_spine_int_disabled.current|length == 1 + - query_spine_int_disabled.current.0.fabricOOServicePol.children.0.fabricRsOosPath.attributes.tDn == "topology/pod-1/paths-1201/pathep-[eth1/33]" + - query_spine_int_disabled.current.0.fabricOOServicePol.children.0.fabricRsOosPath.attributes.lc == "blacklist" + + - name: Spine - Enable interface in check mode + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_spine + state: absent + check_mode: true + register: enable_spine_int_check + + - name: Spine - Verify that outofsvc_interface_blacklist remains created after check mode + assert: + that: + - enable_spine_int_check.current|length == 1 + - enable_spine_int_check.current.0.fabricRsOosPath.attributes.tDn == "topology/pod-1/paths-1201/pathep-[eth1/33]" + - enable_spine_int_check.current.0.fabricRsOosPath.attributes.lc == "blacklist" + + - name: Spine - Enable interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_spine + state: absent + register: enable_spine_int + + - name: Spine - Verify that outofsvc_interface_blacklist is deleted + assert: + that: + - enable_spine_int.current.0.fabricOOServicePol.children is not defined + + - name: Spine - Enable interface again + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_spine + state: absent + register: enable_spine_int_again + + - name: Spine - Verify that outofsvc_interface_blacklist remains deleted after enabling again + assert: + that: + - enable_spine_int_again is not changed + - enable_spine_int_again.current.0.fabricOOServicePol.children is not defined + + - name: Fex - Clean test environment with enabled interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_fex + state: absent + + - name: Fex - Query outofsvc_interface_blacklist + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_fex + state: query + register: query_fex_int_enabled + + - name: Fex - Verify that outofsvc_interface_blacklist is not present + assert: + that: + - query_fex_int_enabled.current.0.fabricOOServicePol.children is not defined + + - name: Fex - Disable interface in check mode + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_fex + state: present + check_mode: true + register: disable_fex_int_check + + - name: Fex - Verify that outofsvc_interface_blacklist is not created after check mode + assert: + that: + - disable_fex_int_check.current.0.fabricOOServicePol.children is not defined + + - name: Fex - Disable interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_fex + state: present + register: disable_fex_int + + - name: Fex - Verify that outofsvc_interface_blacklist is created + assert: + that: + - disable_fex_int.current|length == 1 + - disable_fex_int.current.0.fabricRsOosPath.attributes.tDn == "topology/pod-1/paths-1101/extpaths-123/pathep-[eth1/33]" + - disable_fex_int.current.0.fabricRsOosPath.attributes.lc == "blacklist" + + - name: Fex - Disable interface again + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_fex + state: present + register: disable_fex_int_again + + - name: Fex - Verify that outofsvc_interface_blacklist remains created after disabling again + assert: + that: + - disable_fex_int_again is not changed + - disable_fex_int_again.current|length == 1 + - disable_fex_int_again.current.0.fabricRsOosPath.attributes.tDn == "topology/pod-1/paths-1101/extpaths-123/pathep-[eth1/33]" + - disable_fex_int_again.current.0.fabricRsOosPath.attributes.lc == "blacklist" + + - name: Fex - Query interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_fex + state: query + register: query_fex_int_disabled + + - name: Fex - Verify that outofsvc_interface_blacklist remains created after query + assert: + that: + - query_fex_int_disabled is not changed + - query_fex_int_disabled.current|length == 1 + - query_fex_int_disabled.current.0.fabricOOServicePol.children.0.fabricRsOosPath.attributes.tDn == "topology/pod-1/paths-1101/extpaths-123/pathep-[eth1/33]" + - query_fex_int_disabled.current.0.fabricOOServicePol.children.0.fabricRsOosPath.attributes.lc == "blacklist" + + - name: Fex - Enable interface in check mode + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_fex + state: absent + check_mode: true + register: enable_fex_int_check + + - name: Fex - Verify that outofsvc_interface_blacklist remains created after check mode + assert: + that: + - enable_fex_int_check.current|length == 1 + - enable_fex_int_check.current.0.fabricRsOosPath.attributes.tDn == "topology/pod-1/paths-1101/extpaths-123/pathep-[eth1/33]" + - enable_fex_int_check.current.0.fabricRsOosPath.attributes.lc == "blacklist" + + - name: Fex - Enable interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_fex + state: absent + register: enable_fex_int + + - name: Fex - Verify that outofsvc_interface_blacklist is deleted + assert: + that: + - enable_fex_int.current.0.fabricOOServicePol.children is not defined + + - name: Fex - Enable interface again + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_fex + state: absent + register: enable_fex_int_again + + - name: Fex - Verify that outofsvc_interface_blacklist remains deleted after enabling again + assert: + that: + - enable_fex_int_again is not changed + - enable_fex_int_again.current.0.fabricOOServicePol.children is not defined + + - name: Leaf - Disable interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_leaf + state: present + + - name: Spine - Disable interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_spine + state: present + + - name: Fex - Disable interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_fex + state: present + + - name: All - Query interfaces + cisco.aci.aci_interface_blacklist: + <<: *aci_info + state: query + register: query_all_disabled + + - name: All - Verify that multiple outofsvc_interface_blacklist exist + assert: + that: + - query_all_disabled is not changed + - query_all_disabled.current | length == 3 + + - name: Leaf - Enable interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_leaf + state: absent + + - name: Spine - Enable interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_spine + state: absent + + - name: Fex - Enable interface + cisco.aci.aci_interface_blacklist: + <<: *aci_info + <<: *test_vars_fex + state: absent + + - name: All - Query interfaces + cisco.aci.aci_interface_blacklist: + <<: *aci_info + state: query + register: query_all_enabled + + - name: All - Verify that no outofsvc_interface_blacklist exist + assert: + that: + - query_all_enabled is not changed + - query_all_enabled.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_config/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_config/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_config/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_config/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_config/tasks/main.yml new file mode 100644 index 000000000..75253bd40 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_config/tasks/main.yml @@ -0,0 +1,680 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Sabari Jaganathan <sajagana@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: '{{ aci_output_level | default("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 + +- name: Execute tasks only for ACI v6+ and non-cloud sites + when: + - version.current.0.topSystem.attributes.version is version('6', '>=') + - query_cloud.current == [] # This condition will execute only non-cloud sites + block: + # Negative test cases + - name: Ensure Interface does not exists, invalid test without node id + cisco.aci.aci_interface_config: + <<: *aci_info + role: leaf + port_type: access + interface_type: switch_port + interface: "1/1/1" + state: absent + register: invalid_interface_absent + ignore_errors: true + + - name: Ensure Interface 501 does not exists, invalid test with invalid interface details + cisco.aci.aci_interface_config: + <<: *aci_info + role: leaf + port_type: access + interface_type: switch_port + node: 501 + interface: "a/b/c" + state: absent + register: invalid_interface_details + ignore_errors: true + + - name: Add Interface 501, invalid test with policy_group and breakout + cisco.aci.aci_interface_config: + <<: *aci_info + role: leaf + port_type: access + interface_type: switch_port + policy_group: ans_test_switch_port + node: 501 + breakout: "100g-4x" + interface: "1/1/1" + state: present + register: invalid_policy_group_with_breakout + ignore_errors: true + + - name: Assertions check for the invalid tasks + assert: + that: + - invalid_interface_absent.msg is match("state is absent but all of the following are missing{{':'}} node") + - invalid_interface_details is not changed + - invalid_interface_details.msg is match("Interface configuration failed due to") + - invalid_policy_group_with_breakout is not changed + - invalid_policy_group_with_breakout.msg == "parameters are mutually exclusive{{':'}} policy_group|breakout" + + - name: Invalid Node ID check + cisco.aci.aci_interface_config: + <<: *aci_info + node: 5000 + interface: "1/1/1" + state: present + register: invalid_node + ignore_errors: true + + - name: Invalid Interface ID check + cisco.aci.aci_interface_config: + <<: *aci_info + node: 101 + interface: "1" + state: present + register: invalid_interface + ignore_errors: true + + - name: Invalid Card ID check + cisco.aci.aci_interface_config: + <<: *aci_info + node: 101 + interface: "1000/1/1" + state: present + register: invalid_card + ignore_errors: true + + - name: Invalid Port ID check + cisco.aci.aci_interface_config: + <<: *aci_info + node: 101 + interface: "1/500/1" + state: present + register: invalid_port + ignore_errors: true + + - name: Invalid Sub Port ID check + cisco.aci.aci_interface_config: + <<: *aci_info + node: 101 + interface: "1/1/100" + state: present + register: invalid_sub_port + ignore_errors: true + + - name: Assertions check for invalid interface configuration tasks + assert: + that: + - invalid_node is not changed + - invalid_node.msg is match("^Node ID{{':'}} .+? is invalid; it must be in the range of 101 to 4000.") + - invalid_interface is not changed + - invalid_interface.msg is match("^Interface{{':'}} .+? is invalid; The format must be either card\/port\/sub_port\(1\/1\/1\) or card\/port\(1\/1\)") + - invalid_card is not changed + - invalid_card.msg is match("^Card ID{{':'}} .+? is invalid; it must be in the range of 1 to 64.") + - invalid_port is not changed + - invalid_port.msg is match("^Port ID{{':'}} .+? is invalid; it must be in the range of 1 to 128.") + - 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 + cisco.aci.aci_interface_config: &interface_501_absent + <<: *aci_info + role: leaf + port_type: access + interface_type: switch_port + policy_group: ans_test_switch_port + node: 501 + interface: "1/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 + 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 + cisco.aci.aci_interface_config: &nm_interface_501_present + <<: *interface_501_absent + state: present + register: nm_interface_501_present + + - name: Assertions check for an interface 501 + assert: + that: + - interface_501_absent.current == [] + - cm_interface_501_present is changed + - cm_interface_501_present.current == [] + - nm_interface_501_present is changed + - 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.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" + + - name: Ensure Interface 502 with leaf access with policy_group - pc_or_vpc absent + cisco.aci.aci_interface_config: &interface_502_absent + <<: *aci_info + role: leaf + port_type: access + interface_type: pc_or_vpc + policy_group: ans_test_pc_or_vpc + node: 502 + interface: "2/2/2" + description: "Interface - 502 added by Ansible" + state: absent + register: interface_502_absent + + - name: Ensure Interface 502 with leaf access with policy_group - pc_or_vpc present - check mode + cisco.aci.aci_interface_config: &cm_interface_502_present + <<: *interface_502_absent + state: present + check_mode: true + register: cm_interface_502_present + + - name: Ensure Interface 502 with leaf access with policy_group - pc_or_vpc present - normal mode + cisco.aci.aci_interface_config: &nm_interface_502_present + <<: *interface_502_absent + state: present + register: nm_interface_502_present + + - name: Assertions check for an interface 502 + assert: + that: + - interface_502_absent.current == [] + - cm_interface_502_present is changed + - cm_interface_502_present.current == [] + - nm_interface_502_present is changed + - nm_interface_502_present.current != [] + - nm_interface_502_present.current.0.infraPortConfig.attributes.assocGrp == "uni/infra/funcprof/accbundle-ans_test_pc_or_vpc" + - nm_interface_502_present.current.0.infraPortConfig.attributes.brkoutMap == "none" + - nm_interface_502_present.current.0.infraPortConfig.attributes.card == "2" + - nm_interface_502_present.current.0.infraPortConfig.attributes.description == "Interface - 502 added by Ansible" + - nm_interface_502_present.current.0.infraPortConfig.attributes.dn == "uni/infra/portconfnode-502-card-2-port-2-sub-2" + - nm_interface_502_present.current.0.infraPortConfig.attributes.node == "502" + - nm_interface_502_present.current.0.infraPortConfig.attributes.port == "2" + - nm_interface_502_present.current.0.infraPortConfig.attributes.role == "leaf" + - nm_interface_502_present.current.0.infraPortConfig.attributes.shutdown == "no" + + - name: Ensure Interface 505 with leaf access with policy_group - fc absent + cisco.aci.aci_interface_config: &interface_505_absent + <<: *aci_info + role: leaf + port_type: access + interface_type: fc + policy_group: ans_test_fc + node: 505 + interface: "5/5/5" + description: "Interface - 505 added by Ansible" + state: absent + register: interface_505_absent + + - name: Ensure Interface 505 with leaf access with policy_group - fc present - check mode + cisco.aci.aci_interface_config: &cm_interface_505_present + <<: *interface_505_absent + state: present + check_mode: true + register: cm_interface_505_present + + - name: Ensure Interface 505 with leaf access with policy_group - fc present - normal mode + cisco.aci.aci_interface_config: &nm_interface_505_present + <<: *interface_505_absent + state: present + register: nm_interface_505_present + + - name: Assertions check for an interface 505 + assert: + that: + - interface_505_absent.current == [] + - cm_interface_505_present is changed + - cm_interface_505_present.current == [] + - nm_interface_505_present is changed + - nm_interface_505_present.current != [] + - nm_interface_505_present.current.0.infraPortConfig.attributes.assocGrp == "uni/infra/funcprof/fcaccportgrp-ans_test_fc" + - nm_interface_505_present.current.0.infraPortConfig.attributes.brkoutMap == "none" + - nm_interface_505_present.current.0.infraPortConfig.attributes.card == "5" + - nm_interface_505_present.current.0.infraPortConfig.attributes.description == "Interface - 505 added by Ansible" + - nm_interface_505_present.current.0.infraPortConfig.attributes.dn == "uni/infra/portconfnode-505-card-5-port-5-sub-5" + - nm_interface_505_present.current.0.infraPortConfig.attributes.node == "505" + - nm_interface_505_present.current.0.infraPortConfig.attributes.port == "5" + - nm_interface_505_present.current.0.infraPortConfig.attributes.role == "leaf" + - nm_interface_505_present.current.0.infraPortConfig.attributes.shutdown == "no" + + - name: Ensure Interface 506 with leaf access with policy_group - fc_port_channel absent + cisco.aci.aci_interface_config: &interface_506_absent + <<: *aci_info + role: leaf + port_type: access + interface_type: fc_port_channel + policy_group: ans_test_fc_port_channel + node: 506 + interface: "6/6/6" + description: "Interface - 506 added by Ansible" + state: absent + register: interface_506_absent + + - name: Ensure Interface 506 with leaf access with policy_group - fc_port_channel present - check mode + cisco.aci.aci_interface_config: &cm_interface_506_present + <<: *interface_506_absent + state: present + check_mode: true + register: cm_interface_506_present + + - name: Ensure Interface 506 with leaf access with policy_group - fc_port_channel present - normal mode + cisco.aci.aci_interface_config: &nm_interface_506_present + <<: *interface_506_absent + state: present + register: nm_interface_506_present + + - name: Assertions check for an interface 506 + assert: + that: + - interface_506_absent.current == [] + - cm_interface_506_present is changed + - cm_interface_506_present.current == [] + - nm_interface_506_present is changed + - nm_interface_506_present.current != [] + - nm_interface_506_present.current.0.infraPortConfig.attributes.assocGrp == "uni/infra/funcprof/fcaccbundle-ans_test_fc_port_channel" + - nm_interface_506_present.current.0.infraPortConfig.attributes.brkoutMap == "none" + - nm_interface_506_present.current.0.infraPortConfig.attributes.card == "6" + - nm_interface_506_present.current.0.infraPortConfig.attributes.description == "Interface - 506 added by Ansible" + - nm_interface_506_present.current.0.infraPortConfig.attributes.dn == "uni/infra/portconfnode-506-card-6-port-6-sub-6" + - nm_interface_506_present.current.0.infraPortConfig.attributes.node == "506" + - nm_interface_506_present.current.0.infraPortConfig.attributes.port == "6" + - nm_interface_506_present.current.0.infraPortConfig.attributes.role == "leaf" + - nm_interface_506_present.current.0.infraPortConfig.attributes.shutdown == "no" + + - name: Ensure Interface 507 with leaf fabric with policy_group - leaf_fabric absent + cisco.aci.aci_interface_config: &interface_507_absent + <<: *aci_info + role: leaf + port_type: fabric + interface_type: leaf_fabric + policy_group: ans_test_leaf_fabric + node: 507 + interface: "7/7/7" + description: "Interface - 507 added by Ansible" + state: absent + register: interface_507_absent + + - name: Ensure Interface 507 with leaf fabric with policy_group - leaf_fabric present - check mode + cisco.aci.aci_interface_config: &cm_interface_507_present + <<: *interface_507_absent + state: present + check_mode: true + register: cm_interface_507_present + + - name: Ensure Interface 507 with leaf fabric with policy_group - leaf_fabric present - normal mode + cisco.aci.aci_interface_config: &nm_interface_507_present + <<: *interface_507_absent + state: present + register: nm_interface_507_present + + - name: Assertions check for an interface 507 + assert: + that: + - interface_507_absent.current == [] + - cm_interface_507_present is changed + - cm_interface_507_present.current == [] + - nm_interface_507_present is changed + - nm_interface_507_present.current != [] + - nm_interface_507_present.current.0.fabricPortConfig.attributes.assocGrp == "uni/fabric/funcprof/leportgrp-ans_test_leaf_fabric" + - nm_interface_507_present.current.0.fabricPortConfig.attributes.description == "Interface - 507 added by Ansible" + - nm_interface_507_present.current.0.fabricPortConfig.attributes.dn == "uni/fabric/portconfnode-507-card-7-port-7-sub-7" + - nm_interface_507_present.current.0.fabricPortConfig.attributes.role == "leaf" + - nm_interface_507_present.current.0.fabricPortConfig.attributes.shutdown == "no" + + - name: Ensure Interface 508 with spine access with policy_group - spine_access absent + cisco.aci.aci_interface_config: &interface_508_absent + <<: *aci_info + role: spine + port_type: access + interface_type: spine_access + policy_group: ans_test_spine_access + node: 508 + interface: "8/8/8" + description: "Interface - 508 added by Ansible" + state: absent + register: interface_508_absent + + - name: Ensure Interface 508 with spine access with policy_group - spine_access present - check mode + cisco.aci.aci_interface_config: &cm_interface_508_present + <<: *interface_508_absent + state: present + check_mode: true + register: cm_interface_508_present + + - name: Ensure Interface 508 with spine access with policy_group - spine_access present - normal mode + cisco.aci.aci_interface_config: &nm_interface_508_present + <<: *interface_508_absent + state: present + register: nm_interface_508_present + + - name: Assertions check for an interface 508 + assert: + that: + - interface_508_absent.current == [] + - cm_interface_508_present is changed + - cm_interface_508_present.current == [] + - nm_interface_508_present is changed + - nm_interface_508_present.current != [] + - nm_interface_508_present.current.0.infraPortConfig.attributes.assocGrp == "uni/infra/funcprof/spaccportgrp-ans_test_spine_access" + - nm_interface_508_present.current.0.infraPortConfig.attributes.description == "Interface - 508 added by Ansible" + - nm_interface_508_present.current.0.infraPortConfig.attributes.dn == "uni/infra/portconfnode-508-card-8-port-8-sub-8" + - nm_interface_508_present.current.0.infraPortConfig.attributes.role == "spine" + - nm_interface_508_present.current.0.infraPortConfig.attributes.shutdown == "no" + + - name: Ensure Interface 509 with spine fabric with policy_group - spine_fabric absent + cisco.aci.aci_interface_config: &interface_509_absent + <<: *aci_info + role: spine + port_type: fabric + interface_type: spine_fabric + policy_group: ans_test_spine_fabric + node: 509 + interface: "9/9/9" + description: "Interface - 509 added by Ansible" + state: absent + register: interface_509_absent + + - name: Ensure Interface 509 with spine fabric with policy_group - spine_fabric present - check mode + cisco.aci.aci_interface_config: &cm_interface_509_present + <<: *interface_509_absent + state: present + check_mode: true + register: cm_interface_509_present + + - name: Ensure Interface 509 with spine fabric with policy_group - spine_fabric present - normal mode + cisco.aci.aci_interface_config: &nm_interface_509_present + <<: *interface_509_absent + state: present + register: nm_interface_509_present + + - name: Ensure Interface 509 with spine fabric with policy_group - spine_fabric present - normal mode with idempotency check + cisco.aci.aci_interface_config: + <<: *interface_509_absent + state: present + register: idm_interface_509_present + + - name: Assertions check for an interface 509 + assert: + that: + - interface_509_absent.current == [] + - cm_interface_509_present is changed + - cm_interface_509_present.current == [] + - nm_interface_509_present is changed + - nm_interface_509_present.current != [] + - nm_interface_509_present.current.0.fabricPortConfig.attributes.assocGrp == "uni/fabric/funcprof/spportgrp-ans_test_spine_fabric" + - nm_interface_509_present.current.0.fabricPortConfig.attributes.description == "Interface - 509 added by Ansible" + - nm_interface_509_present.current.0.fabricPortConfig.attributes.dn == "uni/fabric/portconfnode-509-card-9-port-9-sub-9" + - nm_interface_509_present.current.0.fabricPortConfig.attributes.role == "spine" + - nm_interface_509_present.current.0.fabricPortConfig.attributes.shutdown == "no" + - idm_interface_509_present is not changed + - idm_interface_509_present.current != [] + - idm_interface_509_present.current.0.fabricPortConfig.attributes.assocGrp == "uni/fabric/funcprof/spportgrp-ans_test_spine_fabric" + - idm_interface_509_present.current.0.fabricPortConfig.attributes.description == "Interface - 509 added by Ansible" + - idm_interface_509_present.current.0.fabricPortConfig.attributes.dn == "uni/fabric/portconfnode-509-card-9-port-9-sub-9" + - idm_interface_509_present.current.0.fabricPortConfig.attributes.role == "spine" + - idm_interface_509_present.current.0.fabricPortConfig.attributes.shutdown == "no" + + # Breakout part begins + - name: Convert the interface 501 to breakout(100g-4x) with policy group - invalid test + cisco.aci.aci_interface_config: + <<: *aci_info + role: leaf + port_type: access + interface_type: switch_port + policy_group: ans_test_switch_port + breakout: "100g-4x" + node: 501 + interface: "1/1/1" + description: "Interface - 501 added by Ansible" + state: present + register: invalid_breakout_501_present + ignore_errors: true + + - name: Convert the interface 501 to breakout(100g-4x) - check mode + cisco.aci.aci_interface_config: &valid_breakout_501_present + <<: *aci_info + role: leaf + port_type: access + interface_type: switch_port + breakout: "100g-4x" + node: 501 + interface: "1/1/1" + description: "Interface - 501 added by Ansible" + admin_state: "down" + state: present + check_mode: true + register: cm_valid_breakout_501_present + + - name: Convert the interface 501 to breakout(100g-4x) - normal mode + cisco.aci.aci_interface_config: + <<: *valid_breakout_501_present + register: nm_valid_breakout_501_present + + - name: Convert the interface 501 to breakout(100g-4x) - normal mode with idempotency check + cisco.aci.aci_interface_config: + <<: *valid_breakout_501_present + register: idm_breakout_501_present + + - name: Assertions check for convert the interface 501 to breakout(100g-4x) + assert: + that: + - invalid_breakout_501_present is not changed + - invalid_breakout_501_present.msg == "parameters are mutually exclusive{{':'}} policy_group|breakout" + - cm_valid_breakout_501_present is changed + - cm_valid_breakout_501_present.current != [] + - cm_valid_breakout_501_present.current.0.infraPortConfig.attributes.brkoutMap == "none" + - nm_valid_breakout_501_present is changed + - 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.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.role == "leaf" + - idm_breakout_501_present.current.0.infraPortConfig.attributes.shutdown == "yes" + # Breakup part ends + + - name: Query all access interfaces + cisco.aci.aci_interface_config: + <<: *aci_info + port_type: access + state: query + register: query_all_access_interfaces + + - name: Assertions check for query all access interfaces + assert: + that: + - query_all_access_interfaces is not changed + - query_all_access_interfaces.current|length >= 6 + + - name: Query all fabric interfaces + cisco.aci.aci_interface_config: + <<: *aci_info + port_type: fabric + state: query + register: query_all_fabric_interfaces + + - name: Assertions check for query all fabric interfaces + assert: + that: + - query_all_fabric_interfaces is not changed + - query_all_fabric_interfaces.current|length >= 2 + + - name: Query a access interface with node id 502 + cisco.aci.aci_interface_config: + <<: *aci_info + port_type: access + node: 502 + state: query + register: query_access_interface_502 + + - name: Assertions check for query a access interface with node id 502 + assert: + that: + - query_access_interface_502 is not changed + - query_access_interface_502.current|length == 1 + - query_access_interface_502.current.0.infraPortConfig.attributes.brkoutMap == "none" + - query_access_interface_502.current.0.infraPortConfig.attributes.description == "Interface - 502 added by Ansible" + - query_access_interface_502.current.0.infraPortConfig.attributes.dn == "uni/infra/portconfnode-502-card-2-port-2-sub-2" + - query_access_interface_502.current.0.infraPortConfig.attributes.role == "leaf" + - query_access_interface_502.current.0.infraPortConfig.attributes.shutdown == "no" + + - name: Query a fabric interface with node id 509 + cisco.aci.aci_interface_config: + <<: *aci_info + port_type: fabric + node: 509 + state: query + register: query_access_fabric_509 + + - name: Assertions check for query a fabric interface with node id 509 + assert: + that: + - query_access_fabric_509 is not changed + - query_access_fabric_509.current|length == 1 + - query_access_fabric_509.current.0.fabricPortConfig.attributes.assocGrp == "uni/fabric/funcprof/spportgrp-ans_test_spine_fabric" + - query_access_fabric_509.current.0.fabricPortConfig.attributes.description == "Interface - 509 added by Ansible" + - query_access_fabric_509.current.0.fabricPortConfig.attributes.dn == "uni/fabric/portconfnode-509-card-9-port-9-sub-9" + - query_access_fabric_509.current.0.fabricPortConfig.attributes.role == "spine" + - query_access_fabric_509.current.0.fabricPortConfig.attributes.shutdown == "no" + + - name: Ensure Breakout Interface 501 absent + cisco.aci.aci_interface_config: + <<: *valid_breakout_501_present + state: absent + register: rm_interface_501_present + + - name: Ensure Interface 502 with leaf access with policy_group - pc_or_vpc absent + cisco.aci.aci_interface_config: + <<: *interface_502_absent + state: absent + register: rm_interface_502_present + + - name: Ensure Interface 505 with leaf access with policy_group - fc absent + cisco.aci.aci_interface_config: + <<: *interface_505_absent + state: absent + register: rm_interface_505_present + + - name: Ensure Interface 506 with leaf access with policy_group - fc_port_channel absent + cisco.aci.aci_interface_config: + <<: *interface_506_absent + state: absent + register: rm_interface_506_present + + - name: Ensure Interface 507 with leaf fabric with policy_group - leaf_fabric absent + cisco.aci.aci_interface_config: + <<: *interface_507_absent + state: absent + register: rm_interface_507_present + + - name: Ensure Interface 508 with spine access with policy_group - spine_access absent + cisco.aci.aci_interface_config: + <<: *interface_508_absent + state: absent + register: rm_interface_508_present + + - name: Assertions check for remove Interfaces 501 to 508 + assert: + that: + - rm_interface_501_present is changed + - rm_interface_501_present.current == [] + - rm_interface_502_present is changed + - rm_interface_502_present.current == [] + - rm_interface_505_present is changed + - rm_interface_505_present.current == [] + - rm_interface_506_present is changed + - rm_interface_506_present.current == [] + - rm_interface_507_present is changed + - rm_interface_507_present.current == [] + - rm_interface_508_present is changed + - rm_interface_508_present.current == [] + + - name: Ensure Interface 509 with spine fabric with policy_group - spine_fabric absent - check mode + cisco.aci.aci_interface_config: + <<: *interface_509_absent + state: absent + check_mode: true + register: cm_rm_interface_509_present + + - name: Ensure Interface 509 with spine fabric with policy_group - spine_fabric absent - normal mode + cisco.aci.aci_interface_config: + <<: *interface_509_absent + state: absent + register: nm_rm_interface_509_present + + - name: Assertions check for remove Interface 509 + assert: + that: + - cm_rm_interface_509_present is changed + - cm_rm_interface_509_present.current != [] + - nm_rm_interface_509_present is changed + - nm_rm_interface_509_present.current == [] + + - name: Ensure Interface 509 with spine fabric with policy_group - spine_fabric absent - normal mode with idempotency check + cisco.aci.aci_interface_config: + <<: *interface_509_absent + state: absent + register: idm_rm_interface_509_present + + - name: Assertions check for remove Interface 509 with idempotency check + assert: + that: + - idm_rm_interface_509_present is not changed + - idm_rm_interface_509_present.current == [] + + - name: Query an interface 509 after removed from the APIC + cisco.aci.aci_interface_config: + <<: *aci_info + node: 509 + port_type: "fabric" + state: query + register: query_interface_509 + + - name: Assertions check for query an interface 509 after removed from the APIC + assert: + that: + - query_interface_509 is not changed + - query_interface_509.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_description/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_description/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_description/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_description/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_description/tasks/main.yml new file mode 100644 index 000000000..ec4f0250d --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_description/tasks/main.yml @@ -0,0 +1,289 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) + +# 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: Node types + set_fact: + test_vars_leaf: &test_vars_leaf + pod_id: 1 + node_id: 1101 + node_type: leaf + interface: 1/33 + description: testing + test_vars_spine: &test_vars_spine + pod_id: 1 + node_id: 1201 + node_type: spine + interface: 1/33 + description: testing + test_vars_fex: &test_vars_fex + pod_id: 1 + node_id: 1101 + interface: 1/33 + fex_id: 123 + description: testing + +- 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: Leaf - Clean test environment with no description interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_leaf + state: absent + + - name: Spine - Clean test environment with no description interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_spine + state: absent + + - name: Fex - Clean test environment with no description interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_fex + state: absent + + - name: Leaf - Query interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_leaf + state: query + register: query_leaf_description + + - name: Leaf - Verify that no infraHPathS is present + assert: + that: + - query_leaf_description.current.0.infraInfra.children.0.infraHPathS.children is not defined + + - name: Leaf - Set description on interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_leaf + state: present + register: set_leaf_description + + - name: Leaf - Verify that description is set on interface + assert: + that: + - set_leaf_description.current|length == 1 + - set_leaf_description.current.0.infraHPathS.children.0.infraRsHPathAtt.attributes.tDn == "topology/pod-1/paths-1101/pathep-[eth1/33]" + - set_leaf_description.current.0.infraHPathS.attributes.descr == "testing" + - set_leaf_description.current.0.infraHPathS.attributes.annotation == 'orchestrator:ansible' + + - name: Query Leaf interface - 1101_eth1_33 + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_leaf + state: query + register: query_leaf_interface_1101_eth1_33 + + - name: Assertion check for query Leaf interface - 1101_eth1_33 + assert: + that: + - query_leaf_interface_1101_eth1_33.current.0.infraHPathS.children | length == 1 + - query_leaf_interface_1101_eth1_33.current.0.infraHPathS.children.0.infraRsHPathAtt.attributes.rn == "rsHPathAtt-[topology/pod-1/paths-1101/pathep-[eth1/33]]" + - query_leaf_interface_1101_eth1_33.current.0.infraHPathS.attributes.dn == "uni/infra/hpaths-1101_eth1_33" + - query_leaf_interface_1101_eth1_33.current.0.infraHPathS.attributes.descr == "testing" + - query_leaf_interface_1101_eth1_33.current.0.infraHPathS.attributes.name == "1101_eth1_33" + + - name: Query all leaf interfaces + cisco.aci.aci_interface_description: + <<: *aci_info + node_type: leaf + state: query + register: query_all_leaf_interfaces + + - name: Verify query all leaf interfaces + assert: + that: + - query_all_leaf_interfaces.current | length > 1 + - query_all_leaf_interfaces.current.1.infraHPathS.children.0.infraRsHPathAtt.attributes.rn == "rsHPathAtt-[topology/pod-1/paths-1101/pathep-[eth1/33]]" + - query_all_leaf_interfaces.current.1.infraHPathS.attributes.dn == "uni/infra/hpaths-1101_eth1_33" + - query_all_leaf_interfaces.current.1.infraHPathS.attributes.descr == "testing" + - query_all_leaf_interfaces.current.1.infraHPathS.attributes.name == "1101_eth1_33" + + - name: Leaf - Clean test environment with no description interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_leaf + state: absent + + - name: Leaf - Query interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_leaf + state: query + register: query_leaf_description_again + + - name: Leaf - Verify that no infraHPathS is present + assert: + that: + - query_leaf_description_again.current.0.infraInfra.children.0.infraHPathS.children is not defined + + - name: Spine - Clean test environment with no description interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_spine + state: absent + + - name: Spine - Query interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_spine + state: query + register: query_spine_description + + - name: Spine - Verify that no infraSHPathS is present + assert: + that: + - query_spine_description.current.0.infraInfra.children.0.infraSHPathS.children is not defined + + - name: Spine - Set description on interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_spine + state: present + register: set_spine_description + + - name: Spine - Verify that description is set on interface + assert: + that: + - set_spine_description.current|length == 1 + - set_spine_description.current.0.infraSHPathS.children.0.infraRsSHPathAtt.attributes.tDn == "topology/pod-1/paths-1201/pathep-[eth1/33]" + - set_spine_description.current.0.infraSHPathS.attributes.descr == "testing" + + - name: Query Spine interface - 1201_eth1_33 + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_spine + state: query + register: query_spine_interface_1201_eth1_33 + + - name: Assertion check for query Spine interface - 1201_eth1_33 + assert: + that: + - query_spine_interface_1201_eth1_33.current.0.infraSHPathS.children | length == 1 + - query_spine_interface_1201_eth1_33.current.0.infraSHPathS.children.0.infraRsSHPathAtt.attributes.rn == "rsSHPathAtt-[topology/pod-1/paths-1201/pathep-[eth1/33]]" + - query_spine_interface_1201_eth1_33.current.0.infraSHPathS.attributes.dn == "uni/infra/shpaths-1201_eth1_33" + - query_spine_interface_1201_eth1_33.current.0.infraSHPathS.attributes.descr == "testing" + - query_spine_interface_1201_eth1_33.current.0.infraSHPathS.attributes.name == "1201_eth1_33" + + - name: Query all spine interfaces + cisco.aci.aci_interface_description: + <<: *aci_info + node_type: spine + state: query + register: query_all_spine_interfaces + + - name: Verify query all spine interfaces + assert: + that: + - query_all_spine_interfaces.current | length >= 1 + - query_all_spine_interfaces.current.1.infraSHPathS.children.0.infraRsSHPathAtt.attributes.rn == "rsSHPathAtt-[topology/pod-1/paths-1201/pathep-[eth1/33]]" + - query_all_spine_interfaces.current.1.infraSHPathS.attributes.dn == "uni/infra/shpaths-1201_eth1_33" + - query_all_spine_interfaces.current.1.infraSHPathS.attributes.descr == "testing" + - query_all_spine_interfaces.current.1.infraSHPathS.attributes.name == "1201_eth1_33" + + - name: Spine - Clean test environment with no description interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_spine + state: absent + + - name: Spine - Query interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_spine + state: query + register: query_spine_description_again + + - name: Spine - Verify that no infraSHPathS is present + assert: + that: + - query_spine_description_again.current.0.infraInfra.children.0.infraSHPathS.children is not defined + + - name: Fex - Clean test environment with no description interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_fex + state: absent + + - name: Fex - Query interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_fex + state: query + register: query_fex_description + + - name: Fex - Verify that no infraHPathS is present + assert: + that: + - query_fex_description.current.0.infraInfra.children.0.infraHPathS.children is not defined + + - name: Fex - Set description on interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_fex + state: present + register: set_fex_description + + - name: Fex - Verify that description is set on interface + assert: + that: + - set_fex_description.current|length == 1 + - set_fex_description.current.0.infraHPathS.children.0.infraRsHPathAtt.attributes.tDn == "topology/pod-1/paths-1101/extpaths-123/pathep-[eth1/33]" + - set_fex_description.current.0.infraHPathS.attributes.descr == "testing" + + - name: Query Fex interface - 1101_eth123_1_33 + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_fex + state: query + register: query_fex_interface_1201_eth1_33 + + - name: Assertion check for query Fex interface - 1101_eth123_1_33 + assert: + that: + - query_fex_interface_1201_eth1_33.current.0.infraHPathS.children | length == 1 + - query_fex_interface_1201_eth1_33.current.0.infraHPathS.children.0.infraRsHPathAtt.attributes.rn == "rsHPathAtt-[topology/pod-1/paths-1101/extpaths-123/pathep-[eth1/33]]" + - query_fex_interface_1201_eth1_33.current.0.infraHPathS.attributes.descr == "testing" + - query_fex_interface_1201_eth1_33.current.0.infraHPathS.attributes.name == "1101_eth123_1_33" + + - name: Fex - Clean test environment with no description interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_fex + state: absent + + - name: Fex - Query interface + cisco.aci.aci_interface_description: + <<: *aci_info + <<: *test_vars_fex + state: query + register: query_fex_description_again + + - name: Fex - Verify that no infraHPathS is present + assert: + that: + - query_fex_description_again.current.0.infraInfra.children.0.infraHPathS.children is not defined diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_cdp/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_cdp/aliases new file mode 100644 index 000000000..cf765b70b --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_cdp/aliases @@ -0,0 +1 @@ +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_cdp/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_cdp/tasks/main.yml new file mode 100644 index 000000000..48ac1d806 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_cdp/tasks/main.yml @@ -0,0 +1,111 @@ +# Test code for the ACI modules +# Copyright: (c) 2019, Tim Knipper (tknipper11) <tim.knipper@gmail.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: 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: Remove CDP Test Policy + cisco.aci.aci_interface_policy_cdp: + name: Ansible_CDP_Test_Policy + 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(false) }}' + output_level: debug + state: absent + register: cdp_delete + + - name: Create CDP Test Policy + cisco.aci.aci_interface_policy_cdp: + name: Ansible_CDP_Test_Policy + 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(false) }}' + # output_level: debug + state: present + register: cdp_create + - debug: + var: cdp_create + + - assert: + that: + - cdp_create is changed + - cdp_create.current.0.cdpIfPol.attributes.annotation == 'orchestrator:ansible' + + + - name: test for idempotency + cisco.aci.aci_interface_policy_cdp: + name: Ansible_CDP_Test_Policy + 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(false) }}' + # output_level: debug + state: present + register: cdp_idem + + - name: Assert that idempotency is not changed + assert: + that: + - cdp_idem is not changed + + + + - name: Create CDP Disable Test Policy + cisco.aci.aci_interface_policy_cdp: + name: Ansible_CDP_Test_Policy + 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(false) }}' + # output_level: debug + state: present + admin_state: false + register: cdp_disable + - debug: + var: cdp_disable + + - name: Assert that CDP is Disabled + assert: + that: + - cdp_disable.current.0.cdpIfPol.attributes.adminSt == 'disabled' + + + - name: Query CDP Policy + cisco.aci.aci_interface_policy_cdp: + 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(false) }}' + # output_level: debug + state: query + register: cdp_query + - debug: + var: cdp_query + + - name: CDP Query Assertion + assert: + that: + - cdp_query is not changed
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_breakout_port_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_breakout_port_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_breakout_port_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_breakout_port_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_breakout_port_group/tasks/main.yml new file mode 100644 index 000000000..b84f64b9a --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_breakout_port_group/tasks/main.yml @@ -0,0 +1,169 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Cindy Zhao (@cizhao) <cizhao@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 + +# CLEAN ENVIRONMENT +- 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 execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Making sure leaf breakout port group doesn't exist at beginning of test + cisco.aci.aci_interface_policy_leaf_breakout_port_group: + <<: *aci_info + breakout_port_group: '{{ item }}' + state: absent + loop: + - 'ansible_breakout_port' + - 'ansible_breakout_port_2' + + - name: Create leaf breakout port group (check_mode) + cisco.aci.aci_interface_policy_leaf_breakout_port_group: + <<: *aci_info + breakout_port_group: ansible_breakout_port + description: description for ansible_breakout_port + breakout_map: 10g-4x + state: present + check_mode: true + register: cm_create_brkout_port + + - name: Create leaf breakout port group (normal_mode) + cisco.aci.aci_interface_policy_leaf_breakout_port_group: + <<: *aci_info + breakout_port_group: ansible_breakout_port + description: description for ansible_breakout_port + breakout_map: 10g-4x + state: present + register: nm_create_brkout_port + + - name: Verify cm_create_brkout_port and nm_create_brkout_port + assert: + that: + - cm_create_brkout_port is changed + - cm_create_brkout_port.previous == [] + - cm_create_brkout_port.proposed.infraBrkoutPortGrp.attributes.name == "ansible_breakout_port" + - cm_create_brkout_port.proposed.infraBrkoutPortGrp.attributes.dn == "uni/infra/funcprof/brkoutportgrp-ansible_breakout_port" + - cm_create_brkout_port.proposed.infraBrkoutPortGrp.attributes.descr == "description for ansible_breakout_port" + - cm_create_brkout_port.proposed.infraBrkoutPortGrp.attributes.brkoutMap == "10g-4x" + - nm_create_brkout_port is changed + - nm_create_brkout_port.previous == [] + - nm_create_brkout_port.current.0.infraBrkoutPortGrp.attributes.name == "ansible_breakout_port" + - nm_create_brkout_port.current.0.infraBrkoutPortGrp.attributes.dn == "uni/infra/funcprof/brkoutportgrp-ansible_breakout_port" + - nm_create_brkout_port.current.0.infraBrkoutPortGrp.attributes.descr == "description for ansible_breakout_port" + - nm_create_brkout_port.current.0.infraBrkoutPortGrp.attributes.brkoutMap == "10g-4x" + - nm_create_brkout_port.current.0.infraBrkoutPortGrp.attributes.annotation == 'orchestrator:ansible' + + - name: Create leaf breakout port group again (normal_mode) + cisco.aci.aci_interface_policy_leaf_breakout_port_group: + <<: *aci_info + breakout_port_group: ansible_breakout_port + description: description for ansible_breakout_port + breakout_map: 10g-4x + state: present + register: nm_create_brkout_port_again + + - name: Verify nm_create_brkout_port_again + assert: + that: + - nm_create_brkout_port_again is not changed + + - name: Create another leaf breakout port group + cisco.aci.aci_interface_policy_leaf_breakout_port_group: + <<: *aci_info + breakout_port_group: ansible_breakout_port_2 + state: present + register: nm_create_another_brkout_port + + - name: Verify nm_create_another_brkout_port + assert: + that: + - nm_create_another_brkout_port is changed + - nm_create_another_brkout_port.previous == [] + - nm_create_another_brkout_port.proposed.infraBrkoutPortGrp.attributes.name == "ansible_breakout_port_2" + - nm_create_another_brkout_port.proposed.infraBrkoutPortGrp.attributes.dn == "uni/infra/funcprof/brkoutportgrp-ansible_breakout_port_2" + - nm_create_another_brkout_port.current.0.infraBrkoutPortGrp.attributes.dn == "uni/infra/funcprof/brkoutportgrp-ansible_breakout_port_2" + - nm_create_another_brkout_port.current.0.infraBrkoutPortGrp.attributes.brkoutMap == "none" + - nm_create_another_brkout_port.current.0.infraBrkoutPortGrp.attributes.name == "ansible_breakout_port_2" + + - name: Query all breakout ports + cisco.aci.aci_interface_policy_leaf_breakout_port_group: + <<: *aci_info + state: query + register: query_all + + - name: Verify query_all + assert: + that: + query_all.current | length >= 2 + + - name: Query specific breakout port + cisco.aci.aci_interface_policy_leaf_breakout_port_group: + <<: *aci_info + breakout_port_group: ansible_breakout_port + state: query + register: query_one + + - name: Verify query_one + assert: + that: + - query_one is not changed + - query_one.current.0.infraBrkoutPortGrp.attributes.name == "ansible_breakout_port" + + - name: Update breakout port + cisco.aci.aci_interface_policy_leaf_breakout_port_group: + <<: *aci_info + breakout_port_group: ansible_breakout_port + breakout_map: none + description: "" + state: present + register: change_ansible_breakout_port + + - name: Verify change_ansible_breakout_port + assert: + that: + - change_ansible_breakout_port is changed + - change_ansible_breakout_port.current.0.infraBrkoutPortGrp.attributes.brkoutMap == "none" + - change_ansible_breakout_port.current.0.infraBrkoutPortGrp.attributes.descr == "" + + - name: Delete breakout port + cisco.aci.aci_interface_policy_leaf_breakout_port_group: + <<: *aci_info + breakout_port_group: ansible_breakout_port + state: absent + register: rm_breakout_port + + - name: Verify rm_breakout_port + assert: + that: + - rm_breakout_port is changed + - rm_breakout_port.current == [] + + - name: Query removed breakout port + cisco.aci.aci_interface_policy_leaf_breakout_port_group: + <<: *aci_info + breakout_port_group: ansible_breakout_port + state: query + register: query_removed_breakout_port + + - name: Verify query_removed_breakout_port + assert: + that: + - query_removed_breakout_port.current == []
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_policy_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_policy_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_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_policy_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_policy_group/tasks/main.yml new file mode 100644 index 000000000..f94ba4e48 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_policy_group/tasks/main.yml @@ -0,0 +1,460 @@ +# Test code for the ACI modules +# 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) + +- 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 + 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 + 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 + 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 + 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 + policy_group: policygroupname_link + lag_type: link + link_level_policy: linklevelpolicy + fibre_channel_interface_policy: fiberchannelpolicy + state: present + check_mode: true + register: intf_policy_leaf_polgrp_check_mode_present + + - name: Adding a interface policy leaf policy group (PC) - creation works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_link_present + register: intf_policy_leaf_polgrp_present + + - name: Adding a interface policy leaf policy group (PC) - idempotency works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_link_present + register: intf_policy_leaf_polgrp_idempotent + + - name: Adding a interface policy leaf policy group description (PC) - update works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_link_present + description: policygroup description + register: intf_policy_leaf_polgrp_update + + # TODO: also test for errors + - name: present assertions + assert: + that: + - intf_policy_leaf_polgrp_check_mode_present is changed + - intf_policy_leaf_polgrp_present is changed + - intf_policy_leaf_polgrp_present.previous == [] + - intf_policy_leaf_polgrp_present.sent.infraAccBndlGrp.attributes.lagT == 'link' + - intf_policy_leaf_polgrp_present.sent.infraAccBndlGrp.attributes.name == 'policygroupname_link' + - intf_policy_leaf_polgrp_present.sent.infraAccBndlGrp.children.0.infraRsFcIfPol.attributes.tnFcIfPolName == 'fiberchannelpolicy' + - intf_policy_leaf_polgrp_present.sent.infraAccBndlGrp.children.1.infraRsHIfPol.attributes.tnFabricHIfPolName == 'linklevelpolicy' + - intf_policy_leaf_polgrp_present.current.0.infraAccBndlGrp.attributes.annotation == 'orchestrator:ansible' + - intf_policy_leaf_polgrp_idempotent is not changed + - intf_policy_leaf_polgrp_idempotent.sent == {} + - intf_policy_leaf_polgrp_update is changed + - intf_policy_leaf_polgrp_update.sent.infraAccBndlGrp.attributes.descr == 'policygroup description' + + - 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 + policy_group: policygroupname_link + lag_type: link + state: query + register: binding_query + + - name: present assertions + assert: + that: + - binding_query is not changed + - binding_query.current | length >= 1 + - '"/api/mo/uni/infra/funcprof/accbundle-policygroupname_link.json" in binding_query.url' + + - name: Remove interface policy leaf policy group (PC) - check mode + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_link_absent + check_mode: true + register: intf_policy_leaf_polgrp_check_mode_absent + + - name: Remove interface policy leaf policy group (PC) - delete works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_link_absent + register: intf_policy_leaf_polgrp_absent + + - name: Remove interface policy leaf policy group (PC) - idempotency works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_link_absent + register: intf_policy_leaf_polgrp_absent_idempotent + + - 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 + policy_group: policygroupname_link + #lag_type: link + state: absent + ignore_errors: true + register: intf_policy_leaf_polgrp_absent_missing_param + + - name: absent assertions + assert: + that: + - intf_policy_leaf_polgrp_check_mode_absent is changed + - intf_policy_leaf_polgrp_check_mode_absent.previous != [] + - intf_policy_leaf_polgrp_absent is changed + - intf_policy_leaf_polgrp_absent.previous == intf_policy_leaf_polgrp_absent.previous + - intf_policy_leaf_polgrp_absent_idempotent is not changed + - intf_policy_leaf_polgrp_absent_idempotent.previous == [] + - intf_policy_leaf_polgrp_absent_missing_param is failed + - 'intf_policy_leaf_polgrp_absent_missing_param.msg == "missing required arguments: lag_type"' + + # ==== END TESTING Port Channel (PC), lag_type: link ==== + + + # ==== START TESTING Virtual Port Channel (VPC), lag_type: node ==== + + - 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 + + - 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 + policy_group: policygroupname_node + lag_type: node + link_level_policy: linklevelpolicy + fibre_channel_interface_policy: fiberchannelpolicy + state: present + check_mode: true + register: intf_policy_leaf_polgrp_check_mode_present + + - name: Adding a interface policy leaf policy group (VPC) - creation works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_node_present + register: intf_policy_leaf_polgrp_present + + - name: Adding a interface policy leaf policy group (VPC) - idempotency works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_node_present + register: intf_policy_leaf_polgrp_idempotent + + - name: Adding a interface policy leaf policy group description (VPC) - update works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_node_present + description: policygroup description + register: intf_policy_leaf_polgrp_update + + # TODO: also test for errors + - name: present assertions + assert: + that: + - intf_policy_leaf_polgrp_check_mode_present is changed + - intf_policy_leaf_polgrp_present is changed + - intf_policy_leaf_polgrp_present.previous == [] + - intf_policy_leaf_polgrp_present.sent.infraAccBndlGrp.attributes.lagT == 'node' + - intf_policy_leaf_polgrp_present.sent.infraAccBndlGrp.attributes.name == 'policygroupname_node' + - intf_policy_leaf_polgrp_present.sent.infraAccBndlGrp.children.0.infraRsFcIfPol.attributes.tnFcIfPolName == 'fiberchannelpolicy' + - intf_policy_leaf_polgrp_present.sent.infraAccBndlGrp.children.1.infraRsHIfPol.attributes.tnFabricHIfPolName == 'linklevelpolicy' + - intf_policy_leaf_polgrp_present.sent.infraAccBndlGrp.attributes.name == 'policygroupname_node' + - intf_policy_leaf_polgrp_idempotent is not changed + - intf_policy_leaf_polgrp_idempotent.sent == {} + - intf_policy_leaf_polgrp_update is changed + - intf_policy_leaf_polgrp_update.sent.infraAccBndlGrp.attributes.descr == 'policygroup description' + + - 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 + policy_group: policygroupname_node + lag_type: node + state: query + register: binding_query + + - name: present assertions + assert: + that: + - binding_query is not changed + - binding_query.current | length >= 1 + - '"/api/mo/uni/infra/funcprof/accbundle-policygroupname_node.json" in binding_query.url' + + # Add lag_type link to see what we get back + - name: Adding a interface policy leaf policy group (PC) - creation works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_link_present + register: intf_policy_leaf_polgrp_present + + - 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 + lag_type: node + state: query + register: binding_query_node_all + + - name: present assertions + assert: + that: + - binding_query_node_all is not changed + - binding_query_node_all.current | length >= 1 + - binding_query_node_all.current | selectattr("infraAccBndlGrp.attributes.lagT", "equalto", "link") | list == [] + - '"/api/class/infraAccBndlGrp.json" in binding_query_node_all.url' + + - name: Remove interface policy leaf policy group (VPC) - check mode + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_node_absent + check_mode: true + register: intf_policy_leaf_polgrp_check_mode_absent + + - name: Remove interface policy leaf policy group (VPC) - delete works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_node_absent + register: intf_policy_leaf_polgrp_absent + + - name: Remove interface policy leaf policy group (VPC) - idempotency works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *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 + 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 + policy_group: policygroupname_node + #lag_type: node + state: absent + ignore_errors: true + register: intf_policy_leaf_polgrp_absent_missing_param + + - name: absent assertions + assert: + that: + - intf_policy_leaf_polgrp_check_mode_absent is changed + - intf_policy_leaf_polgrp_check_mode_absent.previous != [] + - intf_policy_leaf_polgrp_absent is changed + - intf_policy_leaf_polgrp_absent.previous == intf_policy_leaf_polgrp_absent.previous + - intf_policy_leaf_polgrp_absent_idempotent is not changed + - intf_policy_leaf_polgrp_absent_idempotent.previous == [] + - intf_policy_leaf_polgrp_absent_missing_param is failed + - 'intf_policy_leaf_polgrp_absent_missing_param.msg == "missing required arguments: lag_type"' + + # ==== END TESTING Virtual Port Channel (VPC), lag_type: node ==== + + + # ==== START TESTING Virtual Port Channel (VPC), lag_type: leaf ==== + + - 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 + + - 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 + policy_group: policygroupname_leaf + lag_type: leaf + link_level_policy: linklevelpolicy + fibre_channel_interface_policy: fiberchannelpolicy + state: present + check_mode: true + register: intf_policy_leaf_polgrp_check_mode_present + + - name: Adding a interface policy leaf policy group (Leaf Access Port) - creation works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_leaf_present + register: intf_policy_leaf_polgrp_present + + - name: Adding a interface policy leaf policy group (Leaf Access Port) - idempotency works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_leaf_present + register: intf_policy_leaf_polgrp_idempotent + + - name: Adding a interface policy leaf policy group description (Leaf Access Port) - update works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_leaf_present + description: policygroup description + register: intf_policy_leaf_polgrp_update + + - name: Adding a interface policy leaf policy group (Leaf Access Port) - null parameter works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_leaf_present + port_channel_policy: null + ignore_errors: true + register: intf_policy_leaf_polgrp_parameter + + - name: Adding a interface policy leaf policy group (Leaf Access Port) - port_channel_policy not supported error + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_leaf_present + port_channel_policy: "default" + ignore_errors: true + register: intf_policy_leaf_polgrp_pc_policy_error + + # TODO: also test for errors + - name: present assertions + assert: + that: + - intf_policy_leaf_polgrp_check_mode_present is changed + - intf_policy_leaf_polgrp_present is changed + - intf_policy_leaf_polgrp_present.previous == [] + - 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_idempotent is not changed + - intf_policy_leaf_polgrp_idempotent.sent == {} + - intf_policy_leaf_polgrp_update is changed + - intf_policy_leaf_polgrp_update.sent.infraAccPortGrp.attributes.descr == 'policygroup description' + - intf_policy_leaf_polgrp_parameter is not changed + - intf_policy_leaf_polgrp_pc_policy_error.msg == 'port_channel_policy is not a valid parameter for leaf (leaf access port policy group), if used assign null to it (port_channel_policy{{":"}} null).' + + - 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 + policy_group: policygroupname_leaf + lag_type: leaf + state: query + register: binding_query + + - name: present assertions + 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' + + - name: Remove interface policy leaf policy group (Leaf Access Port) - check mode + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_leaf_absent + check_mode: true + register: intf_policy_leaf_polgrp_check_mode_absent + + - name: Remove interface policy leaf policy group (Leaf Access Port) - delete works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *aci_interface_policy_leaf_policy_group_leaf_absent + register: intf_policy_leaf_polgrp_absent + + - name: Remove interface policy leaf policy group (Leaf Access Port) - idempotency works + cisco.aci.aci_interface_policy_leaf_policy_group: + <<: *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 + 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 + policy_group: policygroupname_leaf + #lag_type: leaf + state: absent + ignore_errors: true + register: intf_policy_leaf_polgrp_absent_missing_param + + - name: absent assertions + assert: + that: + - intf_policy_leaf_polgrp_check_mode_absent is changed + - intf_policy_leaf_polgrp_check_mode_absent.previous != [] + - intf_policy_leaf_polgrp_absent is changed + - intf_policy_leaf_polgrp_absent.previous == intf_policy_leaf_polgrp_absent.previous + - intf_policy_leaf_polgrp_absent_idempotent is not changed + - intf_policy_leaf_polgrp_absent_idempotent.previous == [] + - intf_policy_leaf_polgrp_absent_missing_param is failed + - 'intf_policy_leaf_polgrp_absent_missing_param.msg == "missing required arguments: lag_type"' + + # ==== END TESTING Virtual Port Channel (VPC), lag_type: leaf ==== diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_profile/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_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_interface_policy_leaf_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_profile/tasks/main.yml new file mode 100644 index 000000000..51d553c54 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_profile/tasks/main.yml @@ -0,0 +1,273 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Shreyas Srish <ssrish@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) + +- 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 + block: # block specifies execution of tasks within, based on conditions + # CLEAN ENVIRONMENT + - name: Remove leaf profile + cisco.aci.aci_interface_policy_leaf_profile: &interface_policy_leaf_profile_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") }}' + leaf_interface_profile: ansible_test + state: absent + + - name: Remove leaf_interface_profile fex + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_absent + type: fex + leaf_interface_profile: ansible_test_fex + + # ADD LEAF INTERFACE PROFILE + - name: Add leaf interface profile (check_mode) + cisco.aci.aci_interface_policy_leaf_profile: &interface_policy_leaf_profile_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") }}' + interface_profile: ansible_test + state: present + check_mode: true + register: cm_add_leaf_interface_profile + + - name: Add leaf interface profile (normal mode) + cisco.aci.aci_interface_policy_leaf_profile: *interface_policy_leaf_profile_present + register: nm_add_leaf_interface_profile + + - name: Add leaf interface profile again (check_mode) + cisco.aci.aci_interface_policy_leaf_profile: *interface_policy_leaf_profile_present + check_mode: true + register: cm_add_leaf_interface_profile_again + + - name: Add leaf interface profile again (normal mode) + cisco.aci.aci_interface_policy_leaf_profile: *interface_policy_leaf_profile_present + register: nm_add_leaf_interface_profile_again + + - name: Add leaf interface profile fex (normal mode) + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_present + type: fex + leaf_interface_profile: ansible_test_fex + register: nm_add_leaf_interface_profile_fex + + - name: Verify add_leaf_interface_profile + assert: + that: + - cm_add_leaf_interface_profile is changed + - nm_add_leaf_interface_profile is changed + - nm_add_leaf_interface_profile.current.0.infraAccPortP.attributes.annotation == 'orchestrator:ansible' + - cm_add_leaf_interface_profile_again is not changed + - nm_add_leaf_interface_profile_again is not changed + - nm_add_leaf_interface_profile_fex is changed + + # CHANGE LEAF INTERFACE PROFILE + - name: Change description of leaf interface profile (check_mode) + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_present + description: Ansible test leaf interface profile + check_mode: true + register: cm_add_leaf_interface_profile_descr + + - name: Change description of leaf interface profile (normal mode) + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_present + description: Ansible test leaf interface profile + register: nm_add_leaf_interface_profile_descr + + - name: Change description of leaf interface profile again (check_mode) + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_present + description: Ansible test leaf interface profile + check_mode: true + register: cm_add_leaf_interface_profile_descr_again + + - name: Change description of leaf interface profile again (normal mode) + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_present + description: Ansible test leaf interface profile + register: nm_add_leaf_interface_profile_descr_again + + - name: Change description of leaf interface profile fex (normal mode) + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_present + type: fex + description: Ansible test leaf interface profile fex + leaf_interface_profile: ansible_test_fex + register: nm_add_leaf_interface_profile_descr_fex + + - name: Verify add_leaf_interface_profile_descr + assert: + that: + - cm_add_leaf_interface_profile_descr is changed + - nm_add_leaf_interface_profile_descr is changed + - nm_add_leaf_interface_profile_descr_fex is changed + - cm_add_leaf_interface_profile_descr_again is not changed + - nm_add_leaf_interface_profile_descr_again is not changed + + # ADD LEAF INTERFACE PROFILE AGAIN + - name: Add leaf interface profile again with no description (check_mode) + cisco.aci.aci_interface_policy_leaf_profile: *interface_policy_leaf_profile_present + check_mode: true + register: cm_add_leaf_interface_profile_again_no_descr + + - name: Add leaf interface profile again with no description (normal mode) + cisco.aci.aci_interface_policy_leaf_profile: *interface_policy_leaf_profile_present + register: nm_add_leaf_interface_profile_again_no_descr + + - name: Add leaf interface profile again with no description fex (normal mode) + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_present + type: fex + leaf_interface_profile: ansible_test_fex + register: nm_add_leaf_interface_profile_again_no_descr_fex + + - name: Verify add_leaf_interface_profile_again_no_descr + assert: + that: + - cm_add_leaf_interface_profile_again_no_descr is not changed + - nm_add_leaf_interface_profile_again_no_descr is not changed + - nm_add_leaf_interface_profile_again_no_descr_fex is not changed + + # QUERY ALL LEAF INTERFACE PROFILES + - name: Query all interface profiles (check_mode) + cisco.aci.aci_interface_policy_leaf_profile: &interface_policy_leaf_profile_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") }}' + state: query + check_mode: true + register: cm_query_all_leaf_interface_profiles + + - name: Query all leaf_interface_profiles (normal mode) + cisco.aci.aci_interface_policy_leaf_profile: *interface_policy_leaf_profile_query + register: nm_query_all_leaf_interface_profiles + + - name: Query all fex (normal mode) + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_query + type: fex + + - name: Verify query_all_leaf_interface_profiles + assert: + that: + - cm_query_all_leaf_interface_profiles is not changed + - nm_query_all_leaf_interface_profiles is not changed + # NOTE: Order of leaf_interface_profiles is not stable between calls + #- cm_query_all_leaf_interface_profiles == nm_query_all_leaf_interface_profiles + + # QUERY A LEAF INTERFACE PROFILE + - name: Query our leaf_interface_profile + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_query + leaf_interface_profile: ansible_test + check_mode: true + register: cm_query_leaf_interface_profile + + - name: Query our leaf_interface_profile + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_query + leaf_interface_profile: ansible_test + register: nm_query_leaf_interface_profile + + - name: Query our leaf_interface_profile fex + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_query + type: fex + leaf_interface_profile: ansible_test_fex + register: nm_query_leaf_interface_profile_fex + + - name: Verify query_leaf_interface_profile + assert: + that: + - cm_query_leaf_interface_profile is not changed + - nm_query_leaf_interface_profile is not changed + - nm_query_leaf_interface_profile_fex is not changed + - cm_query_leaf_interface_profile == nm_query_leaf_interface_profile + + # REMOVE LEAF INTERFACE PROFILE + - name: Remove leaf_interface_profile (check_mode) + cisco.aci.aci_interface_policy_leaf_profile: *interface_policy_leaf_profile_absent + check_mode: true + register: cm_remove_leaf_interface_profile + + - name: Remove leaf_interface_profile (normal mode) + cisco.aci.aci_interface_policy_leaf_profile: *interface_policy_leaf_profile_absent + register: nm_remove_leaf_interface_profile + + - name: Remove leaf_interface_profile again (check_mode) + cisco.aci.aci_interface_policy_leaf_profile: *interface_policy_leaf_profile_absent + check_mode: true + register: cm_remove_leaf_interface_profile_again + + - name: Remove leaf_interface_profile again (normal mode) + cisco.aci.aci_interface_policy_leaf_profile: *interface_policy_leaf_profile_absent + register: nm_remove_leaf_interface_profile_again + + - name: Remove leaf_interface_profile fex (normal mode) + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_absent + type: fex + leaf_interface_profile: ansible_test_fex + register: nm_remove_leaf_interface_profile_again_fex + + - name: Verify remove_leaf_interface_profile + assert: + that: + - cm_remove_leaf_interface_profile is changed + - nm_remove_leaf_interface_profile is changed + - nm_remove_leaf_interface_profile_again_fex is changed + - cm_remove_leaf_interface_profile_again is not changed + - nm_remove_leaf_interface_profile_again is not changed + + # QUERY NON-EXISTING LEAF INTERFACE PROFILE + - name: Query non-existing leaf_interface_profile (check_mode) + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_query + leaf_interface_profile: ansible_test + check_mode: true + register: cm_query_non_leaf_interface_profile + + - name: Query non-existing leaf_interface_profile (normal mode) + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_query + leaf_interface_profile: ansible_test + register: nm_query_non_leaf_interface_profile + + - name: Query non-existing leaf_interface_profile fex (normal mode) + cisco.aci.aci_interface_policy_leaf_profile: + <<: *interface_policy_leaf_profile_query + type: fex + leaf_interface_profile: ansible_test_fex + register: nm_query_non_leaf_interface_profile_fex + + # TODO: Implement more tests + - name: Verify query_non_leaf_interface_profile + assert: + that: + - cm_query_non_leaf_interface_profile is not changed + - nm_query_non_leaf_interface_profile is not changed + - nm_query_non_leaf_interface_profile_fex is not changed + - cm_query_non_leaf_interface_profile == nm_query_non_leaf_interface_profile
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_profile_fex_policy_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_profile_fex_policy_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_profile_fex_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_profile_fex_policy_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_profile_fex_policy_group/tasks/main.yml new file mode 100644 index 000000000..41853af11 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_leaf_profile_fex_policy_group/tasks/main.yml @@ -0,0 +1,295 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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: 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: Ensure anstest_fex_profile - Interface Policy Fex profile does not exists + cisco.aci.aci_interface_policy_leaf_profile: &fex_profile_absent + <<: *aci_info + type: fex + leaf_interface_profile: anstest_fex_profile + state: absent + + - name: Add anstest_fex_profile - Interface Policy Fex profile + cisco.aci.aci_interface_policy_leaf_profile: &fex_profile_present + <<: *fex_profile_absent + state: present + register: fex_profile_present + + - name: Add Fex Policy Group to anstest_fex_profile - Interface Policy Fex profile with check mode + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + &cm_fex_policy_group_present + <<: *aci_info + name: anstest_fex_policy_group + fex_profile: anstest_fex_profile + state: present + check_mode: true + register: cm_fex_policy_group_present + + - name: Assertions check for add Fex Policy Group to anstest_fex_profile - Interface Policy Fex profile with check mode + assert: + that: + - cm_fex_policy_group_present is changed + - cm_fex_policy_group_present.current | length == 0 + - cm_fex_policy_group_present.previous | length == 0 + - cm_fex_policy_group_present.sent.infraFexBndlGrp.attributes.name == "anstest_fex_policy_group" + - cm_fex_policy_group_present.sent.infraFexBndlGrp.attributes.dn == "uni/infra/fexprof-anstest_fex_profile/fexbundle-anstest_fex_policy_group" + + - name: Add Fex Policy Group to anstest_fex_profile - Interface Policy Fex profile with normal mode + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + &nm_fex_policy_group_present + <<: *cm_fex_policy_group_present + register: nm_fex_policy_group_present + + - name: Assertions check for add Fex Policy Group to anstest_fex_profile - Interface Policy Fex profile with normal mode + assert: + that: + - nm_fex_policy_group_present is changed + - nm_fex_policy_group_present.current | length == 1 + - nm_fex_policy_group_present.previous | length == 0 + - nm_fex_policy_group_present.current.0.infraFexBndlGrp.attributes.name == "anstest_fex_policy_group" + - nm_fex_policy_group_present.current.0.infraFexBndlGrp.attributes.dn == "uni/infra/fexprof-anstest_fex_profile/fexbundle-anstest_fex_policy_group" + + - name: Add Fex Policy Group to anstest_fex_profile - Interface Policy Fex profile with normal mode - idempotency works + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + &idempotency_fex_policy_group_present + <<: *nm_fex_policy_group_present + register: idempotency_fex_policy_group_present + + - name: Idempotency assertions check for add Fex Policy Group to anstest_fex_profile - Interface Policy Fex profile with normal mode + assert: + that: + - idempotency_fex_policy_group_present is not changed + - idempotency_fex_policy_group_present.current | length == 1 + - idempotency_fex_policy_group_present.previous | length == 1 + - idempotency_fex_policy_group_present.current.0.infraFexBndlGrp.attributes.name == "anstest_fex_policy_group" + - idempotency_fex_policy_group_present.current.0.infraFexBndlGrp.attributes.dn == "uni/infra/fexprof-anstest_fex_profile/fexbundle-anstest_fex_policy_group" + - idempotency_fex_policy_group_present.previous.0.infraFexBndlGrp.attributes.name == "anstest_fex_policy_group" + - idempotency_fex_policy_group_present.previous.0.infraFexBndlGrp.attributes.dn == "uni/infra/fexprof-anstest_fex_profile/fexbundle-anstest_fex_policy_group" + + - name: Add multiple Fex Policy Group to anstest_fex_profile - Interface Policy Fex profile with normal mode + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + <<: *aci_info + name: "{{ item.name }}" + fex_profile: "{{ item.fex_profile }}" + state: present + with_items: + - name: anstest_fex_policy_group_1 + fex_profile: anstest_fex_profile + - name: anstest_fex_policy_group_2 + fex_profile: anstest_fex_profile + register: multiple_fex_policy_group_present + + - name: Assertions check for add multiple Fex Policy Group to anstest_fex_profile - Interface Policy Fex profile with normal mode + assert: + that: + - multiple_fex_policy_group_present is changed + - multiple_fex_policy_group_present.results.0 is changed + - multiple_fex_policy_group_present.results.1 is changed + - multiple_fex_policy_group_present.results.0.current | length == 1 + - multiple_fex_policy_group_present.results.1.current | length == 1 + - multiple_fex_policy_group_present.results.0.current.0.infraFexBndlGrp.attributes.name == "anstest_fex_policy_group_1" + - multiple_fex_policy_group_present.results.1.current.0.infraFexBndlGrp.attributes.name == "anstest_fex_policy_group_2" + - multiple_fex_policy_group_present.results.0.current.0.infraFexBndlGrp.attributes.dn == "uni/infra/fexprof-anstest_fex_profile/fexbundle-anstest_fex_policy_group_1" + - multiple_fex_policy_group_present.results.1.current.0.infraFexBndlGrp.attributes.dn == "uni/infra/fexprof-anstest_fex_profile/fexbundle-anstest_fex_policy_group_2" + + - name: Ensure temp_anstest_fex_profile - Interface Policy Fex profile does not exists + cisco.aci.aci_interface_policy_leaf_profile: &temp_anstest_fex_profile_absent + <<: *aci_info + type: fex + leaf_interface_profile: temp_anstest_fex_profile + state: absent + register: temp_anstest_fex_profile_absent + + - name: Assertions check for remove temp_anstest_fex_profile - Interface Policy Fex profile + assert: + that: + - temp_anstest_fex_profile_absent.current | length == 0 + + - name: Add temp_anstest_fex_profile - Interface Policy Fex profile + cisco.aci.aci_interface_policy_leaf_profile: &temp_anstest_fex_profile_present + <<: *temp_anstest_fex_profile_absent + state: present + register: temp_anstest_fex_profile_present + + - name: Assertions check for add temp_anstest_fex_profile - Interface Policy Fex profile + assert: + that: + - temp_anstest_fex_profile_present is changed + - temp_anstest_fex_profile_present.current | length == 1 + - temp_anstest_fex_profile_present.previous | length == 0 + + - name: Add Fex Policy Group to temp_anstest_fex_profile - Interface Policy Fex profile + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + <<: *aci_info + name: anstest_fex_policy_group + fex_profile: temp_anstest_fex_profile + state: present + register: temp_anstest_fex_policy_group_present + + - name: Assertions check for add Fex Policy Group to temp_anstest_fex_profile - Interface Policy Fex profile + assert: + that: + - temp_anstest_fex_policy_group_present is changed + - temp_anstest_fex_policy_group_present.current | length == 1 + - temp_anstest_fex_policy_group_present.previous | length == 0 + - temp_anstest_fex_policy_group_present.current.0.infraFexBndlGrp.attributes.name == "anstest_fex_policy_group" + - temp_anstest_fex_policy_group_present.current.0.infraFexBndlGrp.attributes.dn == "uni/infra/fexprof-temp_anstest_fex_profile/fexbundle-anstest_fex_policy_group" + + - name: Query anstest_fex_policy_group - fex policy group with fex_profile + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + <<: *aci_info + name: anstest_fex_policy_group + fex_profile: anstest_fex_profile + state: query + register: query_res_fex_policy_group_with_profile + + - name: Assertions check for query anstest_fex_policy_group - fex policy group with fex_profile + assert: + that: + - query_res_fex_policy_group_with_profile is not changed + - query_res_fex_policy_group_with_profile.current | length == 1 + - query_res_fex_policy_group_with_profile.current.0.infraFexBndlGrp.attributes.name == "anstest_fex_policy_group" + - query_res_fex_policy_group_with_profile.current.0.infraFexBndlGrp.attributes.dn == "uni/infra/fexprof-anstest_fex_profile/fexbundle-anstest_fex_policy_group" + + - name: Query all fex policy group under anstest_fex_profile + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + <<: *aci_info + fex_profile: anstest_fex_profile + state: query + register: query_all_policy_groups_under_fex_profile + + - name: Assertions check for query all fex policy group under anstest_fex_profile + assert: + that: + - query_all_policy_groups_under_fex_profile is not changed + - query_all_policy_groups_under_fex_profile.current.0.infraFexP.children | length == 3 + + - name: Query all anstest_fex_policy_group - fex policy groups + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + <<: *aci_info + name: anstest_fex_policy_group + state: query + register: query_res_anstest_fex_policy_group + + - name: Assertions check for query all anstest_fex_policy_group - fex policy groups + assert: + that: + - query_res_anstest_fex_policy_group is not changed + - query_res_anstest_fex_policy_group.current | length >= 2 + - query_res_anstest_fex_policy_group.current.0.infraFexBndlGrp.attributes.name == "anstest_fex_policy_group" + - query_res_anstest_fex_policy_group.current.1.infraFexBndlGrp.attributes.name == "anstest_fex_policy_group" + + - name: Query all - fex policy groups + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + <<: *aci_info + state: query + register: all_fex_policy_groups + + - name: Assertions check for query all - fex policy groups + assert: + that: + - all_fex_policy_groups is not changed + - all_fex_policy_groups.current | length >= 4 + + - name: Remove anstest_fex_policy_group - Fex Policy Group from anstest_fex_profile with check mode + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + &cm_anstest_fex_policy_group_absent + <<: *aci_info + name: anstest_fex_policy_group + fex_profile: anstest_fex_profile + state: absent + check_mode: true + register: cm_anstest_fex_policy_group_absent + + - name: Assertions check for remove anstest_fex_policy_group - Fex Policy Group from anstest_fex_profile with check mode + assert: + that: + - cm_anstest_fex_policy_group_absent is changed + - cm_anstest_fex_policy_group_absent.current | length == 1 + - cm_anstest_fex_policy_group_absent.previous | length == 1 + - cm_anstest_fex_policy_group_absent.current.0.infraFexBndlGrp.attributes.name == "anstest_fex_policy_group" + - cm_anstest_fex_policy_group_absent.current.0.infraFexBndlGrp.attributes.dn == "uni/infra/fexprof-anstest_fex_profile/fexbundle-anstest_fex_policy_group" + - cm_anstest_fex_policy_group_absent.previous.0.infraFexBndlGrp.attributes.name == "anstest_fex_policy_group" + - cm_anstest_fex_policy_group_absent.previous.0.infraFexBndlGrp.attributes.dn == "uni/infra/fexprof-anstest_fex_profile/fexbundle-anstest_fex_policy_group" + + - name: Remove anstest_fex_policy_group - Fex Policy Group from anstest_fex_profile with normal mode + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + &nm_anstest_fex_policy_group_absent + <<: *cm_anstest_fex_policy_group_absent + register: nm_anstest_fex_policy_group_absent + + - name: Assertions check for remove anstest_fex_policy_group - Fex Policy Group from anstest_fex_profile with normal mode + assert: + that: + - nm_anstest_fex_policy_group_absent is changed + - nm_anstest_fex_policy_group_absent.current | length == 0 + - nm_anstest_fex_policy_group_absent.previous | length == 1 + - nm_anstest_fex_policy_group_absent.previous.0.infraFexBndlGrp.attributes.name == "anstest_fex_policy_group" + - nm_anstest_fex_policy_group_absent.previous.0.infraFexBndlGrp.attributes.dn == "uni/infra/fexprof-anstest_fex_profile/fexbundle-anstest_fex_policy_group" + + - name: Remove anstest_fex_policy_group - Fex Policy Group from anstest_fex_profile with normal mode - idempotency works + cisco.aci.aci_interface_policy_leaf_profile_fex_policy_group: + &idempotency_anstest_fex_policy_group_absent + <<: *nm_anstest_fex_policy_group_absent + register: idempotency_anstest_fex_policy_group_absent + + - name: Idempotency assertions check for remove anstest_fex_policy_group - Fex Policy Group from anstest_fex_profile with normal mode + assert: + that: + - idempotency_anstest_fex_policy_group_absent is not changed + - idempotency_anstest_fex_policy_group_absent.current | length == 0 + - idempotency_anstest_fex_policy_group_absent.previous | length == 0 + + - name: Remove temp_anstest_fex_profile Fex Profile + cisco.aci.aci_interface_policy_leaf_profile: + <<: *temp_anstest_fex_profile_present + state: absent + register: temp_anstest_fex_profile_absent + + - name: Assertions check for remove temp_anstest_fex_profile Fex Profile + assert: + that: + - temp_anstest_fex_profile_absent is changed + - temp_anstest_fex_profile_absent.current | length == 0 + - temp_anstest_fex_profile_absent.previous | length == 1 + - temp_anstest_fex_profile_absent.previous.0.infraFexP.attributes.name == "temp_anstest_fex_profile" + - temp_anstest_fex_profile_absent.previous.0.infraFexP.attributes.dn == "uni/infra/fexprof-temp_anstest_fex_profile" + + - name: Remove anstest_fex_profile Fex Profile + cisco.aci.aci_interface_policy_leaf_profile: + <<: *fex_profile_present + state: absent + register: fex_profile_present_absent + + - name: Assertions check for remove anstest_fex_profile Fex Profile + assert: + that: + - fex_profile_present_absent is changed + - fex_profile_present_absent.current | length == 0 + - fex_profile_present_absent.previous | length == 1 + - fex_profile_present_absent.previous.0.infraFexP.attributes.name == "anstest_fex_profile" + - fex_profile_present_absent.previous.0.infraFexP.attributes.dn == "uni/infra/fexprof-anstest_fex_profile" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_link_level/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_link_level/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_link_level/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_link_level/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_link_level/tasks/main.yml new file mode 100644 index 000000000..a3ee0c4b8 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_link_level/tasks/main.yml @@ -0,0 +1,292 @@ +# Test code for the ACI modules +# Copyright: (c) 2019, Vasily Prokopov (@vasilyprokopov) +# Copyright: (c) 2020, Shreyas Srish (@shrsr) + +# GNU General Public License v3.0+ (see COPYING 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 + block: # block specifies execution of tasks within, based on conditions + # CLEAN ENVIRONMENT + - name: Remove Link Level Policy + aci_interface_policy_link_level: &interface_policy_link_level_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") }}' + link_level_policy: ansible_test + state: absent + + # ADD LINK LEVEL POLICY + - name: Add Link Level Policy (check mode) + aci_interface_policy_link_level: &interface_policy_link_level_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") }}' + link_level_policy: ansible_test + state: present + check_mode: true + register: cm_add_policy + + - name: Add Link Level Policy (normal mode) + aci_interface_policy_link_level: *interface_policy_link_level_present + register: nm_add_policy + + - name: Verify Add Link Level Policy + assert: + that: + - cm_add_policy is changed + - nm_add_policy is changed + - nm_add_policy.previous == cm_add_policy.previous == cm_add_policy.current == [] + - nm_add_policy.current.0.fabricHIfPol.attributes.name == 'ansible_test' + - nm_add_policy.current.0.fabricHIfPol.attributes.dn == 'uni/infra/hintfpol-ansible_test' + - nm_add_policy.current.0.fabricHIfPol.attributes.annotation == 'orchestrator:ansible' + - nm_add_policy.proposed.fabricHIfPol.attributes.name == cm_add_policy.proposed.fabricHIfPol.attributes.name == nm_add_policy.sent.fabricHIfPol.attributes.name == 'ansible_test' + + - name: Add Link Level Policy again (check mode) + aci_interface_policy_link_level: *interface_policy_link_level_present + check_mode: true + register: cm_add_policy_again + + - name: Add Link Level Policy again (normal mode) + aci_interface_policy_link_level: *interface_policy_link_level_present + register: nm_add_policy_again + + - name: Verify Add Link Level Policy again + assert: + that: + - cm_add_policy_again is not changed + - nm_add_policy_again is not changed + - nm_add_policy_again.previous.0.fabricHIfPol.attributes.name == cm_add_policy_again.previous.0.fabricHIfPol.attributes.name == nm_add_policy_again.current.0.fabricHIfPol.attributes.name == cm_add_policy_again.current.0.fabricHIfPol.attributes.name == 'ansible_test' + - nm_add_policy.proposed.fabricHIfPol.attributes.name == cm_add_policy.proposed.fabricHIfPol.attributes.name == nm_add_policy.sent.fabricHIfPol.attributes.name == cm_add_policy.sent.fabricHIfPol.attributes.name == 'ansible_test' + - nm_add_policy_again.sent == cm_add_policy_again.sent == {} + + # CHANGE LINK LEVEL POLICY + - name: Change description of Link Level Policy (check mode) + aci_interface_policy_link_level: + <<: *interface_policy_link_level_present + description: Ansible test Link Level Policy + check_mode: true + register: cm_add_policy_descr + + - name: Change description of Link Level Policy (normal mode) + aci_interface_policy_link_level: + <<: *interface_policy_link_level_present + description: Ansible test Link Level Policy + register: nm_add_policy_descr + + - name: Verify add_policy_descr + assert: + that: + - cm_add_policy_descr is changed + - nm_add_policy_descr is changed + - cm_add_policy_descr.proposed.fabricHIfPol.attributes.name == nm_add_policy_descr.proposed.fabricHIfPol.attributes.name == 'ansible_test' + - nm_add_policy_descr.current.0.fabricHIfPol.attributes.dn == 'uni/infra/hintfpol-ansible_test' + + - name: Change description of Link Level Policy again (check mode) + aci_interface_policy_link_level: + <<: *interface_policy_link_level_present + description: Ansible test Link Level Policy + check_mode: true + register: cm_add_policy_descr_again + + - name: Change description of Link Level Policy again (normal mode) + aci_interface_policy_link_level: + <<: *interface_policy_link_level_present + description: Ansible test Link Level Policy + register: nm_add_policy_descr_again + + - name: Verify add_policy_descr_again + assert: + that: + - cm_add_policy_descr_again is not changed + - nm_add_policy_descr_again is not changed + - cm_add_policy_descr_again.proposed.fabricHIfPol.attributes.name == nm_add_policy_descr_again.proposed.fabricHIfPol.attributes.name == 'ansible_test' + - cm_add_policy_descr_again.sent == nm_add_policy_descr_again.sent == {} + - cm_add_policy_descr_again.previous.0.fabricHIfPol.attributes.dn == nm_add_policy_descr_again.previous.0.fabricHIfPol.attributes.dn == cm_add_policy_descr_again.current.0.fabricHIfPol.attributes.dn == nm_add_policy_descr_again.current.0.fabricHIfPol.attributes.dn == 'uni/infra/hintfpol-ansible_test' + + # ADD LINK LEVEL POLICY AGAIN WITH NO DESCRIPTION + - name: Add Link Level Policy again with no description (check mode) + aci_interface_policy_link_level: *interface_policy_link_level_present + check_mode: true + register: cm_add_policy_again_no_descr + + - name: Add Link Level Policy again with no description (normal mode) + aci_interface_policy_link_level: *interface_policy_link_level_present + register: nm_add_policy_again_no_descr + + - name: Verify add_policy_again_no_descr + assert: + that: + - cm_add_policy_again_no_descr is not changed + - nm_add_policy_again_no_descr is not changed + - cm_add_policy_again_no_descr.proposed.fabricHIfPol.attributes.name == nm_add_policy_again_no_descr.proposed.fabricHIfPol.attributes.name == 'ansible_test' + - cm_add_policy_again_no_descr.sent == nm_add_policy_again_no_descr.sent == {} + - cm_add_policy_again_no_descr.previous.0.fabricHIfPol.attributes.dn== nm_add_policy_again_no_descr.previous.0.fabricHIfPol.attributes.dn == cm_add_policy_again_no_descr.current.0.fabricHIfPol.attributes.dn == nm_add_policy_again_no_descr.current.0.fabricHIfPol.attributes.dn == 'uni/infra/hintfpol-ansible_test' + + # QUERY ALL LINK LEVEL POLICIES + - name: Query all Link Level Policies (check mode) + aci_interface_policy_link_level: &interface_policy_link_level_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") }}' + state: query + check_mode: true + register: cm_query_all_policies + + - name: Query all Link Level Policies (normal mode) + aci_interface_policy_link_level: *interface_policy_link_level_query + register: nm_query_all_policies + + - name: Verify query_all_policies + assert: + that: + - cm_query_all_policies is not changed + - nm_query_all_policies is not changed + - cm_query_all_policies == nm_query_all_policies + - nm_query_all_policies.current|length >= 1 + + # QUERY A LINK LEVEL POLICY + - name: Query our Link Level Policy (check mode) + aci_interface_policy_link_level: + <<: *interface_policy_link_level_query + link_level_policy: ansible_test + check_mode: true + register: cm_query_policy + + - name: Query our Link Level Policy (normal mode) + aci_interface_policy_link_level: + <<: *interface_policy_link_level_query + link_level_policy: ansible_test + register: nm_query_policy + + - name: Verify query_policy + assert: + that: + - cm_query_policy is not changed + - nm_query_policy is not changed + - cm_query_policy == nm_query_policy + - nm_query_policy.current.0.fabricHIfPol.attributes.descr == 'Ansible test Link Level Policy' + - nm_query_policy.current.0.fabricHIfPol.attributes.dn == 'uni/infra/hintfpol-ansible_test' + - nm_query_policy.current.0.fabricHIfPol.attributes.name == 'ansible_test' + + # REMOVE LINK LEVEL POLICY + - name: Remove Link Level Policy (check mode) + aci_interface_policy_link_level: *interface_policy_link_level_absent + check_mode: true + register: cm_remove_policy + + - name: Remove Link Level Policy (normal mode) + aci_interface_policy_link_level: *interface_policy_link_level_absent + register: nm_remove_policy + + - name: Verify remove_policy + assert: + that: + - cm_remove_policy is changed + - nm_remove_policy is changed + - cm_remove_policy.proposed == nm_remove_policy.proposed == {} + - cm_remove_policy.sent == nm_remove_policy.sent == {} + - cm_remove_policy.previous.0.fabricHIfPol.attributes.dn == nm_remove_policy.previous.0.fabricHIfPol.attributes.dn == cm_remove_policy.current.0.fabricHIfPol.attributes.dn == 'uni/infra/hintfpol-ansible_test' + - nm_remove_policy.current == [] + + - name: Remove Link Level Policy again (check mode) + aci_interface_policy_link_level: *interface_policy_link_level_absent + check_mode: true + register: cm_remove_policy_again + + - name: Remove Link Level Policy again (normal mode) + aci_interface_policy_link_level: *interface_policy_link_level_absent + register: nm_remove_policy_again + + - name: Verify remove_policy_again + assert: + that: + - cm_remove_policy_again is not changed + - nm_remove_policy_again is not changed + - cm_remove_policy_again.proposed == nm_remove_policy_again.proposed == {} + - cm_remove_policy_again.sent == nm_remove_policy_again.sent == {} + - cm_remove_policy_again.previous == nm_remove_policy_again.previous == cm_remove_policy_again.current == nm_remove_policy_again.current == [] + + # QUERY NON-EXISTING LINK LEVEL POLICY + - name: Query non-existing Link Level Policy (check mode) + aci_interface_policy_link_level: + <<: *interface_policy_link_level_query + link_level_policy: ansible_test + check_mode: true + register: cm_query_non_policy + + - name: Query non-existing Link Level Policy (normal mode) + aci_interface_policy_link_level: + <<: *interface_policy_link_level_query + link_level_policy: ansible_test + register: nm_query_non_policy + + - name: Verify query_non_policy + assert: + that: + - cm_query_non_policy is not changed + - nm_query_non_policy is not changed + - cm_query_non_policy == nm_query_non_policy + - cm_query_non_policy.current == nm_query_non_policy.current == [] + + # PROVOKE ERRORS - REQUIRED PARAMETER MISSING + - name: Error when required parameter is missing + aci_interface_policy_link_level: + 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") }}' + state: present + ignore_errors: true + register: error_on_missing_required_param + + - name: Verify error_on_missing_required_param + assert: + that: + - error_on_missing_required_param is failed + - 'error_on_missing_required_param.msg == "state is present but all of the following are missing: link_level_policy"' + + # PROVOKE ERRORS - DEBOUNCE OUT OF RANGE + - name: Error when link debounce interval is out of range + aci_interface_policy_link_level: + 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") }}' + state: present + link_level_policy: ansible_test + link_debounce_interval: 5005 + ignore_errors: true + register: error_on_debounce_out_of_range + + - name: Verify error_on_debounce_out_of_range + assert: + that: + - error_on_debounce_out_of_range is failed + - 'error_on_debounce_out_of_range.msg == "The \"link_debounce_interval\" must be a value between 0 and 5000"'
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_ospf/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_ospf/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_ospf/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_ospf/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_ospf/tasks/main.yml new file mode 100644 index 000000000..96a5472f0 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_ospf/tasks/main.yml @@ -0,0 +1,232 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Dag Wieers (dagwieers) <dag@wieers.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 + + +# 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 + 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 + 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 + state: present + check_mode: true + register: cm_add_ospf_interface_policy + +- name: Add ospf interface policy (normal mode) + cisco.aci.aci_interface_policy_ospf: *interface_policy_ospf_present + register: nm_add_ospf_interface_policy + +- name: Add ospf interface policy again (check_mode) + cisco.aci.aci_interface_policy_ospf: *interface_policy_ospf_present + check_mode: true + register: cm_add_ospf_interface_policy_again + +- name: Add ospf interface policy again (normal mode) + cisco.aci.aci_interface_policy_ospf: *interface_policy_ospf_present + register: nm_add_ospf_interface_policy_again + +- name: Verify add_ospf_interface_policy + assert: + that: + - cm_add_ospf_interface_policy is changed + - nm_add_ospf_interface_policy is changed + - nm_add_ospf_interface_policy.current.0.ospfIfPol.attributes.annotation == 'orchestrator:ansible' + - cm_add_ospf_interface_policy_again is not changed + - nm_add_ospf_interface_policy_again is not changed + + +# CHANGE OSPF INTERFACE POLICY +- name: Change description of ospf interface policy (check_mode) + cisco.aci.aci_interface_policy_ospf: + <<: *interface_policy_ospf_present + description: Ansible test ospf interface policy + 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 + 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 + 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 + register: nm_add_ospf_descr_again + +- name: Verify add_ospf_descr + assert: + that: + - cm_add_ospf_descr is changed + - nm_add_ospf_descr is changed + - cm_add_ospf_descr_again is not changed + - nm_add_ospf_descr_again is not changed + + +# ADD OSPF INTERFACE POLICY AGAIN +- name: Add ospf interface policy again with no description (check_mode) + cisco.aci.aci_interface_policy_ospf: *interface_policy_ospf_present + check_mode: true + register: cm_add_ospf_again_no_descr + +- name: Add ospf interface policy again with no description (normal mode) + cisco.aci.aci_interface_policy_ospf: *interface_policy_ospf_present + register: nm_add_ospf_again_no_descr + +- name: Verify add_ospf_again_no_descr + assert: + that: + - cm_add_ospf_again_no_descr is not changed + - nm_add_ospf_again_no_descr is not changed + + +# QUERY ALL OSPF INTERFACE POLICIES +- name: Query all ospf interface policies (check_mode) + cisco.aci.aci_interface_policy_ospf: &interface_policy_ospf_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") }}' + tenant: ansible_test + state: query + check_mode: true + register: cm_query_all_ospfs + +- name: Query all ospfs (normal mode) + cisco.aci.aci_interface_policy_ospf: *interface_policy_ospf_query + register: nm_query_all_ospfs + +- name: Verify query_all_ospfs + assert: + that: + - cm_query_all_ospfs is not changed + - nm_query_all_ospfs is not changed + # NOTE: Order of ospfs is not stable between calls + #- cm_query_all_ospfs == nm_query_all_ospfs + + +# QUERY A OSPF INTERFACE POLICY +- name: Query our ospf + cisco.aci.aci_interface_policy_ospf: + <<: *interface_policy_ospf_query + tenant: ansible_test + ospf: ansible_ospf + check_mode: true + register: cm_query_ospf + +- name: Query our ospf + cisco.aci.aci_interface_policy_ospf: + <<: *interface_policy_ospf_query + tenant: ansible_test + ospf: ansible_ospf + register: nm_query_ospf + +- name: Verify query_ospf + assert: + that: + - cm_query_ospf is not changed + - nm_query_ospf is not changed + - cm_query_ospf == nm_query_ospf + + +# REMOVE OSPF INTERFACE POLICY +- name: Remove ospf (check_mode) + cisco.aci.aci_interface_policy_ospf: *interface_policy_ospf_absent + check_mode: true + register: cm_remove_ospf + +- name: Remove ospf (normal mode) + cisco.aci.aci_interface_policy_ospf: *interface_policy_ospf_absent + register: nm_remove_ospf + +- name: Remove ospf again (check_mode) + cisco.aci.aci_interface_policy_ospf: *interface_policy_ospf_absent + check_mode: true + register: cm_remove_ospf_again + +- name: Remove ospf again (normal mode) + cisco.aci.aci_interface_policy_ospf: *interface_policy_ospf_absent + register: nm_remove_ospf_again + +- name: Verify remove_ospf + assert: + that: + - cm_remove_ospf is changed + - nm_remove_ospf is changed + - cm_remove_ospf_again is not changed + - nm_remove_ospf_again is not changed + + +# QUERY NON-EXISTING OSPF INTERFACE POLICY +- name: Query non-existing ospf (check_mode) + cisco.aci.aci_interface_policy_ospf: + <<: *interface_policy_ospf_query + ospf: ansible_ospf + check_mode: true + register: cm_query_non_ospf + +- name: Query non-existing ospf (normal mode) + cisco.aci.aci_interface_policy_ospf: + <<: *interface_policy_ospf_query + ospf: ansible_ospf + register: nm_query_non_ospf + +# TODO: Implement more tests +- name: Verify query_non_ospf + assert: + that: + - cm_query_non_ospf is not changed + - nm_query_non_ospf is not changed + - cm_query_non_ospf == nm_query_non_ospf diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_port_security/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_port_security/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_port_security/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_security/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_port_security/tasks/main.yml new file mode 100644 index 000000000..c040bfb1e --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_port_security/tasks/main.yml @@ -0,0 +1,177 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Shreyas Srish <ssrish@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: Remove policy port security + aci_interface_policy_port_security: + <<: *aci_info + port_security: '{{ item }}' + state: absent + loop: + - security1 + - security2 + - security3 + + # ADD + - name: Add a port security interface policy - check mode + aci_interface_policy_port_security: + <<: *aci_info + port_security: security1 + description: security 1 + max_end_points: 300 + port_security_timeout: 190 + state: present + check_mode: true + register: port_security1_cm + + - name: Add a port security interface policy - normal mode + aci_interface_policy_port_security: + <<: *aci_info + port_security: security1 + description: security 1 + max_end_points: 300 + port_security_timeout: 190 + state: present + register: port_security1_nm + + - name: Add a port security interface policy again - normal mode + aci_interface_policy_port_security: + <<: *aci_info + port_security: security1 + description: security 1 + max_end_points: 300 + port_security_timeout: 190 + state: present + register: port_security1_nm_again + + - name: Add a port security interface policy - normal mode + aci_interface_policy_port_security: + <<: *aci_info + port_security: security2 + description: security 2 + max_end_points: 300 + port_security_timeout: 10 + state: present + ignore_errors: true + register: port_security1_nm_error_timeout + + - name: Add a port security interface policy - normal mode + aci_interface_policy_port_security: + <<: *aci_info + port_security: security3 + description: security 3 + max_end_points: 15000 + port_security_timeout: 60 + state: present + ignore_errors: true + register: port_security1_nm_error_max + + - name: Add a port security interface policy again for security 3- normal mode + aci_interface_policy_port_security: + <<: *aci_info + port_security: security3 + description: security 3 + max_end_points: 12000 + port_security_timeout: 60 + state: present + ignore_errors: true + register: port_security1_nm_with_no_error + + - name: Verify present cases + assert: + that: + - port_security1_cm is changed + - port_security1_nm is changed + - port_security1_cm.proposed.l2PortSecurityPol.attributes.dn == "uni/infra/portsecurityP-security1" + - port_security1_cm.proposed.l2PortSecurityPol.attributes.name == "security1" + - port_security1_cm.proposed.l2PortSecurityPol.attributes.timeout == "190" + - port_security1_cm.proposed.l2PortSecurityPol.attributes.maximum == "300" + - port_security1_cm.proposed.l2PortSecurityPol.attributes.descr == "security 1" + - port_security1_nm.current.0.l2PortSecurityPol.attributes.dn == "uni/infra/portsecurityP-security1" + - port_security1_nm.current.0.l2PortSecurityPol.attributes.name == "security1" + - port_security1_nm.current.0.l2PortSecurityPol.attributes.timeout == "190" + - port_security1_nm.current.0.l2PortSecurityPol.attributes.maximum == "300" + - port_security1_nm.current.0.l2PortSecurityPol.attributes.descr == "security 1" + - port_security1_nm.current.0.l2PortSecurityPol.attributes.annotation == 'orchestrator:ansible' + - port_security1_nm_again is not changed + - port_security1_nm_error_timeout.msg == "The port_security_timeout must be between 60 and 3600" + - port_security1_nm_error_max.msg == "The max_end_points must be between 0 and 12000" + + # QUERY + - name: Query a port security interface policy - normal mode + aci_interface_policy_port_security: + <<: *aci_info + port_security: security1 + state: query + register: port_security1_query + + - name: Query all port security interface policies - normal mode + aci_interface_policy_port_security: + <<: *aci_info + state: query + register: port_all_query + + - name: Verify query cases + assert: + that: + - port_security1_query is not changed + - port_all_query is not changed + - port_security1_query.current.0.l2PortSecurityPol.attributes.dn == "uni/infra/portsecurityP-security1" + - port_security1_query.current.0.l2PortSecurityPol.attributes.name == "security1" + - port_security1_query.current.0.l2PortSecurityPol.attributes.timeout == "190" + - port_security1_query.current.0.l2PortSecurityPol.attributes.maximum == "300" + - port_security1_query.current.0.l2PortSecurityPol.attributes.descr == "security 1" + - port_all_query.current|length >= 1 + + # REMOVE + - name: Remove a port security interface policy - normal mode + aci_interface_policy_port_security: + <<: *aci_info + port_security: security1 + state: absent + register: port_security1_remove + + - name: Verify remove cases + assert: + that: + - port_security1_remove is changed + - port_security1_remove.previous.0.l2PortSecurityPol.attributes.dn == "uni/infra/portsecurityP-security1" + - port_security1_remove.previous.0.l2PortSecurityPol.attributes.name == "security1" + - port_security1_remove.previous.0.l2PortSecurityPol.attributes.timeout == "190" + - port_security1_remove.previous.0.l2PortSecurityPol.attributes.maximum == "300" + - port_security1_remove.previous.0.l2PortSecurityPol.attributes.descr == "security 1" + + # CLEAN END + - name: Remove all policy port securities + aci_interface_policy_port_security: + <<: *aci_info + port_security: '{{ item }}' + state: absent + loop: + - security1 + - security2 + - security3
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_spanning_tree/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_spanning_tree/aliases new file mode 100644 index 000000000..cf765b70b --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_spanning_tree/aliases @@ -0,0 +1 @@ +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_spanning_tree/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_spanning_tree/tasks/main.yml new file mode 100644 index 000000000..3bb33d896 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_policy_spanning_tree/tasks/main.yml @@ -0,0 +1,162 @@ +# Test code for the ACI modules + +# Copyright: (c) 2023, Eric Girard <@netgirard> +# 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 execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # CLEAN ENVIRONMENT + - name: Remove policy spanning tree + aci_interface_policy_spanning_tree: + <<: *aci_info + stp_policy: "{{ item }}" + state: absent + loop: + - stp_bpduguard + - stp_bpdufilter + - stp_both + + # ADD + - name: Add a spanning tree interface policy BPDU Guard - check mode + aci_interface_policy_spanning_tree: + <<: *aci_info + stp_policy: stp_bpduguard + description: BPDU Guard + bpdu_guard: true + state: present + check_mode: true + register: stp_bpduguard_cm + + - name: Add a spanning tree interface policy BPDU Guard - normal mode + aci_interface_policy_spanning_tree: + <<: *aci_info + stp_policy: stp_bpduguard + description: BPDU Guard + bpdu_guard: true + state: present + register: stp_bpduguard_nm + + - name: Add a spanning tree interface policy BPDU Guard - normal mode again + aci_interface_policy_spanning_tree: + <<: *aci_info + stp_policy: stp_bpduguard + description: BPDU Guard + bpdu_guard: true + state: present + register: stp_bpduguard_nm_again + + - name: Add a spanning tree interface policy BPDU Filter - check mode + aci_interface_policy_spanning_tree: + <<: *aci_info + stp_policy: stp_bpdufilter + description: BPDU Filter + bpdu_filter: true + state: present + check_mode: true + register: stp_bpdufilter_cm + + - name: Add a spanning tree interface policy BPDU Filter - normal mode + aci_interface_policy_spanning_tree: + <<: *aci_info + stp_policy: stp_bpdufilter + description: BPDU Filter + bpdu_filter: true + state: present + register: stp_bpdufilter_nm + + - name: Add a spanning tree interface policy BPDU Filter - normal mode again + aci_interface_policy_spanning_tree: + <<: *aci_info + stp_policy: stp_bpdufilter + description: BPDU Filter + bpdu_filter: true + state: present + register: stp_bpdufilter_nm_again + + - name: Add a spanning tree interface policy Both - normal mode + aci_interface_policy_spanning_tree: + <<: *aci_info + stp_policy: stp_both + description: Both controls + bpdu_guard: true + bpdu_filter: true + state: present + register: stp_both_nm + + - name: Add a spanning tree interface policy Both - normal mode again + aci_interface_policy_spanning_tree: + <<: *aci_info + stp_policy: stp_both + description: Both controls + bpdu_guard: true + bpdu_filter: true + state: present + register: stp_both_nm_again + + - name: verify add tasks + assert: + that: + - stp_bpduguard_cm is changed + - stp_bpduguard_nm is changed + - stp_bpduguard_nm_again is not changed + - stp_bpdufilter_cm is changed + - stp_bpdufilter_nm is changed + - stp_bpdufilter_nm_again is not changed + - stp_both_nm is changed + - stp_both_nm_again is not changed + - stp_bpduguard_nm.current.0.stpIfPol.attributes.ctrl == 'bpdu-guard' + - stp_bpdufilter_nm.current.0.stpIfPol.attributes.ctrl == 'bpdu-filter' + - stp_both_nm.current.0.stpIfPol.attributes.ctrl == 'bpdu-filter,bpdu-guard' + + # QUERY + - name: Query a spanning tree interface policy + aci_interface_policy_spanning_tree: + <<: *aci_info + stp_policy: stp_both + state: query + register: stp_query_both + + - name: Query all spanning tree interface policies + aci_interface_policy_spanning_tree: + <<: *aci_info + state: query + register: stp_query_all + + - name: verify query tasks + assert: + that: + - stp_query_both is not changed + - stp_query_all is not changed + - stp_query_both.current.0.stpIfPol.attributes.ctrl == 'bpdu-filter,bpdu-guard' + - stp_query_all.current|length >= 3 + + # CLEAN ENVIRONMENT + - name: Remove policy port security + aci_interface_policy_spanning_tree: + <<: *aci_info + stp_policy: "{{ item }}" + state: absent + loop: + - stp_bpduguard + - stp_bpdufilter + - stp_both
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_selector_to_switch_policy_leaf_profile/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_selector_to_switch_policy_leaf_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_selector_to_switch_policy_leaf_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_interface_selector_to_switch_policy_leaf_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_selector_to_switch_policy_leaf_profile/tasks/main.yml new file mode 100644 index 000000000..099b2eed9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_interface_selector_to_switch_policy_leaf_profile/tasks/main.yml @@ -0,0 +1,181 @@ +# Test code for the ACI modules +# 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) + +- 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 + block: # block specifies execution of tasks within, based on conditions + - name: delete Switch Policy Leaf profile for kick off + cisco.aci.aci_switch_policy_leaf_profile: + 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") }}' + leaf_profile: swleafprftest + state: absent + + - name: delete Interface Policy Leaf profile for kick off + cisco.aci.aci_interface_policy_leaf_profile: + 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") }}' + leaf_interface_profile: leafintprftest + state: absent + + - name: Ensuring Switch Policy Leaf profile exists for kick off + cisco.aci.aci_switch_policy_leaf_profile: &aci_switch_policy_leaf_profile_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 + leaf_profile: swleafprftest + state: present + register: leaf_profile_present + + - name: Ensuring Interface Policy Leaf profile exists for kick off + cisco.aci.aci_interface_policy_leaf_profile: &aci_interface_policy_leaf_profile_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") }}' + leaf_interface_profile: leafintprftest + state: present + register: leaf_profile_present + + - name: Bind an Interface Selector to a Switch Policy Leaf Profile - check mode works + cisco.aci.aci_interface_selector_to_switch_policy_leaf_profile: &aci_interface_selector_to_switch_policy_leaf_profile_present + <<: *aci_switch_policy_leaf_profile_present + interface_selector: leafintprftest + check_mode: true + register: intftoleaf_check_mode_present + + - name: Bind an Interface Selector to a Switch Policy Leaf Profile - creation works + cisco.aci.aci_interface_selector_to_switch_policy_leaf_profile: + <<: *aci_interface_selector_to_switch_policy_leaf_profile_present + register: intftoleaf_present + + - name: Bind an Interface Selector to a Switch Policy Leaf Profile - idempotency works + cisco.aci.aci_interface_selector_to_switch_policy_leaf_profile: + <<: *aci_interface_selector_to_switch_policy_leaf_profile_present + register: intftoleaf_idempotent + + # TODO: also test for errors + - name: present assertions + assert: + that: + - intftoleaf_check_mode_present is changed + - intftoleaf_present is changed + - intftoleaf_present.previous == [] + - intftoleaf_present.sent.infraRsAccPortP.attributes.tDn == 'uni/infra/accportprof-leafintprftest' + - intftoleaf_present.current.0.infraRsAccPortP.attributes.annotation == 'orchestrator:ansible' + - intftoleaf_idempotent is not changed + - intftoleaf_idempotent.sent == {} + + - name: Query an interface selector profile associated with a switch policy leaf profile + cisco.aci.aci_interface_selector_to_switch_policy_leaf_profile: + <<: *aci_switch_policy_leaf_profile_present + interface_selector: leafintprftest + state: query + register: binding_query1 + + - name: query 1 assertions + assert: + that: + - binding_query1 is not changed + - binding_query1.current | length >= 1 + - '"api/mo/uni/infra/nprof-swleafprftest/rsaccPortP-[uni/infra/accportprof-leafintprftest].json" in binding_query1.url' + + - name: Query interface selector profile associations without specifying a switch policy leaf profile + cisco.aci.aci_interface_selector_to_switch_policy_leaf_profile: + 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 + interface_selector: leafintprftest + state: query + register: binding_query2 + + - name: query 2 assertions + assert: + that: + - binding_query2 is not changed + - binding_query2.current | length >= 1 + - binding_query2.filter_string == '?query-target-filter=eq(infraRsAccPortP.tDn,"uni/infra/accportprof-leafintprftest")' + + - name: Remove binding of interface access port selector and Interface Policy Leaf Profile - check mode + cisco.aci.aci_interface_selector_to_switch_policy_leaf_profile: &aci_interface_selector_to_switch_policy_leaf_profile_absent + <<: *aci_switch_policy_leaf_profile_present + interface_selector: leafintprftest + state: absent + check_mode: true + register: intftoleaf_check_mode_absent + + - name: Remove binding of interface access port selector and Interface Policy Leaf Profile - delete works + cisco.aci.aci_interface_selector_to_switch_policy_leaf_profile: + <<: *aci_interface_selector_to_switch_policy_leaf_profile_absent + register: intftoleaf_absent + + - name: Remove binding of interface access port selector and Interface Policy Leaf Profile - idempotency works + cisco.aci.aci_interface_selector_to_switch_policy_leaf_profile: + <<: *aci_interface_selector_to_switch_policy_leaf_profile_absent + register: intftoleaf_absent_idempotent + + - name: Remove binding of interface access port selector and Interface Policy Leaf Profile - check mode + cisco.aci.aci_interface_selector_to_switch_policy_leaf_profile: + <<: *aci_switch_policy_leaf_profile_present + state: absent + ignore_errors: true + register: intftoleaf_absent_missing_param + + - name: absent assertions + assert: + that: + - intftoleaf_check_mode_absent is changed + - intftoleaf_check_mode_absent.previous != [] + - intftoleaf_absent is changed + - intftoleaf_absent.previous == intftoleaf_check_mode_absent.previous + - intftoleaf_absent_idempotent is not changed + - intftoleaf_absent_idempotent.previous == [] + - intftoleaf_absent_missing_param is failed + - 'intftoleaf_absent_missing_param.msg == "state is absent but all of the following are missing: interface_selector"' + + - name: Remove an interface selector associated with a Switch Policy Leaf Profile - Clean up + cisco.aci.aci_interface_selector_to_switch_policy_leaf_profile: + <<: *aci_interface_selector_to_switch_policy_leaf_profile_absent + state: absent + + - name: delete Switch Policy Leaf profile - Clean up + cisco.aci.aci_switch_policy_leaf_profile: + <<: *aci_switch_policy_leaf_profile_present + state: absent + + - name: delete Interface Policy Leaf profile - Clean up + cisco.aci.aci_interface_policy_leaf_profile: + <<: *aci_interface_policy_leaf_profile_present + leaf_interface_profile: leafintprftest + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out/tasks/main.yml new file mode 100644 index 000000000..f72831322 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out/tasks/main.yml @@ -0,0 +1,136 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Shreyas Srish (@shrsr) + +# 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: Add a new L2Out + aci_l2out: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + description: Test deployment + bd: ansible_bd + domain: l2Dom + vlan: 3200 + state: present + register: add_l2out + + - name: Verify add_l2out + assert: + that: + - add_l2out.current.0.l2extOut.attributes.dn == "uni/tn-ansible_tenant/l2out-ansible_l2out" + - add_l2out.current.0.l2extOut.attributes.name == "ansible_l2out" + - add_l2out.current.0.l2extOut.attributes.annotation == 'orchestrator:ansible' + + - name: Add the L2Out again + aci_l2out: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + description: Test deployment + bd: ansible_bd + domain: l2Dom + vlan: 3200 + state: present + register: add_l2out_again + + - name: Verify add_l2out_again + assert: + that: + - add_l2out_again is not changed + + - name: Add a new L2Out + aci_l2out: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out_2 + description: Test deployment + bd: ansible_bd + domain: l2Dom + vlan: 3200 + state: present + register: add_l2out_2 + + - name: Verify add_l2out_2 + assert: + that: + - add_l2out_2.current.0.l2extOut.attributes.dn == "uni/tn-ansible_tenant/l2out-ansible_l2out_2" + - add_l2out_2.current.0.l2extOut.attributes.name == "ansible_l2out_2" + + - name: Query the L2Out + aci_l2out: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + state: query + register: query_l2out + + - name: Verify query_l2out + assert: + that: + - query_l2out is not changed + - query_l2out.current.0.l2extOut.attributes.dn == "uni/tn-ansible_tenant/l2out-ansible_l2out" + - query_l2out.current.0.l2extOut.attributes.name == "ansible_l2out" + + - name: Query all l2outs under a specific tenant + aci_l2out: + <<: *aci_info + tenant: ansible_tenant + state: query + register: query_l2out_all + + - name: Verify query_l2out_all + assert: + that: + - query_l2out_all is not changed + + - name: Remove the L2Out + aci_l2out: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + state: absent + register: remove_l2out + + - name: Verify remove_l2out + assert: + that: + - remove_l2out is changed + - remove_l2out.previous.0.l2extOut.attributes.dn == "uni/tn-ansible_tenant/l2out-ansible_l2out" + - remove_l2out.previous.0.l2extOut.attributes.name == "ansible_l2out"
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_extepg/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_extepg/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_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_l2out_extepg/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_extepg/tasks/main.yml new file mode 100644 index 000000000..39feb5216 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_extepg/tasks/main.yml @@ -0,0 +1,163 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Shreyas Srish (@shrsr) + +# 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: Add New L2Out + aci_l2out: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + description: Ansible Test + bd: ansible_bd + domain: l2Dom + vlan: 3200 + state: present + register: add_l2out + + - name: Add another L2Out + aci_l2out: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out_2 + description: Ansible Test + bd: ansible_bd + domain: l2Dom + vlan: 3200 + state: present + register: add_l2out_2 + + - name: Add L2 external end point group + aci_l2out_extepg: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + extepg: ansible_extepg + description: Ansible external epg + preferred_group: True + state: present + register: l2extepg + + - name: Verify l2extepg + assert: + that: + - l2extepg.current.0.l2extInstP.attributes.dn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_extepg" + - l2extepg.current.0.l2extInstP.attributes.annotation == 'orchestrator:ansible' + + - name: Add L2 external end point group again + aci_l2out_extepg: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + extepg: ansible_extepg + description: Ansible external epg + preferred_group: True + state: present + register: l2extepg_again + + - name: Verify l2extepg_again + assert: + that: + - l2extepg_again is not changed + - l2extepg.current.0.l2extInstP.attributes.dn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_extepg" + + - name: Add another L2 external end point group + aci_l2out_extepg: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out_2 + extepg: ansible_extepg_2 + description: Ansible external epg + qos_class: level1 + preferred_group: True + state: present + register: l2extepg_2 + + - name: Verify l2extepg_2 + assert: + that: + - l2extepg_2.current.0.l2extInstP.attributes.dn == "uni/tn-ansible_tenant/l2out-ansible_l2out_2/instP-ansible_extepg_2" + + - name: Query the L2 external end point group + aci_l2out_extepg: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + extepg: ansible_extepg + state: query + register: query_l2extepg + + - name: Query all L2 external epg in a tenant + aci_l2out_extepg: + <<: *aci_info + tenant: ansible_tenant + state: query + register: query_all_in_tenant + + - name: Verify query_all_in_tenant + assert: + that: + - query_all_in_tenant is not changed + + - name: Query all L2 external epgs + aci_l2out_extepg: + <<: *aci_info + state: query + register: query_all + + - name: Verify query_all + assert: + that: + - query_all is not changed + + - name: Remove L2 external end point group + aci_l2out_extepg: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + extepg: ansible_extepg + preferred_group: True + state: absent + register: remove_l2extepg + + - name: Verify remove_l2extepg + assert: + that: + - remove_l2extepg is changed + - remove_l2extepg.previous.0.l2extInstP.attributes.dn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_extepg"
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_extepg_to_contract/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_extepg_to_contract/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_extepg_to_contract/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_extepg_to_contract/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_extepg_to_contract/tasks/main.yml new file mode 100644 index 000000000..25c211f6b --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_extepg_to_contract/tasks/main.yml @@ -0,0 +1,218 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, Anvitha Jain (@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 + +# 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: Add New L2Out + aci_l2out: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + description: Ansible Test + bd: ansible_bd + domain: l2Dom + vlan: 3200 + state: present + register: add_l2out + + - name: Add another L2Out + aci_l2out: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out_2 + description: Ansible Test + bd: ansible_bd + domain: l2Dom + vlan: 3200 + state: present + register: add_l2out_2 + + - name: Add L2 external end point group + aci_l2out_extepg: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + extepg: ansible_extepg + description: Ansible external epg + preferred_group: True + state: present + register: l2extepg + + - name: Verify l2extepg + assert: + that: + - l2extepg is changed + - l2extepg.current.0.l2extInstP.attributes.dn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_extepg" + + - name: Add L2 external end point group again + aci_l2out_extepg: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + extepg: ansible_extepg + description: Ansible external epg + preferred_group: True + state: present + register: l2extepg_again + + - name: Verify l2extepg_again + assert: + that: + - l2extepg_again is not changed + - l2extepg.current.0.l2extInstP.attributes.dn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_extepg" + + - name: Add another L2 external end point group + aci_l2out_extepg: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out_2 + extepg: ansible_extepg_2 + description: Ansible external epg + qos_class: level1 + preferred_group: True + state: present + register: l2extepg_2 + + - name: Verify l2extepg_2 + assert: + that: + - l2extepg_2 is changed + - l2extepg_2.current.0.l2extInstP.attributes.dn == "uni/tn-ansible_tenant/l2out-ansible_l2out_2/instP-ansible_extepg_2" + + - name: Bind External End Point Groups to Contracts + aci_l2out_extepg_to_contract: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + extepg: ansible_extepg + contract: ansible_contract + contract_type: provider + state: present + register: bind_extepg_provider_contract + + - name: Verify bind_extepg_provider_contract + assert: + that: + - bind_extepg_provider_contract is changed + - bind_extepg_provider_contract.current.0.fvRsProv.attributes.dn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_extepg/rsprov-ansible_contract" + - bind_extepg_provider_contract.current.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' + + - name: Bind second External End Point Groups to Contracts + aci_l2out_extepg_to_contract: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out_2 + extepg: ansible_extepg_2 + contract: ansible_contract2 + contract_type: provider + state: present + register: bind_extepg_provider_contract + + - name: Verify bind_extepg_provider_contract + assert: + that: + - bind_extepg_provider_contract is changed + - bind_extepg_provider_contract.current.0.fvRsProv.attributes.dn == "uni/tn-ansible_tenant/l2out-ansible_l2out_2/instP-ansible_extepg_2/rsprov-ansible_contract2" + + - name: Query the External End Point Groups + aci_l2out_extepg_to_contract: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + extepg: ansible_extepg + contract: ansible_contract + contract_type: provider + state: query + register: query_extepg + + - name: Verify query_extepg + assert: + that: + - query_extepg is not changed + - query_extepg.current.0.fvRsProv.attributes.dn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_extepg/rsprov-ansible_contract" + + - name: Query all the External End Point Groups + aci_l2out_extepg_to_contract: + <<: *aci_info + contract_type: provider + state: query + register: query_all + + - name: Verify query_extepg + assert: + that: + - query_extepg is not changed + - query_extepg.current | length > 0 + + - name: Remove existing contract to External End Point Groups + aci_l2out_extepg_to_contract: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + extepg: ansible_extepg + contract: ansible_contract + contract_type: provider + state: absent + register: remove_contract_extepg + + - name: Verify remove_contract_extepg + assert: + that: + - remove_contract_extepg is changed + - remove_contract_extepg.current == [] + - remove_contract_extepg.previous.0.fvRsProv.attributes.dn == "uni/tn-ansible_tenant/l2out-ansible_l2out/instP-ansible_extepg/rsprov-ansible_contract" + + - name: Bind External End Point Groups to Contracts + aci_l2out_extepg_to_contract: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + extepg: ansible_extepg + contract: ansible_contract + contract_type: consumer + provider_match: all + state: present + ignore_errors: true + register: bind_extepg_consumer_contract + + - name: Verify bind_extepg_consumer_contract + assert: + that: + - bind_extepg_consumer_contract is not changed + - bind_extepg_consumer_contract.msg == "the 'provider_match' is only configurable for Provided Contracts"
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_logical_interface_path/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_logical_interface_path/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_logical_interface_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_l2out_logical_interface_path/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_logical_interface_path/tasks/main.yml new file mode 100644 index 000000000..a573668de --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_logical_interface_path/tasks/main.yml @@ -0,0 +1,202 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, Cindy Zhao (@cizhao) + +# 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: Remove test tenant before we kickoff + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + tenant: ansible_test + 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: 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: Create l2out + cisco.aci.aci_l2out: + <<: *aci_info + tenant: ansible_test + l2out: anstest + bd: anstest + domain: anstest + vlan: 3200 + + - name: Crete node profile + cisco.aci.aci_l2out_logical_node_profile: &np_present + <<: *aci_info + node_profile: anstest + l2out: anstest + tenant: ansible_test + state: present + + - name: Add interface profile + cisco.aci.aci_l2out_logical_interface_profile: &intf_present + <<: *np_present + interface_profile: INTFS + + - name: Add new path to interface profile (check_mode) + cisco.aci.aci_l2out_logical_interface_path: &path_present + <<: *aci_info + tenant: ansible_test + l2out: anstest + node_profile: anstest + interface_profile: INTFS + interface_type: vpc + pod_id: 1 + leaves: + - 101 + - 102 + interface: '1/7' + state: present + check_mode: true + register: cm_path_to_intfp + + - name: Add new path to interface profile (normal mode) + cisco.aci.aci_l2out_logical_interface_path: + <<: *path_present + register: nm_path_to_intfp + + - name: Verify path to interface profile + assert: + that: + - cm_path_to_intfp is changed + - nm_path_to_intfp is changed + - cm_path_to_intfp.previous == nm_path_to_intfp.previous == [] + - cm_path_to_intfp.proposed.l2extRsPathL2OutAtt.attributes.dn == 'uni/tn-ansible_test/l2out-anstest/lnodep-anstest/lifp-INTFS/rspathL2OutAtt-[topology/pod-1/protpaths-101-102/pathep-[1/7]]' + - nm_path_to_intfp.current.0.l2extRsPathL2OutAtt.attributes.dn == 'uni/tn-ansible_test/l2out-anstest/lnodep-anstest/lifp-INTFS/rspathL2OutAtt-[topology/pod-1/protpaths-101-102/pathep-[1/7]]' + - nm_path_to_intfp.current.0.l2extRsPathL2OutAtt.attributes.annotation == 'orchestrator:ansible' + + - name: Add another path to interface profile - interface type switch port + cisco.aci.aci_l2out_logical_interface_path: + <<: *path_present + interface_type: switch_port + leaves: 103 + interface: anstest + state: present + register: second_path + + - name: Add third path to interface profile - interface type port channel + cisco.aci.aci_l2out_logical_interface_path: + <<: *path_present + interface_type: port_channel + leaves: 104 + interface: anstest2 + state: present + register: third_path + + - name: Verify path to interface profile + assert: + that: + - second_path is changed + - third_path is changed + - second_path.previous == third_path.previous == [] + - second_path.current.0.l2extRsPathL2OutAtt.attributes.dn == 'uni/tn-ansible_test/l2out-anstest/lnodep-anstest/lifp-INTFS/rspathL2OutAtt-[topology/pod-1/paths-103/pathep-[ethanstest]]' + - third_path.current.0.l2extRsPathL2OutAtt.attributes.dn == 'uni/tn-ansible_test/l2out-anstest/lnodep-anstest/lifp-INTFS/rspathL2OutAtt-[topology/pod-1/paths-104/pathep-[anstest2]]' + + # Add path with incorrect parameter + - name: Use vpc interface with one leave + cisco.aci.aci_l2out_logical_interface_path: + <<: *path_present + interface_type: vpc + leaves: 105 + interface: test + state: present + ignore_errors: true + + - name: Use switch_port interface with two leaves + cisco.aci.aci_l2out_logical_interface_path: + <<: *path_present + interface_type: switch_port + leaves: + - 105 + - 106 + interface: test + state: present + ignore_errors: true + + - name: Use more than two leaves + cisco.aci.aci_l2out_logical_interface_path: + <<: *path_present + interface_type: switch_port + leaves: + - 105 + - 106 + - 107 + interface: test + state: present + ignore_errors: true + + - name: Query all + cisco.aci.aci_l2out_logical_interface_path: + <<: *np_present + interface_profile: INTFS + state: query + register: query_all + + - name: Query specific path + cisco.aci.aci_l2out_logical_interface_path: + <<: *path_present + state: query + register: query_path + + - name: Verify query + assert: + that: + - query_all is not changed + - query_all.current.0.l2extLIfP.children | length >= 3 + - query_path is not changed + - query_path.current.0.l2extRsPathL2OutAtt.attributes.dn == 'uni/tn-ansible_test/l2out-anstest/lnodep-anstest/lifp-INTFS/rspathL2OutAtt-[topology/pod-1/protpaths-101-102/pathep-[1/7]]' + + - name: Remove path from interface profile (check_mode) + cisco.aci.aci_l2out_logical_interface_path: &path_absent + <<: *path_present + state: absent + check_mode: true + register: cm_rm_path + + - name: Remove path from interface profile (normal mode) + cisco.aci.aci_l2out_logical_interface_path: + <<: *path_absent + register: nm_rm_path + + # Remove non_existing path + - name: Remove path again + cisco.aci.aci_l2out_logical_interface_path: + <<: *path_absent + register: rm_non_existing + + - name: Verify remove path + assert: + that: + - cm_rm_path is changed + - nm_rm_path is changed + - cm_rm_path.proposed == {} + - nm_rm_path.current == [] + - cm_rm_path.previous.0.l2extRsPathL2OutAtt.attributes.dn == nm_rm_path.previous.0.l2extRsPathL2OutAtt.attributes.dn == 'uni/tn-ansible_test/l2out-anstest/lnodep-anstest/lifp-INTFS/rspathL2OutAtt-[topology/pod-1/protpaths-101-102/pathep-[1/7]]' + - rm_non_existing is not changed
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_logical_interface_profile/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_logical_interface_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_logical_interface_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_l2out_logical_interface_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_logical_interface_profile/tasks/main.yml new file mode 100644 index 000000000..7e28c1cd4 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_logical_interface_profile/tasks/main.yml @@ -0,0 +1,160 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, Cindy Zhao (@cizhao) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# 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") }}' + +# CLEAN ENVIRONMENT +- name: Remove test tenant before we kickoff + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + tenant: ansible_test + 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 + # SETUP ENVIRONMENT + - name: Create tenant + cisco.aci.aci_tenant: &tenant_present + <<: *tenant_absent + state: present + + - name: Create l2out + cisco.aci.aci_l2out: + <<: *aci_info + tenant: ansible_test + l2out: l2outintftest + bd: l2outintftest + domain: l2outintftest + vlan: 3200 + + - name: Crete node profile + cisco.aci.aci_l2out_logical_node_profile: &np_present + <<: *aci_info + node_profile: l2outintftest + l2out: l2outintftest + tenant: ansible_test + state: present + + # BEGIN WITH TESTS (ADD PROFILE) + - name: Add interface profile (check_mode) + cisco.aci.aci_l2out_logical_interface_profile: &intf_present + <<: *np_present + interface_profile: INTFS + check_mode: true + register: cm_add_intf + + - name: Add interface profile (normal_mode) + cisco.aci.aci_l2out_logical_interface_profile: + <<: *intf_present + register: nm_add_intf + + - name: Verify nm_add_intf + assert: + that: + - cm_add_intf is changed + - nm_add_intf is changed + - cm_add_intf.previous == nm_add_intf.previous == [] + - cm_add_intf.sent.l2extLIfP.attributes.name == nm_add_intf.sent.l2extLIfP.attributes.name == 'INTFS' + - nm_add_intf.current.0.l2extLIfP.attributes.annotation == 'orchestrator:ansible' + + - name: Add profile again, check if idempotency works + cisco.aci.aci_l2out_logical_interface_profile: + <<: *intf_present + register: add_intf_again + + - name: Verify add_intf_again + assert: + that: + - add_intf_again is not changed + + # ADD ANOTHER PROFILE + - name: Add another profile + cisco.aci.aci_l2out_logical_interface_profile: + <<: *intf_present + interface_profile: INTF2 + + # QUERY ALL PROFILES + - name: Query all profiles + cisco.aci.aci_l2out_logical_interface_profile: + <<: *aci_info + state: query + l2out: l2outintftest + tenant: ansible_test + node_profile: l2outintftest + register: query_all_profiles + + - name: Verify query_all_profiles + assert: + that: + - query_all_profiles is not changed + - query_all_profiles.current.0.l2extLNodeP.children | length > 1 + + # QUERY A SPECIFIC PROFILE + - name: Query a specific profile + cisco.aci.aci_l2out_logical_interface_profile: + <<: *intf_present + state: query + register: query_spec_profile + + - name: Verify query_spec_profile + assert: + that: + - query_spec_profile is not changed + - query_spec_profile.current|length == 1 + - query_spec_profile.current.0.l2extLIfP.attributes.name == 'INTFS' + - query_spec_profile.current.0.l2extLIfP.attributes.dn == 'uni/tn-ansible_test/l2out-l2outintftest/lnodep-l2outintftest/lifp-INTFS' + + # QUERY A NON EXISTING PROFILE + - name: Query a nonexisting profile + cisco.aci.aci_l2out_logical_interface_profile: + <<: *np_present + interface_profile: nonexist + state: query + register: query_nonexist_profile + + - name: Verify query_nonexist_profile + assert: + that: + - query_nonexist_profile is not changed + - query_nonexist_profile.current == [] + + # REMOVE PROFILE + - name: Remove interface profile + cisco.aci.aci_l2out_logical_interface_profile: &intf_absent + <<: *intf_present + state: absent + register: remove_profile + + - name: Verify remove_profile + assert: + that: + - remove_profile is changed + - remove_profile.current == [] + + # REMOVE NONEXISTING PROFILE + - name: Remove interface profile again (nonexisting) + cisco.aci.aci_l2out_logical_interface_profile: + <<: *intf_absent + register: remove_nonexist_profile + + - name: Verify remove_nonexist_profile + assert: + that: + - remove_nonexist_profile is not changed + - remove_nonexist_profile.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_logical_node_profile/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_logical_node_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_logical_node_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_l2out_logical_node_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_logical_node_profile/tasks/main.yml new file mode 100644 index 000000000..82b4aaac5 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l2out_logical_node_profile/tasks/main.yml @@ -0,0 +1,190 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, Cindy Zhao (@cizhao) + +# 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_info + state: present + tenant: ansible_tenant + register: tenant_present + + - name: Create L2out for tests + cisco.aci.aci_l2out: + <<: *aci_info + state: present + tenant: ansible_tenant + l2out: ansible_l2out + bd: ansible_bd + domain: ansible_dom + vlan: 3200 + register: l2out_present + + - name: Add L2out node profile (check mode) + cisco.aci.aci_l2out_logical_node_profile: &aci_node_profile_present + <<: *aci_info + node_profile: ansible_node_profile + l2out: ansible_l2out + tenant: ansible_tenant + state: present + check_mode: true + register: cm_add_node_profile + + - name: Add L2out node profile (normal mode) + cisco.aci.aci_l2out_logical_node_profile: *aci_node_profile_present + register: nm_add_node_profile + + - name: Add another L2out node profile (normal mode) + cisco.aci.aci_l2out_logical_node_profile: + <<: *aci_info + node_profile: ansible_node_profile2 + l2out: ansible_l2out + tenant: ansible_tenant + state: present + register: nm_add_second_node_profile + + - name: Verify add_node_profile + assert: + that: + - cm_add_node_profile is changed + - nm_add_node_profile is changed + - nm_add_second_node_profile is changed + - cm_add_node_profile.sent.l2extLNodeP.attributes.name == nm_add_node_profile.sent.l2extLNodeP.attributes.name == 'ansible_node_profile' + - cm_add_node_profile.proposed.l2extLNodeP.attributes.name == nm_add_node_profile.proposed.l2extLNodeP.attributes.name == 'ansible_node_profile' + - cm_add_node_profile.current == cm_add_node_profile.previous == nm_add_node_profile.previous == [] + - nm_add_node_profile.current.0.l2extLNodeP.attributes.dn == 'uni/tn-ansible_tenant/l2out-ansible_l2out/lnodep-ansible_node_profile' + - nm_add_node_profile.current.0.l2extLNodeP.attributes.name == 'ansible_node_profile' + - nm_add_node_profile.current.0.l2extLNodeP.attributes.annotation == 'orchestrator:ansible' + - nm_add_second_node_profile.current.0.l2extLNodeP.attributes.dn == 'uni/tn-ansible_tenant/l2out-ansible_l2out/lnodep-ansible_node_profile2' + - nm_add_second_node_profile.current.0.l2extLNodeP.attributes.name == 'ansible_node_profile2' + + - name: Query existing node profile (check mode) + cisco.aci.aci_l2out_logical_node_profile: &query_existing_node_profile + <<: *aci_info + node_profile: ansible_node_profile + l2out: ansible_l2out + tenant: ansible_tenant + state: query + check_mode: true + register: cm_query_node_profile + + - name: Query existing node profile (normal mode) + cisco.aci.aci_l2out_logical_node_profile: *query_existing_node_profile + register: nm_query_node_profile + + - name: Query non-existent node profile + cisco.aci.aci_l2out_logical_node_profile: + <<: *aci_info + node_profile: ansible_fake_node_profile + l2out: ansible_l2out + tenant: ansible_tenant + state: query + check_mode: true + register: nm_query_fake_node_profile + + - name: Query all node profile for L2out + cisco.aci.aci_l2out_logical_node_profile: + <<: *aci_info + l2out: ansible_l2out + tenant: ansible_tenant + state: query + register: nm_query_all_node_profiles + + - name: Verify query_node_profile + assert: + that: + - cm_query_node_profile is not changed + - nm_query_node_profile is not changed + - nm_query_fake_node_profile is not changed + - nm_query_all_node_profiles is not changed + - cm_query_node_profile.current.0.l2extLNodeP.attributes.name == 'ansible_node_profile' + - nm_query_node_profile.current.0.l2extLNodeP.attributes.name == 'ansible_node_profile' + - nm_query_fake_node_profile.current == [] + - nm_query_all_node_profiles.current.0.l2extOut.children.0.l2extLNodeP.attributes.name == 'ansible_node_profile2' + - nm_query_all_node_profiles.current.0.l2extOut.children.1.l2extLNodeP.attributes.name == 'ansible_node_profile' + + - name: Remove node profile (check mode) + cisco.aci.aci_l2out_logical_node_profile: &aci_node_profile_absent + <<: *aci_info + node_profile: ansible_node_profile + l2out: ansible_l2out + tenant: ansible_tenant + state: absent + check_mode: true + register: cm_remove_node_profile + + - name: Remove node profile (normal mode) + cisco.aci.aci_l2out_logical_node_profile: *aci_node_profile_absent + register: nm_remove_node_profile + + - name: Remove node profile (normal mode) again + cisco.aci.aci_l2out_logical_node_profile: *aci_node_profile_absent + register: nm_remove_node_profile_again + + - name: Remove second node profile (check mode) + cisco.aci.aci_l2out_logical_node_profile: &aci_second_node_profile_absent + <<: *aci_info + node_profile: ansible_node_profile2 + l2out: ansible_l2out + tenant: ansible_tenant + state: absent + check_mode: true + register: cm_remove_second_node_profile + + - name: Remove second node profile (normal mode) + cisco.aci.aci_l2out_logical_node_profile: *aci_second_node_profile_absent + register: nm_remove_second_node_profile + + - name: Verify remove_node_profile + assert: + that: + - cm_remove_node_profile is changed + - cm_remove_second_node_profile is changed + - nm_remove_node_profile is changed + - nm_remove_node_profile_again is not changed + - nm_remove_second_node_profile is changed + + # Remove L2out after testing + - name: Remove L2out (normal_mode) + cisco.aci.aci_l2out: + <<: *aci_info + tenant: ansible_tenant + l2out: ansible_l2out + state: absent + + # Remove Tenant after testing + - name: Remove tenant (normal_mode) + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_tenant + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_bgp_peer/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_bgp_peer/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_bgp_peer/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_peer/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_bgp_peer/tasks/main.yml new file mode 100644 index 000000000..4e1784a6a --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_bgp_peer/tasks/main.yml @@ -0,0 +1,1516 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_tenant if it already exists + aci_tenant: + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Remove ansible_l3ext_domain if it already exists + aci_domain: + <<: *aci_info + domain: ansible_l3ext_domain + domain_type: l3dom + state: absent + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will skip execution for cloud sites + block: + - name: Remove ansible_port_channel_ipg if it already exists + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: link + policy_group: ansible_port_channel_ipg + state: absent + + - name: Remove ansible_vpc_ipg if it already exists + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: node + policy_group: ansible_vpc_ipg + state: absent + + - name: Add a new tenant required for l3out + aci_tenant: + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + # ADD domain + - name: Add domain for l3out + aci_domain: + <<: *aci_info + domain: ansible_l3ext_domain + domain_type: l3dom + state: present + + # ADD VRF + - name: Add VRF for l3out + aci_vrf: + <<: *aci_info + tenant: ansible_tenant + vrf: ansible_vrf + state: present + + # ADD PC IPG + - name: Add port-channel IPG + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: link + policy_group: ansible_port_channel_ipg + state: present + + # ADD vPC IPG + - name: Add vPC IPG + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: node + policy_group: ansible_vpc_ipg + state: present + + # ADD l3out + - name: Add l3out + aci_l3out: + <<: *aci_info + tenant: ansible_tenant + name: ansible_l3out + vrf: ansible_vrf + domain: ansible_domain + route_control: export + state: present + + # ADD l3out logical node profile + - name: l3out logical node profile + aci_l3out_logical_node_profile: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + state: present + + # ADD l3out logical interface profile + - name: l3out logical interface profile + aci_l3out_logical_interface_profile: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + state: present + + # ADD l3out interface + - name: Add routed interface + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + interface_type: l3-port + mode: regular + addr: 192.168.50.1/27 + state: present + + # ADD l3out port-channel + - name: Add routed interface port-channel + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + interface_type: l3-port + mode: regular + addr: 192.168.70.1/27 + state: present + + # ADD l3out vPC + - name: Add interface vPC + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + interface_type: ext-svi + mode: native + addr: 192.168.90.1/27 + encap: vlan-913 + state: present + + # ADD BGP peer to ethernet port + - name: add BGP peer to ethernet port (version >= 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + peer_ip: 192.168.50.2 + remote_asn: 65456 + bgp_controls: + - nh-self + - send-com + - send-ext-com + peer_controls: + - bfd + address_type_controls: + - af-ucast + ttl: 2 + state: present + register: add_eth_bgp_peer + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: add BGP peer to ethernet port (version < 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + peer_ip: 192.168.50.2 + remote_asn: 65456 + bgp_controls: + - nh-self + - send-com + - send-ext-com + peer_controls: + - bfd + ttl: 2 + state: present + register: add_eth_bgp_peer_32 + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify BGP peer has been created with correct attributes (version >= 4) + assert: + that: + - add_eth_bgp_peer.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]/peerP-[192.168.50.2]" + - add_eth_bgp_peer.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - add_eth_bgp_peer.current.0.bgpPeerP.attributes.addrTCtrl == "af-ucast" + - add_eth_bgp_peer.current.0.bgpPeerP.attributes.adminSt == "enabled" + - add_eth_bgp_peer.current.0.bgpPeerP.attributes.ctrl == "nh-self,send-com,send-ext-com" + - 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' + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify BGP peer has been created with correct attributes (version < 4) + assert: + that: + - add_eth_bgp_peer_32.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]/peerP-[192.168.50.2]" + - add_eth_bgp_peer_32.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - add_eth_bgp_peer_32.current.0.bgpPeerP.attributes.ctrl == "nh-self,send-com,send-ext-com" + - add_eth_bgp_peer_32.current.0.bgpPeerP.attributes.peerCtrl == "bfd" + - add_eth_bgp_peer_32.current.0.bgpPeerP.attributes.ttl == "2" + - add_eth_bgp_peer_32.current.0.bgpPeerP.attributes.annotation == 'orchestrator:ansible' + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify remote AS object has been created correctly + assert: + that: + - add_eth_bgp_peer.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65456" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify remote AS object has been created correctly + assert: + that: + - add_eth_bgp_peer_32.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65456" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + # ADD BGP peer again to check idempotence + - name: add BGP peer to ethernet port again (version >= 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + peer_ip: 192.168.50.2 + remote_asn: 65456 + bgp_controls: + - nh-self + - send-com + - send-ext-com + peer_controls: + - bfd + address_type_controls: + - af-ucast + ttl: 2 + state: present + register: add_eth_bgp_peer_again + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: add BGP peer to ethernet port again (version < 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + peer_ip: 192.168.50.2 + remote_asn: 65456 + bgp_controls: + - nh-self + - send-com + - send-ext-com + peer_controls: + - bfd + ttl: 2 + state: present + register: add_eth_bgp_peer_again_32 + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify BGP peer has been created with correct attributes (version >= 4) + assert: + that: + - add_eth_bgp_peer_again is not changed + - add_eth_bgp_peer_again.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]/peerP-[192.168.50.2]" + - add_eth_bgp_peer_again.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - add_eth_bgp_peer_again.current.0.bgpPeerP.attributes.addrTCtrl == "af-ucast" + - add_eth_bgp_peer_again.current.0.bgpPeerP.attributes.adminSt == "enabled" + - add_eth_bgp_peer_again.current.0.bgpPeerP.attributes.ctrl == "nh-self,send-com,send-ext-com" + - add_eth_bgp_peer_again.current.0.bgpPeerP.attributes.peerCtrl == "bfd" + - add_eth_bgp_peer_again.current.0.bgpPeerP.attributes.ttl == "2" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify BGP peer has been created with correct attributes (version < 4) + assert: + that: + - add_eth_bgp_peer_again_32 is not changed + - add_eth_bgp_peer_again_32.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]/peerP-[192.168.50.2]" + - add_eth_bgp_peer_again_32.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - add_eth_bgp_peer_again_32.current.0.bgpPeerP.attributes.ctrl == "nh-self,send-com,send-ext-com" + - add_eth_bgp_peer_again_32.current.0.bgpPeerP.attributes.peerCtrl == "bfd" + - add_eth_bgp_peer_again_32.current.0.bgpPeerP.attributes.ttl == "2" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - 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" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify remote AS object his still correct (version < 4) + assert: + that: + - add_eth_bgp_peer_again_32.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65456" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + # MODIFY BGP peer + - name: update BGP peer (version >= 4) + aci_l3out_bgp_peer: &interface_profile_bgp_peer_present + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + peer_ip: 192.168.50.2 + remote_asn: 65457 + bgp_controls: + - allow-self-as + - as-override + peer_controls: + - dis-conn-check + private_asn_controls: + - remove-exclusive + address_type_controls: + - af-ucast + - af-mcast + weight: 50 + allow_self_as_count: 3 + ttl: 4 + admin_state: disabled + state: present + register: update_eth_bgp_peer + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: update BGP peer (version < 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + peer_ip: 192.168.50.2 + remote_asn: 65457 + bgp_controls: + - allow-self-as + - as-override + peer_controls: + - dis-conn-check + private_asn_controls: + - remove-exclusive + weight: 50 + allow_self_as_count: 3 + ttl: 4 + state: present + register: update_eth_bgp_peer_32 + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify BGP peer has been updated with correct attributes (version >= 4) + assert: + that: + - update_eth_bgp_peer is changed + - update_eth_bgp_peer.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]/peerP-[192.168.50.2]" + - update_eth_bgp_peer.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - update_eth_bgp_peer.current.0.bgpPeerP.attributes.addrTCtrl == "af-mcast,af-ucast" + - update_eth_bgp_peer.current.0.bgpPeerP.attributes.adminSt == "disabled" + - update_eth_bgp_peer.current.0.bgpPeerP.attributes.ctrl == "allow-self-as,as-override" + - update_eth_bgp_peer.current.0.bgpPeerP.attributes.peerCtrl == "dis-conn-check" + - 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" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify BGP peer has been updated with correct attributes (version < 4) + assert: + that: + - update_eth_bgp_peer_32 is changed + - update_eth_bgp_peer_32.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]/peerP-[192.168.50.2]" + - update_eth_bgp_peer_32.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - update_eth_bgp_peer_32.current.0.bgpPeerP.attributes.ctrl == "allow-self-as,as-override" + - update_eth_bgp_peer_32.current.0.bgpPeerP.attributes.peerCtrl == "dis-conn-check" + - update_eth_bgp_peer_32.current.0.bgpPeerP.attributes.ttl == "4" + - update_eth_bgp_peer_32.current.0.bgpPeerP.attributes.allowedSelfAsCnt == "3" + - update_eth_bgp_peer_32.current.0.bgpPeerP.attributes.privateASctrl == "remove-exclusive" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - 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" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify remote AS object has been updated correctly (version < 4) + assert: + that: + - update_eth_bgp_peer_32.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65457" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + # QUERY BGP peer + - name: query BGP peer (version >= 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + peer_ip: 192.168.50.2 + state: query + register: query_eth_bgp_peer + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: query BGP peer (version < 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + peer_ip: 192.168.50.2 + state: query + register: query_eth_bgp_peer_32 + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify BGP peer attributes (version >= 4) + assert: + that: + - query_eth_bgp_peer is not changed + - query_eth_bgp_peer.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]/peerP-[192.168.50.2]" + - query_eth_bgp_peer.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - query_eth_bgp_peer.current.0.bgpPeerP.attributes.addrTCtrl == "af-mcast,af-ucast" + - query_eth_bgp_peer.current.0.bgpPeerP.attributes.adminSt == "disabled" + - query_eth_bgp_peer.current.0.bgpPeerP.attributes.ctrl == "allow-self-as,as-override" + - query_eth_bgp_peer.current.0.bgpPeerP.attributes.peerCtrl == "dis-conn-check" + - query_eth_bgp_peer.current.0.bgpPeerP.attributes.ttl == "4" + - query_eth_bgp_peer.current.0.bgpPeerP.attributes.allowedSelfAsCnt == "3" + - query_eth_bgp_peer.current.0.bgpPeerP.attributes.privateASctrl == "remove-exclusive" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify BGP peer attributes (version < 4) + assert: + that: + - query_eth_bgp_peer_32 is not changed + - query_eth_bgp_peer_32.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]/peerP-[192.168.50.2]" + - query_eth_bgp_peer_32.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - query_eth_bgp_peer_32.current.0.bgpPeerP.attributes.ctrl == "allow-self-as,as-override" + - query_eth_bgp_peer_32.current.0.bgpPeerP.attributes.peerCtrl == "dis-conn-check" + - query_eth_bgp_peer_32.current.0.bgpPeerP.attributes.ttl == "4" + - query_eth_bgp_peer_32.current.0.bgpPeerP.attributes.allowedSelfAsCnt == "3" + - query_eth_bgp_peer_32.current.0.bgpPeerP.attributes.privateASctrl == "remove-exclusive" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify BGP remote AS (version >= 4) + assert: + that: + - query_eth_bgp_peer.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65457" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify BGP remote AS (version < 4) + assert: + that: + - query_eth_bgp_peer_32.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65457" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: Execute tasks only for the APIC version version >= 4 + when: version.current.0.topSystem.attributes.version is version('4', '>=') + block: + # Route Control Profile validation check for Interface Profile level + - name: Add Route Control Profile to the ansible_interface_profile (version >= 4) - check mode + aci_l3out_bgp_peer: + <<: *interface_profile_bgp_peer_present + route_control_profiles: + - tenant: "ansible_tenant" + profile: "anstest_import" + direction: "import" + - tenant: "ansible_tenant" + profile: "anstest_export" + direction: "export" + l3out: "anstest_l3out" + state: present + check_mode: true + register: cm_if_rtctrl_present + + - name: Assertions check for add Route Control Profile to the ansible_interface_profile (version >= 4) - check mode + assert: + that: + - cm_if_rtctrl_present is changed + - cm_if_rtctrl_present.sent.bgpPeerP.children | length == 2 + + - name: Add Route Control Profile to the ansible_interface_profile (version >= 4) - normal mode - missing param + aci_l3out_bgp_peer: + <<: *interface_profile_bgp_peer_present + route_control_profiles: + - tenant: "ansible_tenant" + profile: "anstest_import" + - tenant: "ansible_tenant" + profile: "anstest_export" + direction: "export" + l3out: "anstest_l3out" + state: present + register: nm_if_rtctrl_present_missing_param + ignore_errors: true + + - name: Assertions check for add Route Control Profile to the ansible_interface_profile (version >= 4) - normal mode - missing param + assert: + that: + - nm_if_rtctrl_present_missing_param is failed + - "nm_if_rtctrl_present_missing_param.msg == 'missing required arguments: direction found in route_control_profiles'" + + - name: Add Route Control Profile to the ansible_interface_profile (version >= 4) - normal mode + aci_l3out_bgp_peer: &nm_if_rtctrl_present + <<: *interface_profile_bgp_peer_present + route_control_profiles: + - tenant: "ansible_tenant" + profile: "anstest_import" + direction: "import" + - tenant: "ansible_tenant" + profile: "anstest_export" + direction: "export" + l3out: "anstest_l3out" + state: present + register: nm_if_rtctrl_present + + - name: Assertions check for add Route Control Profile to the ansible_interface_profile (version >= 4) - normal mode + assert: + that: + - nm_if_rtctrl_present is changed + - nm_if_rtctrl_present.current | length == 1 + - nm_if_rtctrl_present.previous | length == 1 + - nm_if_rtctrl_present.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - nm_if_rtctrl_present.previous.0.bgpPeerP.attributes.addr == "192.168.50.2" + - nm_if_rtctrl_present.current.0.bgpPeerP.children | length >= nm_if_rtctrl_present.previous.0.bgpPeerP.children | length + + - name: Add Route Control Profile to the ansible_interface_profile (version >= 4) - normal mode - idempotency works + aci_l3out_bgp_peer: + <<: *nm_if_rtctrl_present + state: present + register: idempotency_nm_if_rtctrl_present + + - name: Idempotency assertions check for add Route Control Profile to the ansible_interface_profile (version >= 4) - normal mode + assert: + that: + - idempotency_nm_if_rtctrl_present is not changed + - idempotency_nm_if_rtctrl_present.current | length == 1 + - idempotency_nm_if_rtctrl_present.previous | length == 1 + - idempotency_nm_if_rtctrl_present.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - idempotency_nm_if_rtctrl_present.previous.0.bgpPeerP.attributes.addr == "192.168.50.2" + - idempotency_nm_if_rtctrl_present.current.0.bgpPeerP.children | length >= 2 + - idempotency_nm_if_rtctrl_present.previous.0.bgpPeerP.children | length >= 2 + + - name: Query a BGP Peer with Interface Profile + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + peer_ip: 192.168.50.2 + state: query + register: query_if_bgp_peer + + - name: Assertions check for query a BGP Peer with Interface Profile + assert: + that: + - query_if_bgp_peer is not changed + - query_if_bgp_peer.current | length == 1 + - query_if_bgp_peer.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - query_if_bgp_peer.current.0.bgpPeerP.children | length >= 2 + + # Route Control Profile validation check for Node Profile level + - name: Add BGP Peer to the Node Profile level (version >= 4) - check mode + aci_l3out_bgp_peer: &cm_ln_rtctrl_present + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + peer_ip: 192.168.50.3 + route_control_profiles: + - tenant: "ansible_tenant" + profile: "anstest_import" + direction: "import" + - tenant: "ansible_tenant" + profile: "anstest_export" + direction: "export" + l3out: "anstest_l3out" + state: present + check_mode: true + register: cm_ln_rtctrl_present + + - name: Assertions check for add BGP Peer to the Node Profile level (version >= 4) - check mode + assert: + that: + - cm_ln_rtctrl_present is changed + - cm_ln_rtctrl_present.current | length == 0 + - cm_ln_rtctrl_present.previous | length == 0 + - cm_ln_rtctrl_present.sent.bgpPeerP.attributes.addr == "192.168.50.3" + - cm_ln_rtctrl_present.sent.bgpPeerP.children | length >= 2 + + - name: Add BGP Peer to the Node Profile level (version >= 4) - normal mode + aci_l3out_bgp_peer: + <<: *cm_ln_rtctrl_present + state: present + register: nm_ln_rtctrl_present + + - name: Assertions check for add BGP Peer to the Node Profile level (version >= 4) - normal mode + assert: + that: + - nm_ln_rtctrl_present is changed + - nm_ln_rtctrl_present.current | length == 1 + - 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 + + - name: Add BGP Peer to the Node Profile level (version >= 4) - normal mode - idempotency works + aci_l3out_bgp_peer: + <<: *cm_ln_rtctrl_present + state: present + register: idempotency_nm_ln_rtctrl_present + + - name: Idempotency assertions check for add BGP Peer to the Node Profile level (version >= 4) - normal mode + assert: + that: + - idempotency_nm_ln_rtctrl_present is not changed + - idempotency_nm_ln_rtctrl_present.current | length == 1 + - idempotency_nm_ln_rtctrl_present.current.0.bgpPeerP.attributes.addr == "192.168.50.3" + - idempotency_nm_ln_rtctrl_present.current.0.bgpPeerP.children | length >= 2 + - idempotency_nm_ln_rtctrl_present.previous | length == 1 + - idempotency_nm_ln_rtctrl_present.previous.0.bgpPeerP.attributes.addr == "192.168.50.3" + + - name: Add BGP Peer to the Node Profile level (version >= 4) - normal mode - missing param + aci_l3out_bgp_peer: + <<: *cm_ln_rtctrl_present + route_control_profiles: + - tenant: "ansible_tenant" + profile: "anstest_import" + - tenant: "ansible_tenant" + profile: "anstest_export" + direction: "export" + l3out: "anstest_l3out" + state: present + register: nm_ln_rtctrl_present_missing_param + ignore_errors: true + + - name: Assertions check for add BGP Peer to the Node Profile level (version >= 4) - normal mode - missing param + assert: + that: + - nm_ln_rtctrl_present_missing_param is failed + - "nm_ln_rtctrl_present_missing_param.msg == 'missing required arguments: direction found in route_control_profiles'" + + - name: Query a BGP Peer from the Node Profile level + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + peer_ip: 192.168.50.3 + state: query + register: query_ln_bgp_peer + + - name: Assertions check for query a BGP Peer from the Node Profile level + assert: + that: + - query_ln_bgp_peer is not changed + - query_ln_bgp_peer.current | length == 1 + - query_ln_bgp_peer.current.0.bgpPeerP.attributes.addr == "192.168.50.3" + + - name: Query all BGP peers + aci_l3out_bgp_peer: + <<: *aci_info + state: query + register: query_all_bgp_peer + + - name: Assertions check for query all BGP peers + assert: + that: + - query_all_bgp_peer is not changed + - query_all_bgp_peer.current | length != 0 + + # DELETE BGP peer + - name: delete BGP peer + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + peer_ip: 192.168.50.2 + state: absent + register: remove_eth_bgp_peer + + - name: verify remove_eth_bgp_peer + assert: + that: + - remove_eth_bgp_peer is changed + - remove_eth_bgp_peer.current == [] + - remove_eth_bgp_peer.previous.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]/peerP-[192.168.50.2]" + - remove_eth_bgp_peer.previous.0.bgpPeerP.attributes.addr == "192.168.50.2" + + # ADD BGP peer to port-channel + - name: add BGP peer to port-channel (version >= 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + peer_ip: 192.168.50.2 + remote_asn: 65456 + bgp_controls: + - nh-self + - send-com + - send-ext-com + peer_controls: + - bfd + address_type_controls: + - af-ucast + ttl: 2 + state: present + register: add_pc_bgp_peer + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: add BGP peer to port-channel (version < 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + peer_ip: 192.168.50.2 + remote_asn: 65456 + bgp_controls: + - nh-self + - send-com + - send-ext-com + peer_controls: + - bfd + ttl: 2 + state: present + register: add_pc_bgp_peer_32 + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify BGP peer has been created with correct attributes (version >= 4) + assert: + that: + - add_pc_bgp_peer.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]/peerP-[192.168.50.2]" + - add_pc_bgp_peer.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - add_pc_bgp_peer.current.0.bgpPeerP.attributes.addrTCtrl == "af-ucast" + - add_pc_bgp_peer.current.0.bgpPeerP.attributes.adminSt == "enabled" + - add_pc_bgp_peer.current.0.bgpPeerP.attributes.ctrl == "nh-self,send-com,send-ext-com" + - add_pc_bgp_peer.current.0.bgpPeerP.attributes.peerCtrl == "bfd" + - add_pc_bgp_peer.current.0.bgpPeerP.attributes.ttl == "2" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify BGP peer has been created with correct attributes (version < 4) + assert: + that: + - add_pc_bgp_peer_32.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]/peerP-[192.168.50.2]" + - add_pc_bgp_peer_32.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - add_pc_bgp_peer_32.current.0.bgpPeerP.attributes.ctrl == "nh-self,send-com,send-ext-com" + - add_pc_bgp_peer_32.current.0.bgpPeerP.attributes.peerCtrl == "bfd" + - add_pc_bgp_peer_32.current.0.bgpPeerP.attributes.ttl == "2" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify remote AS object has been created correctly (version >= 4) + assert: + that: + - add_pc_bgp_peer.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65456" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify remote AS object has been created correctly (version < 4) + assert: + that: + - add_pc_bgp_peer_32.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65456" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + # ADD BGP peer again to check idempotence + - name: add BGP peer to port-channel again (version >= 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + peer_ip: 192.168.50.2 + remote_asn: 65456 + bgp_controls: + - nh-self + - send-com + - send-ext-com + peer_controls: + - bfd + address_type_controls: + - af-ucast + ttl: 2 + state: present + register: add_pc_bgp_peer_again + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: add BGP peer to port-channel again (version < 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + peer_ip: 192.168.50.2 + remote_asn: 65456 + bgp_controls: + - nh-self + - send-com + - send-ext-com + peer_controls: + - bfd + ttl: 2 + state: present + register: add_pc_bgp_peer_again_32 + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify BGP peer has been created with correct attributes (version >= 4) + assert: + that: + - add_pc_bgp_peer_again is not changed + - add_pc_bgp_peer_again.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]/peerP-[192.168.50.2]" + - add_pc_bgp_peer_again.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - add_pc_bgp_peer_again.current.0.bgpPeerP.attributes.addrTCtrl == "af-ucast" + - add_pc_bgp_peer_again.current.0.bgpPeerP.attributes.adminSt == "enabled" + - add_pc_bgp_peer_again.current.0.bgpPeerP.attributes.ctrl == "nh-self,send-com,send-ext-com" + - add_pc_bgp_peer_again.current.0.bgpPeerP.attributes.peerCtrl == "bfd" + - add_pc_bgp_peer_again.current.0.bgpPeerP.attributes.ttl == "2" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify BGP peer has been created with correct attributes (version < 4) + assert: + that: + - add_pc_bgp_peer_again_32 is not changed + - add_pc_bgp_peer_again_32.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]/peerP-[192.168.50.2]" + - add_pc_bgp_peer_again_32.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - add_pc_bgp_peer_again_32.current.0.bgpPeerP.attributes.ctrl == "nh-self,send-com,send-ext-com" + - add_pc_bgp_peer_again_32.current.0.bgpPeerP.attributes.peerCtrl == "bfd" + - add_pc_bgp_peer_again_32.current.0.bgpPeerP.attributes.ttl == "2" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify remote AS object has been created correctly (version >= 4) + assert: + that: + - add_pc_bgp_peer_again.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65456" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify remote AS object has been created correctly (version < 4) + assert: + that: + - add_pc_bgp_peer_again_32.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65456" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + # MODIFY BGP peer + - name: update BGP peer (version >= 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + peer_ip: 192.168.50.2 + remote_asn: 65457 + bgp_controls: + - allow-self-as + - as-override + peer_controls: + - bfd + - dis-conn-check + private_asn_controls: + - remove-all + - remove-exclusive + - replace-as + address_type_controls: + - af-ucast + - af-mcast + weight: 50 + allow_self_as_count: 3 + ttl: 4 + admin_state: disabled + state: present + register: update_pc_bgp_peer + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: update BGP peer (version < 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + peer_ip: 192.168.50.2 + remote_asn: 65457 + bgp_controls: + - allow-self-as + - as-override + peer_controls: + - bfd + - dis-conn-check + private_asn_controls: + - remove-all + - remove-exclusive + - replace-as + weight: 50 + allow_self_as_count: 3 + ttl: 4 + state: present + register: update_pc_bgp_peer_32 + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify BGP peer has been updated with correct attributes (version >= 4) + assert: + that: + - update_pc_bgp_peer is changed + - update_pc_bgp_peer.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]/peerP-[192.168.50.2]" + - update_pc_bgp_peer.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - update_pc_bgp_peer.current.0.bgpPeerP.attributes.addrTCtrl == "af-mcast,af-ucast" + - update_pc_bgp_peer.current.0.bgpPeerP.attributes.adminSt == "disabled" + - update_pc_bgp_peer.current.0.bgpPeerP.attributes.ctrl == "allow-self-as,as-override" + - update_pc_bgp_peer.current.0.bgpPeerP.attributes.peerCtrl == "bfd,dis-conn-check" + - update_pc_bgp_peer.current.0.bgpPeerP.attributes.ttl == "4" + - update_pc_bgp_peer.current.0.bgpPeerP.attributes.allowedSelfAsCnt == "3" + - update_pc_bgp_peer.current.0.bgpPeerP.attributes.privateASctrl == "remove-all,remove-exclusive,replace-as" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify BGP peer has been updated with correct attributes (version < 4) + assert: + that: + - update_pc_bgp_peer_32 is changed + - update_pc_bgp_peer_32.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]/peerP-[192.168.50.2]" + - update_pc_bgp_peer_32.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - update_pc_bgp_peer_32.current.0.bgpPeerP.attributes.ctrl == "allow-self-as,as-override" + - update_pc_bgp_peer_32.current.0.bgpPeerP.attributes.peerCtrl == "bfd,dis-conn-check" + - update_pc_bgp_peer_32.current.0.bgpPeerP.attributes.ttl == "4" + - update_pc_bgp_peer_32.current.0.bgpPeerP.attributes.allowedSelfAsCnt == "3" + - update_pc_bgp_peer_32.current.0.bgpPeerP.attributes.privateASctrl == "remove-all,remove-exclusive,replace-as" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify remote AS object has been created correctly (version >= 4) + assert: + that: + - update_pc_bgp_peer.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65457" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify remote AS object has been created correctly (version < 4) + assert: + that: + - update_pc_bgp_peer_32.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65457" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + # QUERY BGP peer + - name: query BGP peer (version >= 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + peer_ip: 192.168.50.2 + state: query + register: query_pc_bgp_peer + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: query BGP peer (version < 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + peer_ip: 192.168.50.2 + state: query + register: query_pc_bgp_peer_32 + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify BGP peer attributes (version >= 4) + assert: + that: + - query_pc_bgp_peer is not changed + - query_pc_bgp_peer.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]/peerP-[192.168.50.2]" + - query_pc_bgp_peer.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - query_pc_bgp_peer.current.0.bgpPeerP.attributes.addrTCtrl == "af-mcast,af-ucast" + - query_pc_bgp_peer.current.0.bgpPeerP.attributes.adminSt == "disabled" + - query_pc_bgp_peer.current.0.bgpPeerP.attributes.ctrl == "allow-self-as,as-override" + - query_pc_bgp_peer.current.0.bgpPeerP.attributes.peerCtrl == "bfd,dis-conn-check" + - query_pc_bgp_peer.current.0.bgpPeerP.attributes.ttl == "4" + - query_pc_bgp_peer.current.0.bgpPeerP.attributes.allowedSelfAsCnt == "3" + - query_pc_bgp_peer.current.0.bgpPeerP.attributes.privateASctrl == "remove-all,remove-exclusive,replace-as" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify BGP peer attributes (version < 4) + assert: + that: + - query_pc_bgp_peer_32 is not changed + - query_pc_bgp_peer_32.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]/peerP-[192.168.50.2]" + - query_pc_bgp_peer_32.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - query_pc_bgp_peer_32.current.0.bgpPeerP.attributes.ctrl == "allow-self-as,as-override" + - query_pc_bgp_peer_32.current.0.bgpPeerP.attributes.peerCtrl == "bfd,dis-conn-check" + - query_pc_bgp_peer_32.current.0.bgpPeerP.attributes.ttl == "4" + - query_pc_bgp_peer_32.current.0.bgpPeerP.attributes.allowedSelfAsCnt == "3" + - query_pc_bgp_peer_32.current.0.bgpPeerP.attributes.privateASctrl == "remove-all,remove-exclusive,replace-as" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify BGP remote AS (version >= 4) + assert: + that: + - query_pc_bgp_peer.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65457" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify BGP remote AS (version < 4) + assert: + that: + - query_pc_bgp_peer_32.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65457" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + # DELETE BGP peer + - name: delete BGP peer + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + peer_ip: 192.168.50.2 + state: absent + register: remove_pc_bgp_peer + + - name: verify remove_pc_bgp_peer + assert: + that: + - remove_pc_bgp_peer is changed + - remove_pc_bgp_peer.current == [] + - remove_pc_bgp_peer.previous.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]/peerP-[192.168.50.2]" + - remove_pc_bgp_peer.previous.0.bgpPeerP.attributes.addr == "192.168.50.2" + + # ADD BGP peer to vPC + - name: add BGP peer to vPC (version >= 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + peer_ip: 192.168.50.2 + remote_asn: 65456 + bgp_controls: + - nh-self + - send-com + - send-ext-com + peer_controls: + - bfd + address_type_controls: + - af-ucast + ttl: 2 + state: present + register: add_vpc_bgp_peer + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: add BGP peer to vPC (version < 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + peer_ip: 192.168.50.2 + remote_asn: 65456 + bgp_controls: + - nh-self + - send-com + - send-ext-com + peer_controls: + - bfd + ttl: 2 + state: present + register: add_vpc_bgp_peer_32 + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify BGP peer has been created with correct attributes (version >= 4) + assert: + that: + - add_vpc_bgp_peer.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/protpaths-201-202/pathep-[ansible_vpc_ipg]]/peerP-[192.168.50.2]" + - add_vpc_bgp_peer.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - add_vpc_bgp_peer.current.0.bgpPeerP.attributes.addrTCtrl == "af-ucast" + - add_vpc_bgp_peer.current.0.bgpPeerP.attributes.adminSt == "enabled" + - add_vpc_bgp_peer.current.0.bgpPeerP.attributes.ctrl == "nh-self,send-com,send-ext-com" + - add_vpc_bgp_peer.current.0.bgpPeerP.attributes.peerCtrl == "bfd" + - add_vpc_bgp_peer.current.0.bgpPeerP.attributes.ttl == "2" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify BGP peer has been created with correct attributes (version < 4) + assert: + that: + - add_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/protpaths-201-202/pathep-[ansible_vpc_ipg]]/peerP-[192.168.50.2]" + - add_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - add_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.ctrl == "nh-self,send-com,send-ext-com" + - add_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.peerCtrl == "bfd" + - add_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.ttl == "2" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify remote AS object has been created correctly (version >= 4) + assert: + that: + - add_vpc_bgp_peer.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65456" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify remote AS object has been created correctly (version < 4) + assert: + that: + - add_vpc_bgp_peer_32.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65456" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + # ADD BGP peer again to check idempotence + - name: add BGP peer to vPC again (version >= 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + peer_ip: 192.168.50.2 + remote_asn: 65456 + bgp_controls: + - nh-self + - send-com + - send-ext-com + peer_controls: + - bfd + address_type_controls: + - af-ucast + ttl: 2 + state: present + register: add_vpc_bgp_peer_again + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: add BGP peer to vPC again (version < 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + peer_ip: 192.168.50.2 + remote_asn: 65456 + bgp_controls: + - nh-self + - send-com + - send-ext-com + peer_controls: + - bfd + ttl: 2 + state: present + register: add_vpc_bgp_peer_again_32 + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify BGP peer has been created with correct attributes (version >= 4) + assert: + that: + - add_vpc_bgp_peer_again is not changed + - add_vpc_bgp_peer_again.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/protpaths-201-202/pathep-[ansible_vpc_ipg]]/peerP-[192.168.50.2]" + - add_vpc_bgp_peer_again.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - add_vpc_bgp_peer_again.current.0.bgpPeerP.attributes.addrTCtrl == "af-ucast" + - add_vpc_bgp_peer_again.current.0.bgpPeerP.attributes.adminSt == "enabled" + - add_vpc_bgp_peer_again.current.0.bgpPeerP.attributes.ctrl == "nh-self,send-com,send-ext-com" + - add_vpc_bgp_peer_again.current.0.bgpPeerP.attributes.peerCtrl == "bfd" + - add_vpc_bgp_peer_again.current.0.bgpPeerP.attributes.ttl == "2" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify BGP peer has been created with correct attributes (version < 4) + assert: + that: + - add_vpc_bgp_peer_again_32 is not changed + - add_vpc_bgp_peer_again_32.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/protpaths-201-202/pathep-[ansible_vpc_ipg]]/peerP-[192.168.50.2]" + - add_vpc_bgp_peer_again_32.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - add_vpc_bgp_peer_again_32.current.0.bgpPeerP.attributes.ctrl == "nh-self,send-com,send-ext-com" + - add_vpc_bgp_peer_again_32.current.0.bgpPeerP.attributes.peerCtrl == "bfd" + - add_vpc_bgp_peer_again_32.current.0.bgpPeerP.attributes.ttl == "2" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify remote AS object has been created correctly (version >= 4) + assert: + that: + - add_vpc_bgp_peer_again.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65456" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify remote AS object has been created correctly (version < 4) + assert: + that: + - add_vpc_bgp_peer_again_32.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65456" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + # MODIFY BGP peer + - name: update BGP peer (version >= 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + peer_ip: 192.168.50.2 + remote_asn: 65457 + bgp_controls: + - allow-self-as + - as-override + peer_controls: + - bfd + - dis-conn-check + private_asn_controls: + - remove-all + - remove-exclusive + - replace-as + address_type_controls: + - af-ucast + - af-mcast + weight: 50 + allow_self_as_count: 3 + ttl: 4 + admin_state: disabled + state: present + register: update_vpc_bgp_peer + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: update BGP peer (version < 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + peer_ip: 192.168.50.2 + remote_asn: 65457 + bgp_controls: + - allow-self-as + - as-override + peer_controls: + - bfd + - dis-conn-check + private_asn_controls: + - remove-all + - remove-exclusive + - replace-as + weight: 50 + allow_self_as_count: 3 + ttl: 4 + state: present + register: update_vpc_bgp_peer_32 + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify BGP peer has been updated with correct attributes (version >= 4) + assert: + that: + - update_vpc_bgp_peer is changed + - update_vpc_bgp_peer.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/protpaths-201-202/pathep-[ansible_vpc_ipg]]/peerP-[192.168.50.2]" + - update_vpc_bgp_peer.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - update_vpc_bgp_peer.current.0.bgpPeerP.attributes.addrTCtrl == "af-mcast,af-ucast" + - update_vpc_bgp_peer.current.0.bgpPeerP.attributes.adminSt == "disabled" + - update_vpc_bgp_peer.current.0.bgpPeerP.attributes.ctrl == "allow-self-as,as-override" + - update_vpc_bgp_peer.current.0.bgpPeerP.attributes.peerCtrl == "bfd,dis-conn-check" + - update_vpc_bgp_peer.current.0.bgpPeerP.attributes.ttl == "4" + - update_vpc_bgp_peer.current.0.bgpPeerP.attributes.allowedSelfAsCnt == "3" + - update_vpc_bgp_peer.current.0.bgpPeerP.attributes.privateASctrl == "remove-all,remove-exclusive,replace-as" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify BGP peer has been updated with correct attributes (version < 4) + assert: + that: + - update_vpc_bgp_peer_32 is changed + - update_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/protpaths-201-202/pathep-[ansible_vpc_ipg]]/peerP-[192.168.50.2]" + - update_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - update_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.ctrl == "allow-self-as,as-override" + - update_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.peerCtrl == "bfd,dis-conn-check" + - update_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.ttl == "4" + - update_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.allowedSelfAsCnt == "3" + - update_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.privateASctrl == "remove-all,remove-exclusive,replace-as" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify remote AS object has been created correctly (version >= 4) + assert: + that: + - update_vpc_bgp_peer.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65457" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify remote AS object has been created correctly (version < 4) + assert: + that: + - update_vpc_bgp_peer_32.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65457" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + # QUERY BGP peer + - name: query BGP peer (version >= 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + peer_ip: 192.168.50.2 + state: query + register: query_vpc_bgp_peer + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: query BGP peer (version < 4) + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + peer_ip: 192.168.50.2 + state: query + register: query_vpc_bgp_peer_32 + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify BGP peer attributes (version >= 4) + assert: + that: + - query_vpc_bgp_peer is not changed + - query_vpc_bgp_peer.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/protpaths-201-202/pathep-[ansible_vpc_ipg]]/peerP-[192.168.50.2]" + - query_vpc_bgp_peer.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - query_vpc_bgp_peer.current.0.bgpPeerP.attributes.addrTCtrl == "af-mcast,af-ucast" + - query_vpc_bgp_peer.current.0.bgpPeerP.attributes.adminSt == "disabled" + - query_vpc_bgp_peer.current.0.bgpPeerP.attributes.ctrl == "allow-self-as,as-override" + - query_vpc_bgp_peer.current.0.bgpPeerP.attributes.peerCtrl == "bfd,dis-conn-check" + - query_vpc_bgp_peer.current.0.bgpPeerP.attributes.ttl == "4" + - query_vpc_bgp_peer.current.0.bgpPeerP.attributes.allowedSelfAsCnt == "3" + - query_vpc_bgp_peer.current.0.bgpPeerP.attributes.privateASctrl == "remove-all,remove-exclusive,replace-as" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify BGP peer attributes (version < 4) + assert: + that: + - query_vpc_bgp_peer_32 is not changed + - query_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/protpaths-201-202/pathep-[ansible_vpc_ipg]]/peerP-[192.168.50.2]" + - query_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.addr == "192.168.50.2" + - query_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.ctrl == "allow-self-as,as-override" + - query_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.peerCtrl == "bfd,dis-conn-check" + - query_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.ttl == "4" + - query_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.allowedSelfAsCnt == "3" + - query_vpc_bgp_peer_32.current.0.bgpPeerP.attributes.privateASctrl == "remove-all,remove-exclusive,replace-as" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + - name: verify BGP remote AS (version >= 4) + assert: + that: + - query_pc_bgp_peer.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65457" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + + - name: verify BGP remote AS (version < 4) + assert: + that: + - query_pc_bgp_peer_32.current.0.bgpPeerP.children.1.bgpAsP.attributes.asn == "65457" + when: version.current.0.topSystem.attributes.version is version('4', '<') + + # DELETE BGP peer + - name: delete BGP peer + aci_l3out_bgp_peer: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + peer_ip: 192.168.50.2 + state: absent + register: remove_vpc_bgp_peer + + - name: verify remove_vpc_bgp_peer + assert: + that: + - remove_vpc_bgp_peer is changed + - remove_vpc_bgp_peer.current == [] + - remove_vpc_bgp_peer.previous.0.bgpPeerP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/protpaths-201-202/pathep-[ansible_vpc_ipg]]/peerP-[192.168.50.2]" + - remove_vpc_bgp_peer.previous.0.bgpPeerP.attributes.addr == "192.168.50.2" + + # CLEAN UP + - name: Remove ansible_tenant + aci_tenant: + <<: *aci_info + tenant: ansible_tenant + state: absent + + - name: Remove ansible_l3ext_domain + aci_domain: + <<: *aci_info + domain: ansible_l3ext_domain + domain_type: l3dom + state: absent + + - name: Remove ansible_port_channel_ipg + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: link + policy_group: ansible_port_channel_ipg + state: absent + + - name: Remove ansible_vpc_ipg + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: node + policy_group: ansible_vpc_ipg + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extepg_to_contract/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extepg_to_contract/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extepg_to_contract/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_to_contract/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extepg_to_contract/tasks/main.yml new file mode 100644 index 000000000..c49475d0a --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extepg_to_contract/tasks/main.yml @@ -0,0 +1,152 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Shreyas Srish (@shrsr) + +# 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: Add a new l3out + aci_l3out: + <<: *aci_info + tenant: ansible_tenant + name: ansible_l3out + description: l3out for Ansible tenant + domain: ansible_dom + route_control: export + vrf: ansible_vrf + l3protocol: ospf + state: present + + - name: Add a new ExtEpg + aci_l3out_extepg: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + name: ansible_extEpg + description: ExtEpg for Ansible l3out + state: present + + - name: Bind External End Point Groups to Contracts + aci_l3out_extepg_to_contract: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + contract: ansible_contract + contract_type: provider + state: present + register: bind_extepg_provider_contract + + - name: Verify bind_extepg_provider_contract + assert: + that: + - bind_extepg_provider_contract.current.0.fvRsProv.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_extEpg/rsprov-ansible_contract" + - bind_extepg_provider_contract.current.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' + + - name: Bind second External End Point Groups to Contracts + aci_l3out_extepg_to_contract: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + contract: ansible_contract2 + contract_type: provider + state: present + register: bind_extepg_provider_contract_2 + + - name: Verify bind_extepg_provider_contract_2 + assert: + that: + - bind_extepg_provider_contract_2.current.0.fvRsProv.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_extEpg/rsprov-ansible_contract2" + + - name: Query the External End Point Groups + aci_l3out_extepg_to_contract: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + contract: ansible_contract + contract_type: provider + state: query + register: query_extepg + + - name: Verify query_extepg + assert: + that: + - query_extepg is not changed + - query_extepg.current.0.fvRsProv.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_extEpg/rsprov-ansible_contract" + + - name: Query all the External End Point Groups + aci_l3out_extepg_to_contract: + <<: *aci_info + contract_type: provider + state: query + register: query_all + + - name: Remove existing contract to External End Point Groups + aci_l3out_extepg_to_contract: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + contract: ansible_contract + contract_type: provider + state: absent + register: remove_contract_extepg + + - name: Verify remove_contract_extepg + assert: + that: + - remove_contract_extepg.previous.0.fvRsProv.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/instP-ansible_extEpg/rsprov-ansible_contract" + + - name: Bind External End Point Groups to Contracts + aci_l3out_extepg_to_contract: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + contract: ansible_contract + contract_type: consumer + provider_match: all + state: present + ignore_errors: true + register: bind_extepg_consumer_contract + + - name: Verify bind_extepg_consumer_contract + assert: + that: + - bind_extepg_consumer_contract.msg == "the 'provider_match' is only configurable for Provided Contracts"
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extsubnet/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extsubnet/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extsubnet/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_extsubnet/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extsubnet/tasks/main.yml new file mode 100644 index 000000000..4be8a65f7 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_extsubnet/tasks/main.yml @@ -0,0 +1,318 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Cindy Zhao (@cizhao) + +# 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: Add a new l3out + aci_l3out: + <<: *aci_info + tenant: ansible_tenant + name: ansible_l3out + description: l3out for Ansible tenant + domain: ansible_dom + route_control: export + vrf: ansible_vrf + l3protocol: ospf + state: present + + - name: Add a new ExtEpg + aci_l3out_extepg: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + name: ansible_extEpg + description: ExtEpg for Ansible l3out + state: present + + - name: Add a subnet (check mode) + cisco.aci.aci_l3out_extsubnet: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + subnet_name: test + network: 192.0.2.0/24 + state: present + check_mode: true + register: cm_add_subnet + + - name: Add a subnet (normal mode) + cisco.aci.aci_l3out_extsubnet: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + subnet_name: test + network: 192.0.2.0/24 + state: present + register: nm_add_subnet + + - name: Verify cm_add_subnet and nm_add_subnet + assert: + that: + - cm_add_subnet is changed + - nm_add_subnet is changed + - cm_add_subnet.proposed.l3extSubnet.attributes.ip == "192.0.2.0/24" + - cm_add_subnet.proposed.l3extSubnet.attributes.name == "test" + - nm_add_subnet.current.0.l3extSubnet.attributes.ip == "192.0.2.0/24" + - nm_add_subnet.current.0.l3extSubnet.attributes.name == "test" + - nm_add_subnet.current.0.l3extSubnet.attributes.scope == "import-security" + - nm_add_subnet.current.0.l3extSubnet.attributes.annotation == 'orchestrator:ansible' + + - name: Add subnet again + cisco.aci.aci_l3out_extsubnet: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + subnet_name: test + network: 192.0.2.0/24 + state: present + register: nm_add_subnet_again + + - name: Verify nm_add_subnet_again + assert: + that: + - nm_add_subnet_again is not changed + + - name: Change subnet (check_mode) + cisco.aci.aci_l3out_extsubnet: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + network: 192.0.2.0/24 + subnet_name: ansible_test + description: description for subnet + scope: [ shared-security, import-security ] + state: present + check_mode: true + register: cm_change_subnet + + - name: Change subnet (normal mode) + cisco.aci.aci_l3out_extsubnet: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + network: 192.0.2.0/24 + subnet_name: ansible_test + description: description for subnet + scope: [ shared-security, import-security ] + state: present + register: nm_change_subnet + + - name: Verify cm_change_subnet and nm_change_subnet + assert: + that: + - cm_change_subnet is changed + - nm_change_subnet is changed + - cm_change_subnet.previous.0.l3extSubnet.attributes.descr == nm_change_subnet.previous.0.l3extSubnet.attributes.descr == "" + - cm_change_subnet.previous.0.l3extSubnet.attributes.name == nm_change_subnet.previous.0.l3extSubnet.attributes.name == "test" + - cm_change_subnet.previous.0.l3extSubnet.attributes.scope == nm_change_subnet.previous.0.l3extSubnet.attributes.scope == "import-security" + - cm_change_subnet.proposed.l3extSubnet.attributes.descr == "description for subnet" + - cm_change_subnet.proposed.l3extSubnet.attributes.name == "ansible_test" + - cm_change_subnet.proposed.l3extSubnet.attributes.scope == "import-security,shared-security" + - nm_change_subnet.current.0.l3extSubnet.attributes.descr == "description for subnet" + - nm_change_subnet.current.0.l3extSubnet.attributes.name == "ansible_test" + - nm_change_subnet.current.0.l3extSubnet.attributes.scope == "import-security,shared-security" + + - name: Add another subnet (normal mode) + cisco.aci.aci_l3out_extsubnet: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + network: 192.1.2.0/24 + state: present + register: nm_add_another_subnet + + - name: Verify nm_add_another_subnet + assert: + that: + - nm_add_another_subnet is changed + - nm_add_another_subnet.current.0.l3extSubnet.attributes.ip == "192.1.2.0/24" + + - name: Query all subnets + cisco.aci.aci_l3out_extsubnet: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + state: query + register: query_all + + - name: Query specific subnet + cisco.aci.aci_l3out_extsubnet: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + network: 192.0.2.0/24 + state: query + register: query_subnet + + - name: Verify query_all and query_subnet + assert: + that: + - query_all is not changed + - query_subnet is not changed + - query_all.current.0.l3extInstP.children | length == 2 + - query_subnet.current.0.l3extSubnet.attributes.name == "ansible_test" + - query_subnet.current.0.l3extSubnet.attributes.ip == "192.0.2.0/24" + + - name: Remove subnet + cisco.aci.aci_l3out_extsubnet: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + network: 192.0.2.0/24 + state: absent + register: rm_subnet + + - name: Verify rm_subnet + assert: + that: + - rm_subnet is changed + - rm_subnet.current == [] + - rm_subnet.previous.0.l3extSubnet.attributes.ip == "192.0.2.0/24" + - rm_subnet.previous.0.l3extSubnet.attributes.name == "ansible_test" + + - name: Change subnet aggregate mismatch without scope (normal mode) + cisco.aci.aci_l3out_extsubnet: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + network: 0.0.0.0/0 + subnet_name: ansible_test + description: description for subnet + aggregate: [ export-rtctrl, import-rtctrl ] + state: present + register: nm_aggregate_scope_none + ignore_errors: true + + - name: asserts failed aggregate creation tasks + assert: + that: + - nm_aggregate_scope_none is failed + - nm_aggregate_scope_none.msg.startswith("missing parameter(s) required by 'aggregate'") + + - name: Change subnet aggregate mismatch (normal mode) + cisco.aci.aci_l3out_extsubnet: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + network: 0.0.0.0/0 + subnet_name: ansible_test + description: description for subnet + scope: [ import-security ] + aggregate: [ export-rtctrl, import-rtctrl ] + state: present + register: nm_aggregate_scope_mismatch + ignore_errors: true + + - name: asserts failed aggregate creation tasks + assert: + that: + - nm_aggregate_scope_mismatch is failed + - nm_aggregate_scope_mismatch.msg == "All aggregate values ['export-rtctrl', 'import-rtctrl'] need to be defined in scope ['import-security']." + + - name: Change subnet aggregate match (check mode) + cisco.aci.aci_l3out_extsubnet: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + network: 0.0.0.0/0 + subnet_name: ansible_test + description: description for subnet + scope: [ export-rtctrl, import-rtctrl, import-security ] + aggregate: [ export-rtctrl, import-rtctrl ] + state: present + check_mode: true + register: cm_aggregate_scope_match + + - name: Change subnet aggregate match (normal mode) + cisco.aci.aci_l3out_extsubnet: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + network: 0.0.0.0/0 + subnet_name: ansible_test + description: description for subnet + scope: [ export-rtctrl, import-rtctrl, import-security ] + aggregate: [ export-rtctrl, import-rtctrl ] + state: present + register: nm_aggregate_scope_match + + - name: asserts success aggregate creation task + assert: + that: + - cm_aggregate_scope_match is changed + - cm_aggregate_scope_match.proposed.l3extSubnet.attributes.ip == "0.0.0.0/0" + - cm_aggregate_scope_match.proposed.l3extSubnet.attributes.name == "ansible_test" + - cm_aggregate_scope_match.proposed.l3extSubnet.attributes.scope == "export-rtctrl,import-rtctrl,import-security" + - cm_aggregate_scope_match.proposed.l3extSubnet.attributes.aggregate == "export-rtctrl,import-rtctrl" + - nm_aggregate_scope_match.current.0.l3extSubnet.attributes.ip == "0.0.0.0/0" + - nm_aggregate_scope_match.current.0.l3extSubnet.attributes.name == "ansible_test" + - nm_aggregate_scope_match.current.0.l3extSubnet.attributes.scope == "export-rtctrl,import-rtctrl,import-security" + - nm_aggregate_scope_match.current.0.l3extSubnet.attributes.aggregate == "export-rtctrl,import-rtctrl" + + - name: Change subnet other aggregate order (normal mode) + cisco.aci.aci_l3out_extsubnet: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + extepg: ansible_extEpg + network: 0.0.0.0/0 + subnet_name: ansible_test + description: description for subnet + scope: [ export-rtctrl, import-rtctrl, import-security ] + aggregate: [ import-rtctrl, export-rtctrl ] + state: present + register: nm_aggregate_scope_match + + - name: asserts success aggregate creation task reversed input order + assert: + that: + - nm_aggregate_scope_match is not changed
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_interface/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_interface/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_interface/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_interface/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_interface/tasks/main.yml new file mode 100644 index 000000000..5b2a247d8 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_interface/tasks/main.yml @@ -0,0 +1,535 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_tenant if it already exists + 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: Remove ansible_l3ext_domain if it already exists + aci_domain: + <<: *aci_info + domain: ansible_l3ext_domain + domain_type: l3dom + state: absent + + - name: Remove ansible_port_channel_ipg if it already exists + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: link + policy_group: ansible_port_channel_ipg + state: absent + + - name: Remove ansible_vpc_ipg if it already exists + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: node + policy_group: ansible_vpc_ipg + state: absent + + - name: Add a new tenant required for l3out + aci_tenant: + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + # ADD domain + - name: Add domain for l3out + aci_domain: + <<: *aci_info + domain: ansible_l3ext_domain + domain_type: l3dom + state: present + + # ADD VRF + - name: Add VRF for l3out + aci_vrf: + <<: *aci_info + tenant: ansible_tenant + vrf: ansible_vrf + state: present + + # ADD PC IPG + - name: Add port-channel IPG + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: link + policy_group: ansible_port_channel_ipg + state: present + + # ADD vPC IPG + - name: Add vPC IPG + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: node + policy_group: ansible_vpc_ipg + state: present + + # ADD l3out + - name: Add l3out + aci_l3out: + <<: *aci_info + tenant: ansible_tenant + name: ansible_l3out + vrf: ansible_vrf + domain: ansible_domain + route_control: export + state: present + + # ADD l3out logical node profile + - name: l3out logical node profile + aci_l3out_logical_node_profile: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + state: present + + # ADD l3out logical interface profile + - name: l3out logical interface profile + aci_l3out_logical_interface_profile: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + state: present + + # ADD l3out interface + - name: Add routed interface + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + interface_type: l3-port + mode: regular + addr: 192.168.50.1/27 + ipv6_dad: disabled + mtu: 1500 + auto_state: disabled + state: present + register: add_l3out_interface + + - name: Verify l3out has been created with the correct attributes + assert: + that: + - add_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]" + - add_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.addr == "192.168.50.1/27" + - add_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.ipv6Dad == "disabled" + - add_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.mtu == "1500" + - add_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.autostate == "disabled" + - add_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.ifInstT == "l3-port" + - add_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.mode == "regular" + - add_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.annotation == 'orchestrator:ansible' + + # ADD l3out interface again to check idempotency + - name: Add routed interface again + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + interface_type: l3-port + mode: regular + addr: 192.168.50.1/27 + ipv6_dad: disabled + mtu: 1500 + auto_state: disabled + state: present + register: add_l3out_interface_again + + - name: Verify l3out has not changed + assert: + that: + - add_l3out_interface_again is not changed + + # MODIFY l3out attributes + - name: Update routed interface + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + interface_type: sub-interface + mode: regular + addr: 192.168.60.1/27 + encap: vlan-913 + state: present + register: update_l3out_interface + + - name: Verify routed interface has correct attributes + assert: + that: + - update_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]" + - update_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.addr == "192.168.60.1/27" + - update_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.ifInstT == "sub-interface" + - update_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.encap == "vlan-913" + - update_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.mode == "regular" + + # QUERY l3out interface + - name: Query routed interface + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + state: query + register: query_l3out_interface + + - name: Verify query_l3out_interface + assert: + that: + - query_l3out_interface is not changed + - query_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]" + - query_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.addr == "192.168.60.1/27" + - query_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.ifInstT == "sub-interface" + - query_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.encap == "vlan-913" + - query_l3out_interface.current.0.l3extRsPathL3OutAtt.attributes.mode == "regular" + + - name: Query all interfaces + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + state: query + register: query_l3out_interfaces + + - name: Verify query_l3out_interfaces + assert: + that: + - query_l3out_interfaces is not changed + - query_l3out_interfaces.current.0.l3extLIfP.children.0.l3extRsPathL3OutAtt.attributes.rn == "rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]" + - query_l3out_interfaces.current.0.l3extLIfP.children.0.l3extRsPathL3OutAtt.attributes.addr == "192.168.60.1/27" + - query_l3out_interfaces.current.0.l3extLIfP.children.0.l3extRsPathL3OutAtt.attributes.ifInstT == "sub-interface" + - query_l3out_interfaces.current.0.l3extLIfP.children.0.l3extRsPathL3OutAtt.attributes.encap == "vlan-913" + - query_l3out_interfaces.current.0.l3extLIfP.children.0.l3extRsPathL3OutAtt.attributes.mode == "regular" + + # DELETE l3out interface + - name: Remove routed sub-interface + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + state: absent + register: delete_l3out_interface + + - name: Verify interface has been deleted + assert: + that: + - delete_l3out_interface.current == [] + - delete_l3out_interface.previous.0.l3extRsPathL3OutAtt.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]" + + # ADD l3out port-channel + - name: Add routed interface port-channel + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + interface_type: l3-port + mode: regular + addr: 192.168.70.1/27 + state: present + register: add_l3out_pc_interface + + - name: Verify l3out port-channel has been created with the correct attributes + assert: + that: + - add_l3out_pc_interface.current.0.l3extRsPathL3OutAtt.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]" + - add_l3out_pc_interface.current.0.l3extRsPathL3OutAtt.attributes.addr == "192.168.70.1/27" + - add_l3out_pc_interface.current.0.l3extRsPathL3OutAtt.attributes.ifInstT == "l3-port" + - add_l3out_pc_interface.current.0.l3extRsPathL3OutAtt.attributes.mode == "regular" + + # ADD l3out port-channel again to check idempotency + - name: Add routed interface port-channel again + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + interface_type: l3-port + mode: regular + addr: 192.168.70.1/27 + state: present + register: add_l3out_pc_interface_again + + - name: Verify interface has not changed + assert: + that: + - add_l3out_pc_interface_again is not changed + + # MODIFY l3out port-channel attributes + - name: Update routed port-channel interface + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + interface_type: l3-port + mode: regular + addr: 192.168.80.1/27 + state: present + register: update_l3out_pc_interface + + - name: Verify l3out port-channel has been updated with the correct attributes + assert: + that: + - update_l3out_pc_interface is changed + - update_l3out_pc_interface.current.0.l3extRsPathL3OutAtt.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]" + - update_l3out_pc_interface.current.0.l3extRsPathL3OutAtt.attributes.addr == "192.168.80.1/27" + - update_l3out_pc_interface.current.0.l3extRsPathL3OutAtt.attributes.ifInstT == "l3-port" + - update_l3out_pc_interface.current.0.l3extRsPathL3OutAtt.attributes.mode == "regular" + + # QUERY l3out port-channel interface + - name: Query l3out port-channel + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + state: query + register: query_l3out_pc_interface + + - name: Verify query_l3out_pc_interface + assert: + that: + - query_l3out_pc_interface is not changed + - query_l3out_pc_interface.current.0.l3extRsPathL3OutAtt.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]" + - query_l3out_pc_interface.current.0.l3extRsPathL3OutAtt.attributes.addr == "192.168.80.1/27" + - query_l3out_pc_interface.current.0.l3extRsPathL3OutAtt.attributes.ifInstT == "l3-port" + - query_l3out_pc_interface.current.0.l3extRsPathL3OutAtt.attributes.mode == "regular" + + # DELETE l3out port-channel interface + - name: Remove port-channel + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + state: absent + register: delete_l3out_pc_interface + + - name: Verify interface has been deleted + assert: + that: + - delete_l3out_pc_interface.current == [] + - delete_l3out_pc_interface.previous.0.l3extRsPathL3OutAtt.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]" + + # ADD l3out vPC + - name: Add interface vPC + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + interface_type: ext-svi + mode: native + addr: 192.168.90.1/27 + encap: vlan-913 + state: present + register: add_l3out_vpc_interface + + - name: Verify l3out vPC has been created with the correct attributes + assert: + that: + - add_l3out_vpc_interface.current.0.l3extRsPathL3OutAtt.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/protpaths-201-202/pathep-[ansible_vpc_ipg]]" + - add_l3out_vpc_interface.current.0.l3extRsPathL3OutAtt.attributes.addr == "192.168.90.1/27" + - add_l3out_vpc_interface.current.0.l3extRsPathL3OutAtt.attributes.ifInstT == "ext-svi" + - add_l3out_vpc_interface.current.0.l3extRsPathL3OutAtt.attributes.encap == "vlan-913" + - add_l3out_vpc_interface.current.0.l3extRsPathL3OutAtt.attributes.mode == "native" + + - name: Add interface vPC again + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + interface_type: ext-svi + mode: native + addr: 192.168.90.1/27 + encap: vlan-913 + state: present + register: add_l3out_vpc_interface_again + + - name: Verify vPC interface is not changed + assert: + that: + - add_l3out_vpc_interface_again is not changed + + # MODIFY vPC interface + - name: Update interface vPC + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + interface_type: ext-svi + mode: regular + addr: 192.168.90.1/27 + encap: vlan-913 + state: present + register: modify_l3out_vpc_interface + + - name: Verify l3out vPC has been updated with the correct attributes + assert: + that: + - modify_l3out_vpc_interface is changed + - modify_l3out_vpc_interface.current.0.l3extRsPathL3OutAtt.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/protpaths-201-202/pathep-[ansible_vpc_ipg]]" + - modify_l3out_vpc_interface.current.0.l3extRsPathL3OutAtt.attributes.addr == "192.168.90.1/27" + - modify_l3out_vpc_interface.current.0.l3extRsPathL3OutAtt.attributes.ifInstT == "ext-svi" + - modify_l3out_vpc_interface.current.0.l3extRsPathL3OutAtt.attributes.encap == "vlan-913" + - modify_l3out_vpc_interface.current.0.l3extRsPathL3OutAtt.attributes.mode == "regular" + + # QUERY vPC interface + - name: Query vPC interface + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + state: query + register: query_l3out_vpc_interface + + - name: Verify l3out vPC query + assert: + that: + - query_l3out_vpc_interface is not changed + - query_l3out_vpc_interface.current.0.l3extRsPathL3OutAtt.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/protpaths-201-202/pathep-[ansible_vpc_ipg]]" + - query_l3out_vpc_interface.current.0.l3extRsPathL3OutAtt.attributes.addr == "192.168.90.1/27" + - query_l3out_vpc_interface.current.0.l3extRsPathL3OutAtt.attributes.ifInstT == "ext-svi" + - query_l3out_vpc_interface.current.0.l3extRsPathL3OutAtt.attributes.encap == "vlan-913" + - query_l3out_vpc_interface.current.0.l3extRsPathL3OutAtt.attributes.mode == "regular" + + - name: Delete vPC interface + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + state: absent + register: delete_l3out_vpc_interface + + - name: Verify vPC interface is deleted + assert: + that: + - delete_l3out_vpc_interface.current == [] + + # CLEAN UP + - name: Remove ansible_tenant + aci_tenant: + <<: *aci_info + tenant: ansible_tenant + state: absent + + - name: Remove ansible_l3ext_domain + aci_domain: + <<: *aci_info + domain: ansible_l3ext_domain + domain_type: l3dom + state: absent + + - name: Remove ansible_port_channel_ipg + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: link + policy_group: ansible_port_channel_ipg + state: absent + + - name: Remove ansible_vpc_ipg + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: node + policy_group: ansible_vpc_ipg + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_interface_secondary_ip/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_interface_secondary_ip/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_interface_secondary_ip/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_interface_secondary_ip/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_interface_secondary_ip/tasks/main.yml new file mode 100644 index 000000000..775d40ee8 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_interface_secondary_ip/tasks/main.yml @@ -0,0 +1,502 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove test tenant if it already exists + aci_tenant: + <<: *aci_info + tenant: ansible_test + 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: Remove port-channel IPG + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: link + policy_group: ansible_port_channel_ipg + state: absent + + - name: Remove vPC IPG + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: node + policy_group: ansible_vpc_ipg + state: absent + + # ADD PC IPG + - name: Add port-channel IPG + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: link + policy_group: ansible_port_channel_ipg + state: present + + # ADD vPC IPG + - name: Add vPC IPG + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: node + policy_group: ansible_vpc_ipg + state: present + + # ADD domain + - name: Add domain for l3out + aci_domain: + <<: *aci_info + domain: ansible_l3ext_domain + domain_type: l3dom + state: present + + # ADD tenant + - name: Add a new tenant required for l3out + aci_tenant: + <<: *aci_info + tenant: ansible_test + description: Ansible tenant + state: present + + # ADD VRF + - name: Add VRF for l3out + aci_vrf: + <<: *aci_info + tenant: ansible_test + vrf: ansible_vrf + state: present + + # ADD l3out + - name: Add l3out + aci_l3out: + <<: *aci_info + tenant: ansible_test + name: ansible_l3out + vrf: ansible_vrf + domain: ansible_domain + route_control: export + state: present + + # ADD l3out logical node profile + - name: l3out logical node profile + aci_l3out_logical_node_profile: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + state: present + + # ADD l3out logical interface profile + - name: l3out logical interface profile + aci_l3out_logical_interface_profile: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + state: present + + # ADD l3out routed interface + - name: Add routed interface + aci_l3out_interface: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + interface_type: l3-port + mode: regular + addr: 192.168.50.1/27 + state: present + + # ADD l3out routed interface po + - name: Add routed interface port-channel + aci_l3out_interface: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + interface_type: l3-port + mode: regular + addr: 192.168.70.1/27 + state: present + + # ADD l3out routed interface vPC + - name: Add routed interface vPC + aci_l3out_interface: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + interface_type: ext-svi + mode: native + encap: vlan-913 + state: present + + # ADD l3out routed interface vPC member + - name: Add routed interface vPC member + aci_l3out_logical_interface_vpc_member: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + side: A + addr: 192.168.90.1/27 + state: present + + # ADD secondary IPs to the interfaces + - name: Add secondary IP to routed interface + aci_l3out_interface_secondary_ip: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + addr: 192.168.50.2/27 + ipv6_dad: disabled + state: present + register: secondary_intf + + - name: Add secondary to IP routed interface port-channel + aci_l3out_interface_secondary_ip: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + addr: 192.168.70.2/27 + ipv6_dad: disabled + state: present + register: secondary_po + + - name: Add secondary IP to routed interface vPC + aci_l3out_interface_secondary_ip: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + side: A + addr: 192.168.90.2/27 + ipv6_dad: disabled + state: present + register: secondary_vpc + + - name: Verify secondaries have been created with the correct attributes + assert: + that: + - secondary_intf.current.0.l3extIp.attributes.dn == "uni/tn-ansible_test/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]/addr-[192.168.50.2/27]" + - secondary_intf.current.0.l3extIp.attributes.ipv6Dad == "disabled" + - secondary_intf.current.0.l3extIp.attributes.annotation == 'orchestrator:ansible' + - secondary_po.current.0.l3extIp.attributes.dn== "uni/tn-ansible_test/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]/addr-[192.168.70.2/27]" + - secondary_po.current.0.l3extIp.attributes.ipv6Dad == "disabled" + - secondary_vpc.current.0.l3extIp.attributes.addr == "192.168.90.2/27" + - secondary_vpc.current.0.l3extIp.attributes.ipv6Dad == "disabled" + + # CHECK idempotency + - name: Add secondary IP to routed interface with no changes + aci_l3out_interface_secondary_ip: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + addr: 192.168.50.2/27 + ipv6_dad: disabled + state: present + register: secondary_intf_again + + - name: Add secondary to IP routed interface port-channel with no changes + aci_l3out_interface_secondary_ip: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + addr: 192.168.70.2/27 + ipv6_dad: disabled + state: present + register: secondary_po_again + + - name: Add secondary IP to routed interface vPC with no changes + aci_l3out_interface_secondary_ip: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + side: A + addr: 192.168.90.2/27 + ipv6_dad: disabled + state: present + register: secondary_vpc_again + + - name: Verify MOs have not changed + assert: + that: + - secondary_intf_again is not changed + - secondary_po_again is not changed + - secondary_vpc_again is not changed + + # CHECK updates/modifications + - name: Modify routed interface + aci_l3out_interface_secondary_ip: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + addr: 192.168.50.2/27 + ipv6_dad: enabled + state: present + register: secondary_intf_update + + - name: Modify routed port-channel + aci_l3out_interface_secondary_ip: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + addr: 192.168.70.2/27 + ipv6_dad: enabled + state: present + register: secondary_po_update + + - name: Modify routed vPC + aci_l3out_interface_secondary_ip: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + side: A + addr: 192.168.90.2/27 + ipv6_dad: enabled + state: present + register: secondary_vpc_update + + - name: Verify updates have been applied + assert: + that: + - secondary_intf_update is changed + - secondary_po_update is changed + - secondary_vpc_update is changed + - secondary_intf_update.current.0.l3extIp.attributes.ipv6Dad == "enabled" + - secondary_po_update.current.0.l3extIp.attributes.ipv6Dad == "enabled" + - secondary_vpc_update.current.0.l3extIp.attributes.ipv6Dad == "enabled" + + # QUERIES + - name: Query secondary for interface + aci_l3out_interface_secondary_ip: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + addr: 192.168.50.2/27 + ipv6_dad: enabled + state: query + register: secondary_intf_query + + - name: Query secondary for po + aci_l3out_interface_secondary_ip: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + addr: 192.168.70.2/27 + ipv6_dad: enabled + state: query + register: secondary_po_query + + - name: Query secondary for vpc + aci_l3out_interface_secondary_ip: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + side: A + addr: 192.168.90.2/27 + ipv6_dad: enabled + state: query + register: secondary_vpc_query + + - name: Query all secondary IPs + aci_l3out_interface_secondary_ip: + <<: *aci_info + state: query + register: secondary_all_query + + - name: Verify queries + assert: + that: + - secondary_intf_query is not changed + - secondary_po_query is not changed + - secondary_vpc_query is not changed + - secondary_intf_query.current.0.l3extIp.attributes.dn == "uni/tn-ansible_test/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]/addr-[192.168.50.2/27]" + - secondary_intf_query.current.0.l3extIp.attributes.ipv6Dad == "enabled" + - secondary_po_query.current.0.l3extIp.attributes.dn== "uni/tn-ansible_test/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]/addr-[192.168.70.2/27]" + - secondary_po_query.current.0.l3extIp.attributes.ipv6Dad == "enabled" + - secondary_vpc_query.current.0.l3extIp.attributes.addr == "192.168.90.2/27" + - secondary_vpc_query.current.0.l3extIp.attributes.ipv6Dad == "enabled" + - secondary_all_query.current|length > 1 + + # DELETE secondary IPs + - name: Delete secondary for interface + aci_l3out_interface_secondary_ip: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/15 + addr: 192.168.50.2/27 + ipv6_dad: enabled + state: absent + register: secondary_intf_remove + + - name: Delete secondary for po + aci_l3out_interface_secondary_ip: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201 + path_ep: ansible_port_channel_ipg + addr: 192.168.70.2/27 + ipv6_dad: enabled + state: absent + register: secondary_po_remove + + - name: Delete secondary for vpc + aci_l3out_interface_secondary_ip: + <<: *aci_info + tenant: ansible_test + l3out: ansible_l3out + node_profile: ansible_node_profile + interface_profile: ansible_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: ansible_vpc_ipg + side: A + addr: 192.168.90.2/27 + ipv6_dad: enabled + state: absent + register: secondary_vpc_remove + + - name: Verify objects have been deleted + assert: + that: + - secondary_intf_remove.current == [] + - secondary_po_remove.current == [] + - secondary_vpc_remove.current == [] + - secondary_intf_remove.previous.0.l3extIp.attributes.dn == "uni/tn-ansible_test/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[eth1/15]]/addr-[192.168.50.2/27]" + - secondary_po_remove.previous.0.l3extIp.attributes.dn == "uni/tn-ansible_test/out-ansible_l3out/lnodep-ansible_node_profile/lifp-ansible_interface_profile/rspathL3OutAtt-[topology/pod-1/paths-201/pathep-[ansible_port_channel_ipg]]/addr-[192.168.70.2/27]" + - secondary_vpc_remove.previous.0.l3extIp.attributes.addr == "192.168.90.2/27" + + # CLEAN UP + - name: Remove tenant + aci_tenant: + <<: *aci_info + tenant: ansible_test + state: absent + + - name: Remove ext domain + aci_domain: + <<: *aci_info + domain: ansible_l3ext_domain + domain_type: l3dom + state: absent + + - name: Remove port-channel + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: link + policy_group: ansible_port_channel_ipg + state: absent + + - name: Remove vpc + aci_interface_policy_leaf_policy_group: + <<: *aci_info + lag_type: node + policy_group: ansible_vpc_ipg + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_profile/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_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_logical_interface_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_profile/tasks/main.yml new file mode 100644 index 000000000..4466369d5 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_profile/tasks/main.yml @@ -0,0 +1,174 @@ +# Author: Marcel Zehnder (@maercu) +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# 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") }}' + +# CLEAN ENVIRONMENT +- name: Remove test tenant before we kickoff + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + tenant: ansible_test + 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 + # SETUP ENVIRONMENT + - name: Create domain + cisco.aci.aci_domain: &domain_present + <<: *aci_info + domain: l3outintftest + domain_type: l3dom + state: present + + - name: Create tenant + cisco.aci.aci_tenant: &tenant_present + <<: *tenant_absent + state: present + + - name: Configure VRF + cisco.aci.aci_vrf: &vrf_present + <<: *tenant_present + vrf: l3outintftest + + - name: Create L3Out + cisco.aci.aci_l3out: + <<: *vrf_present + l3out: l3outintftest + domain: l3outintftest + route_control: export + + - name: Crete node profile + cisco.aci.aci_l3out_logical_node_profile: &np_present + <<: *tenant_present + l3out: l3outintftest + node_profile: NODES + + # BEGIN WITH TESTS (ADD PROFILE) + - name: Add interface profile (check_mode) + cisco.aci.aci_l3out_logical_interface_profile: &intf_present + <<: *np_present + interface_profile: INTFS + check_mode: true + register: cm_add_intf + + - name: Add interface profile (normal_mode) + cisco.aci.aci_l3out_logical_interface_profile: + <<: *intf_present + register: nm_add_intf + + - name: Verify nm_add_intf + assert: + that: + - cm_add_intf is changed + - 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' + - nm_add_intf.current.0.l3extLIfP.attributes.annotation == 'orchestrator:ansible' + + - name: Add profile again, check if idempotency works + cisco.aci.aci_l3out_logical_interface_profile: + <<: *intf_present + register: add_intf_again + + - name: Verify add_intf_again + assert: + that: + - add_intf_again is not changed + + # UPDATE INTERFACE PROFILE + - name: Update profile + cisco.aci.aci_l3out_logical_interface_profile: &intf_update + <<: *intf_present + nd_policy: NDTEST + register: update_intf + + - name: Verify update_intf + assert: + that: + - update_intf is changed + - update_intf.previous != [] + + # ADD ANOTHER PROFILE + - name: Add another profile + cisco.aci.aci_l3out_logical_interface_profile: + <<: *intf_present + interface_profile: INTF2 + + # QUERY ALL PROFILES + - name: Query all profiles + cisco.aci.aci_l3out_logical_interface_profile: + <<: *aci_info + state: query + register: query_all_profiles + + - name: Verify query_all_profiles + assert: + that: + - query_all_profiles is not changed + - query_all_profiles.current|length >= 1 + + # QUERY A SPECIFIC PROFILE + - name: Query a specific profile + cisco.aci.aci_l3out_logical_interface_profile: + <<: *intf_update + state: query + register: query_spec_profile + + - name: Verify query_spec_profile + assert: + that: + - query_spec_profile is not changed + - query_spec_profile.current|length == 1 + + # QUERY A NON EXISTING PROFILE + - name: Query a nonexisting profile + cisco.aci.aci_l3out_logical_interface_profile: + <<: *np_present + interface_profile: nonexist + state: query + register: query_nonexist_profile + + - name: Verify query_nonexist_profile + assert: + that: + - query_nonexist_profile is not changed + - query_nonexist_profile.current == [] + + # REMOVE PROFILE + - name: Remove interface profile + cisco.aci.aci_l3out_logical_interface_profile: &intf_absent + <<: *intf_update + state: absent + register: remove_profile + + - name: Verify remove_profile + assert: + that: + - remove_profile is changed + - remove_profile.current == [] + + # REMOVE NONEXISTING PROFILE + - name: Remove interface profile again (nonexisting) + cisco.aci.aci_l3out_logical_interface_profile: + <<: *intf_absent + register: remove_nonexist_profile + + - name: Verify remove_nonexist_profile + assert: + that: + - remove_nonexist_profile is not changed + - remove_nonexist_profile.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_profile_ospf_policy/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_profile_ospf_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_profile_ospf_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_logical_interface_profile_ospf_policy/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_profile_ospf_policy/tasks/main.yml new file mode 100644 index 000000000..d10a88a7f --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_profile_ospf_policy/tasks/main.yml @@ -0,0 +1,172 @@ +# Author: Jason Juenger (@jasonjuenger) +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# 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") }}' + +# CLEAN ENVIRONMENT +- name: Remove test tenant before we kickoff + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + tenant: ansible_test + 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 + # SETUP ENVIRONMENT + - name: Create domain + cisco.aci.aci_domain: &domain_present + <<: *aci_info + domain: l3outintftest + domain_type: l3dom + state: present + + - name: Create tenant + cisco.aci.aci_tenant: &tenant_present + <<: *tenant_absent + state: present + + - name: Configure VRF + cisco.aci.aci_vrf: &vrf_present + <<: *tenant_present + vrf: l3outintftest + + - name: Create L3Out + cisco.aci.aci_l3out: + <<: *vrf_present + l3out: l3outintftest + domain: l3outintftest + route_control: export + + - name: Create node profile + cisco.aci.aci_l3out_logical_node_profile: &np_present + <<: *tenant_present + l3out: l3outintftest + node_profile: NODES + + - name: Create interface profile + cisco.aci.aci_l3out_logical_interface_profile: &intf_present + <<: *np_present + interface_profile: INTFS + + # BEGIN WITH TESTS (ADD OSPF POLICY TO PROFILE) + - name: Add ospf policy to interface profile (check mode) + cisco.aci.aci_l3out_logical_interface_profile_ospf_policy: &ospfIfP_present + <<: *intf_present + ospf_policy: default + check_mode: true + register: cm_add_ospfIfP + + - name: Add ospf policy to interface profile (normal mode) + cisco.aci.aci_l3out_logical_interface_profile_ospf_policy: *ospfIfP_present + register: nm_add_ospfIfP + + - name: Verify add_ospfIfP + assert: + that: + - cm_add_ospfIfP is changed + - nm_add_ospfIfP is changed + - cm_add_ospfIfP.previous == nm_add_ospfIfP.previous == [] + - cm_add_ospfIfP.proposed.ospfIfP.children[0].ospfRsIfPol.attributes.tnOspfIfPolName == 'default' + - nm_add_ospfIfP.current[0].ospfIfP.children[0].ospfRsIfPol.attributes.tnOspfIfPolName == 'default' + + - name: Add ospf policy again to check idempotency + cisco.aci.aci_l3out_logical_interface_profile_ospf_policy: *ospfIfP_present + register: nm_add_ospfIfP_again + + - name: Verify add_ospfIfP_again + assert: + that: + - nm_add_ospfIfP_again is not changed + + # UPDATE INTERFACE PROFILE OSPF POLICY + - name: Update interface profile ospf policy + cisco.aci.aci_l3out_logical_interface_profile_ospf_policy: &ospfIfP_update + <<: *ospfIfP_present + ospf_auth_type: simple + ospf_auth_key: my_key + register: update_ospfIfP + + - name: Verify update_ospfIfP + assert: + that: + - update_ospfIfP is changed + - update_ospfIfP.previous != [] + - update_ospfIfP.current[0].ospfIfP.children[0].ospfRsIfPol.attributes.tnOspfIfPolName == 'default' + - update_ospfIfP.current[0].ospfIfP.attributes.authType == 'simple' + + # QUERY INTERFACE PROFILE OSPF POLICY + - name: Query interface profile ospf policy + cisco.aci.aci_l3out_logical_interface_profile_ospf_policy: + <<: *ospfIfP_update + state: query + register: query_ospfIfP_profile + + - name: Verify query_ospfIfP_profile + assert: + that: + - query_ospfIfP_profile is not changed + - query_ospfIfP_profile.current|length == 1 + - query_ospfIfP_profile.current[0].ospfIfP.children[0].ospfRsIfPol.attributes.tnOspfIfPolName == 'default' + - query_ospfIfP_profile.current[0].ospfIfP.attributes.authType == 'simple' + + # REMOVE POLICY + - name: Remove interface profile ospf policy + cisco.aci.aci_l3out_logical_interface_profile_ospf_policy: &ospfIfP_absent + <<: *intf_present + state: absent + register: remove_profile + + - name: Remove interface profile ospf policy again for idempotency + cisco.aci.aci_l3out_logical_interface_profile_ospf_policy: + <<: *ospfIfP_absent + state: absent + register: remove_profile_again + + - name: Verify remove_profile and remove_profile_again + assert: + that: + - remove_profile.previous|length == 1 + - remove_profile.previous[0].ospfIfP.children[0].ospfRsIfPol.attributes.tnOspfIfPolName == 'default' + - remove_profile.previous[0].ospfIfP.attributes.authType == 'simple' + - remove_profile is changed + - remove_profile_again is not changed + - remove_profile.current == remove_profile_again.current == [] + + # QUERY NON-EXISTING POLICY + - name: Query a nonexisting policy + cisco.aci.aci_l3out_logical_interface_profile_ospf_policy: + <<: *ospfIfP_absent + state: query + register: query_nonexist_policy + + - name: Verify query_nonexist_policy + assert: + that: + - query_nonexist_policy is not changed + - query_nonexist_policy.current == [] + + # REMOVE NON-EXISTING POLICY + - name: Remove interface profile ospf policy again (nonexisting) + cisco.aci.aci_l3out_logical_interface_profile_ospf_policy: + <<: *ospfIfP_absent + register: remove_nonexist_policy + + - name: Verify remove_nonexist_policy + assert: + that: + - remove_nonexist_policy is not changed + - remove_nonexist_policy.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_vpc_member/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_vpc_member/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_vpc_member/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_logical_interface_vpc_member/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_vpc_member/tasks/main.yml new file mode 100644 index 000000000..749d2137f --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_interface_vpc_member/tasks/main.yml @@ -0,0 +1,149 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Anvitha Jain (@anvitha-jain) + +# 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: Add a new L3Out + aci_l3out: + <<: *aci_info + tenant: ansible_tenant + name: ansible_l3out + description: L3Out for ansible_tenant tenant + domain: ansible_dom + vrf: ansible_vrf + l3protocol: ospf + route_control: export + state: present + + - name: Add a new logical node profile + cisco.aci.aci_l3out_logical_node_profile: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_LNode + state: present + + - name: Add a interface profile + cisco.aci.aci_l3out_logical_interface_profile: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_LNode + interface_profile: ansible_LInterface + state: present + + - name: Add two vPC-interfaces + aci_l3out_interface: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_LNode + interface_profile: ansible_LInterface + pod_id: 1 + node_id: 101-102 + path_ep: "{{ item }}" + interface_type: ext-svi + state: present + loop: + - policy_group_one + - policy_group_two + + - name: Add a VPC member based on path_dn + aci_l3out_logical_interface_vpc_member: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + logical_node: ansible_LNode + logical_interface: ansible_LInterface + path_dn: topology/pod-1/protpaths-101-102/pathep-[policy_group_one] + side: A + state: present + register: l3out_logical_interface_vpc_member_present + + - name: Assertions check for add a VPC member based on path_dn + assert: + that: + - l3out_logical_interface_vpc_member_present is changed + - l3out_logical_interface_vpc_member_present.current.0.l3extMember.attributes.annotation == 'orchestrator:ansible' + + - name: Add a VPC member based on pod_id, node_id, path_ep + aci_l3out_logical_interface_vpc_member: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + node_profile: ansible_LNode + interface_profile: ansible_LInterface + pod_id: 1 + node_id: 101-102 + path_ep: policy_group_two + side: A + addr: 192.168.1.254/24 + ipv6_dad: disabled + state: present + + - name: Query a specific VPC member under ansible_l3out + aci_l3out_logical_interface_vpc_member: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + logical_node: ansible_LNode + logical_interface: ansible_LInterface + path_dn: topology/pod-1/protpaths-101-102/pathep-[policy_group_one] + side: A + state: query + register: query_result + + - name: Query all relationships + aci_l3out_logical_interface_vpc_member: + <<: *aci_info + tenant: ansible_tenant + state: query + ignore_errors: true + register: query_result + + - name: Remove a VPC member + aci_l3out_logical_interface_vpc_member: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + logical_node: ansible_LNode + logical_interface: ansible_LInterface + path_dn: topology/pod-1/protpaths-101-102/pathep-[policy_group_one] + side: A + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_node/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_node/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_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_l3out_logical_node/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml new file mode 100644 index 000000000..68bc64b20 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml @@ -0,0 +1,155 @@ +# Author: Marcel Zehnder (@maercu) +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# 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") }}' + +# CLEAN ENVIRONMENT +- name: Remove test tenant before we kickoff + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + tenant: ansible_test + 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 + # SETUP ENVIRONMENT + - name: Create domain + cisco.aci.aci_domain: &domain_present + <<: *aci_info + domain: l3outtest + domain_type: l3dom + state: present + + - name: Create tenant + cisco.aci.aci_tenant: &tenant_present + <<: *tenant_absent + state: present + + - name: Configure VRF + cisco.aci.aci_vrf: &vrf_present + <<: *tenant_present + vrf: l3outtest + + - name: Create L3Out + cisco.aci.aci_l3out: + <<: *vrf_present + l3out: l3outtest + domain: l3outtest + route_control: export + + - name: Crete node profile + cisco.aci.aci_l3out_logical_node_profile: &np_present + <<: *tenant_present + l3out: l3outtest + node_profile: NODES + + # BEGIN WITH TESTS + - name: Add node (check_mode) + cisco.aci.aci_l3out_logical_node: &node_present + <<: *np_present + pod_id: 1 + node_id: 111 + router_id: 111.111.111.111 + router_id_as_loopback: 'no' + check_mode: true + register: cm_add_node + + - name: Add node (normal mode) + cisco.aci.aci_l3out_logical_node: + <<: *node_present + register: nm_add_node + + - name: Verify nm_add_node + assert: + that: + - 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' + - nm_add_node.current.0.l3extRsNodeL3OutAtt.attributes.annotation == 'orchestrator:ansible' + + - name: Add node again, check if idempotency works + cisco.aci.aci_l3out_logical_node: + <<: *node_present + register: add_node_again + + - name: Verify add_node_again + assert: + that: + - add_node_again is not changed + + # UPDATE NODE + - name: Change roouter id + cisco.aci.aci_l3out_logical_node: &node_update + <<: *node_present + router_id: 11.11.11.11 + register: update_node + + - name: Verify update_node + assert: + that: + - update_node is changed + - update_node.previous != [] + - update_node.sent.l3extRsNodeL3OutAtt.attributes.rtrId == '11.11.11.11' + + # ADD ANOTHER NODE + - name: Add another node + cisco.aci.aci_l3out_logical_node: + <<: *node_present + node_id: 112 + router_id: 12.12.12.12 + + # QUERY ALL NODES + - name: Query all nodes + cisco.aci.aci_l3out_logical_node: + <<: *aci_info + state: query + register: query_all_nodes + + - name: Verify query_all_nodes + assert: + that: + - query_all_nodes is not changed + - query_all_nodes.current|length >= 1 + + # QUERY A SPECIFIC NODE + - name: Query a specific node + cisco.aci.aci_l3out_logical_node: + <<: *node_update + state: query + register: query_spec_node + + - name: Verify query_spec_node + assert: + that: + - query_spec_node is not changed + - query_spec_node.current|length == 1 + + # REMOVE NODE + - name: Remove node + cisco.aci.aci_l3out_logical_node: + <<: *node_update + state: absent + register: remove_node + + - name: Verify remove_node + assert: + that: + - remove_node is changed + - remove_node.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_node_profile/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_node_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_node_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_logical_node_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_node_profile/tasks/main.yml new file mode 100644 index 000000000..cbd3fa1a9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_logical_node_profile/tasks/main.yml @@ -0,0 +1,222 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, Jason Juenger (@jasonjuenger) + +# 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_info + state: present + tenant: ansible_tenant + register: tenant_present + + - name: Create L3out for tests + cisco.aci.aci_l3out: + <<: *aci_info + state: present + tenant: ansible_tenant + l3out: ansible_l3out + domain: ansible_dom + route_control: export + vrf: ansible_vrf + l3protocol: ospf + register: l3out_present + + - name: Add L3out node profile (check mode) + cisco.aci.aci_l3out_logical_node_profile: &aci_node_profile_present + <<: *aci_info + node_profile: ansible_node_profile + description: 'Node profile for Ansible testing' + dscp: CS0 + l3out: ansible_l3out + tenant: ansible_tenant + state: present + check_mode: true + register: cm_add_node_profile + + - name: Add L3out node profile (normal mode) + cisco.aci.aci_l3out_logical_node_profile: *aci_node_profile_present + register: nm_add_node_profile + + - name: Add another L3out node profile (normal mode) + cisco.aci.aci_l3out_logical_node_profile: + <<: *aci_info + node_profile: ansible_node_profile2 + description: 'Second node profile for Ansible testing' + dscp: CS0 + l3out: ansible_l3out + tenant: ansible_tenant + state: present + register: nm_add_second_node_profile + + - name: Verify add_node_profile + assert: + that: + - cm_add_node_profile is changed + - nm_add_node_profile is changed + - nm_add_second_node_profile is changed + - cm_add_node_profile.sent.l3extLNodeP.attributes.descr == nm_add_node_profile.sent.l3extLNodeP.attributes.descr == 'Node profile for Ansible testing' + - cm_add_node_profile.sent.l3extLNodeP.attributes.name == nm_add_node_profile.sent.l3extLNodeP.attributes.name == 'ansible_node_profile' + - cm_add_node_profile.proposed.l3extLNodeP.attributes.descr == nm_add_node_profile.proposed.l3extLNodeP.attributes.descr == 'Node profile for Ansible testing' + - cm_add_node_profile.proposed.l3extLNodeP.attributes.name == nm_add_node_profile.proposed.l3extLNodeP.attributes.name == 'ansible_node_profile' + - cm_add_node_profile.current == cm_add_node_profile.previous == nm_add_node_profile.previous == [] + - nm_add_node_profile.current.0.l3extLNodeP.attributes.dn == 'uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile' + - nm_add_node_profile.current.0.l3extLNodeP.attributes.name == 'ansible_node_profile' + - nm_add_node_profile.current.0.l3extLNodeP.attributes.annotation == 'orchestrator:ansible' + - nm_add_second_node_profile.current.0.l3extLNodeP.attributes.dn == 'uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile2' + - nm_add_second_node_profile.current.0.l3extLNodeP.attributes.name == 'ansible_node_profile2' + + - name: Modify node profile (check mode) + cisco.aci.aci_l3out_logical_node_profile: &aci_node_profile_modify + <<: *aci_info + node_profile: ansible_node_profile + description: 'my_updated_descr' + l3out: ansible_l3out + tenant: ansible_tenant + state: present + check_mode: true + register: cm_mod_node_profile + + - name: Modify node profile (normal mode) + cisco.aci.aci_l3out_logical_node_profile: *aci_node_profile_modify + register: nm_mod_node_profile + + - name: Verify mod_node_profile + assert: + that: + - cm_mod_node_profile is changed + - nm_mod_node_profile is changed + - cm_mod_node_profile.sent.l3extLNodeP.attributes.descr == nm_mod_node_profile.sent.l3extLNodeP.attributes.descr == 'my_updated_descr' + - cm_mod_node_profile.proposed.l3extLNodeP.attributes.descr == nm_mod_node_profile.proposed.l3extLNodeP.attributes.descr == 'my_updated_descr' + - nm_mod_node_profile.current.0.l3extLNodeP.attributes.dn == 'uni/tn-ansible_tenant/out-ansible_l3out/lnodep-ansible_node_profile' + - nm_mod_node_profile.current.0.l3extLNodeP.attributes.name == 'ansible_node_profile' + + - name: Query existing node profile (check mode) + cisco.aci.aci_l3out_logical_node_profile: &query_existing_node_profile + <<: *aci_info + node_profile: ansible_node_profile + l3out: ansible_l3out + tenant: ansible_tenant + state: query + check_mode: true + register: cm_query_node_profile + + - name: Query existing node profile (normal mode) + cisco.aci.aci_l3out_logical_node_profile: *query_existing_node_profile + register: nm_query_node_profile + + - name: Query non-existent node profile + cisco.aci.aci_l3out_logical_node_profile: + <<: *aci_info + node_profile: ansible_fake_node_profile + l3out: ansible_l3out + tenant: ansible_tenant + state: query + check_mode: true + register: nm_query_fake_node_profile + + - name: Query all node profile for L3out + cisco.aci.aci_l3out_logical_node_profile: + <<: *aci_info + l3out: ansible_l3out + tenant: ansible_tenant + state: query + register: nm_query_all_node_profiles + + - name: Verify query_node_profile + assert: + that: + - cm_query_node_profile is not changed + - nm_query_node_profile is not changed + - nm_query_fake_node_profile is not changed + - nm_query_all_node_profiles is not changed + - cm_query_node_profile.current.0.l3extLNodeP.attributes.name == 'ansible_node_profile' + - nm_query_node_profile.current.0.l3extLNodeP.attributes.name == 'ansible_node_profile' + - nm_query_fake_node_profile.current == [] + - nm_query_all_node_profiles.current.0.l3extOut.children.0.l3extLNodeP.attributes.name == 'ansible_node_profile2' + - nm_query_all_node_profiles.current.0.l3extOut.children.1.l3extLNodeP.attributes.name == 'ansible_node_profile' + + - name: Remove node profile (check mode) + cisco.aci.aci_l3out_logical_node_profile: &aci_node_profile_absent + <<: *aci_info + node_profile: ansible_node_profile + l3out: ansible_l3out + tenant: ansible_tenant + state: absent + check_mode: true + register: cm_remove_node_profile + + - name: Remove node profile (normal mode) + cisco.aci.aci_l3out_logical_node_profile: *aci_node_profile_absent + register: nm_remove_node_profile + + - name: Remove node profile (normal mode) again + cisco.aci.aci_l3out_logical_node_profile: *aci_node_profile_absent + register: nm_remove_node_profile_again + + - name: Remove second node profile (check mode) + cisco.aci.aci_l3out_logical_node_profile: &aci_second_node_profile_absent + <<: *aci_info + node_profile: ansible_node_profile2 + l3out: ansible_l3out + tenant: ansible_tenant + state: absent + check_mode: true + register: cm_remove_second_node_profile + + - name: Remove second node profile (normal mode) + cisco.aci.aci_l3out_logical_node_profile: *aci_second_node_profile_absent + register: nm_remove_second_node_profile + + - name: Verify remove_node_profile + assert: + that: + - cm_remove_node_profile is changed + - cm_remove_second_node_profile is changed + - nm_remove_node_profile is changed + - nm_remove_node_profile_again is not changed + - nm_remove_second_node_profile is changed + + # Remove L3out after testing + - name: Remove L3out (normal_mode) + cisco.aci.aci_l3out: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + state: absent + + # Remove Tenant after testing + - name: Remove tenant (normal_mode) + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_tenant + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_static_routes/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_static_routes/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_static_routes/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_static_routes/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_static_routes/tasks/main.yml new file mode 100644 index 000000000..147d180fc --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_static_routes/tasks/main.yml @@ -0,0 +1,258 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Anvitha Jain (@anvitha-jain) + +# 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: Add a new L3Out + aci_l3out: + <<: *aci_info + tenant: ansible_tenant + name: ansible_l3out + description: L3Out for ansible_tenant tenant + domain: ansible_dom + vrf: ansible_vrf + l3protocol: ospf + route_control: export + state: present + + - name: Create L3OUT Logical Node Profile + cisco.aci.aci_l3out_logical_node_profile: &np_present + <<: *aci_info + node_profile: lNode + tenant: ansible_tenant + l3out: ansible_l3out + description: L3Out Logical Node Profile for ansible_tenant tenant + state: present + + - name: Create L3OUT Logical Node + cisco.aci.aci_l3out_logical_node: + <<: *np_present + description: "{{ fake_var | default(omit) }}" + pod_id: 1 + node_id: 101 + router_id: 10.1.0.1 + router_id_as_loopback: 'yes' + register: l3out_logical_node + + - name: Verify l3out_logical_node + assert: + that: + - l3out_logical_node is changed + - l3out_logical_node.previous == [] + - l3out_logical_node.sent.l3extRsNodeL3OutAtt.attributes.rtrId == '10.1.0.1' + - l3out_logical_node.sent.l3extRsNodeL3OutAtt.attributes.rtrIdLoopBack == 'yes' + - l3out_logical_node.sent.l3extRsNodeL3OutAtt.attributes.tDn == 'topology/pod-1/node-101' + + - name: Add static routes (check_mode) + aci_l3out_static_routes: &route_present + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + logical_node: lNode + node_id: 101 + pod_id: 1 + prefix: 10.1.0.1/24 + state: present + check_mode: true + register: cm_add_route + + - name: Add static routes (normal_mode) + aci_l3out_static_routes: + <<: *route_present + register: nm_add_route + + - name: Verify cm_add_route and nm_add_route + assert: + that: + - cm_add_route is changed + - nm_add_route is changed + - cm_add_route.proposed.ipRouteP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-lNode/rsnodeL3OutAtt-[topology/pod-1/node-101]/rt-[10.1.0.1/24]" + - nm_add_route.current[0].ipRouteP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-lNode/rsnodeL3OutAtt-[topology/pod-1/node-101]/rt-[10.1.0.1/24]" + - cm_add_route.proposed.ipRouteP.attributes.ip == "10.1.0.1/24" + - nm_add_route.current[0].ipRouteP.attributes.ip == "10.1.0.1/24" + - nm_add_route.current[0].ipRouteP.attributes.annotation == 'orchestrator:ansible' + + - name: Add static routes again (check_mode) + aci_l3out_static_routes: + <<: *route_present + check_mode: true + register: cm_add_route_again + + - name: Add static routes again (normal_mode) + aci_l3out_static_routes: + <<: *route_present + register: nm_add_route_again + + - name: Verify cm_add_route_again and nm_add_route_again + assert: + that: + - cm_add_route_again is not changed + - nm_add_route_again is not changed + - cm_add_route_again.proposed.ipRouteP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-lNode/rsnodeL3OutAtt-[topology/pod-1/node-101]/rt-[10.1.0.1/24]" + - nm_add_route_again.current[0].ipRouteP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-lNode/rsnodeL3OutAtt-[topology/pod-1/node-101]/rt-[10.1.0.1/24]" + - cm_add_route_again.proposed.ipRouteP.attributes.ip == "10.1.0.1/24" + - nm_add_route_again.current[0].ipRouteP.attributes.ip == "10.1.0.1/24" + + - name: Query system information + aci_system: + <<: *aci_info + id: 1 + state: query + register: version + + - name: Add static routes with bfd + aci_l3out_static_routes: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + logical_node: lNode + node_id: 101 + pod_id: 1 + bfd: bfd + track_policy: test + prefix: 10.1.0.1/24 + state: present + when: version.current.0.topSystem.attributes.version is version('4.2', '>=') + register: nm_add_route_with_bfd + + - name: Verify nm_add_route_with_bfd + assert: + that: + - nm_add_route_with_bfd is changed + - nm_add_route_with_bfd.current[0].ipRouteP.attributes.dn == "uni/tn-ansible_tenant/out-ansible_l3out/lnodep-lNode/rsnodeL3OutAtt-[topology/pod-1/node-101]/rt-[10.1.0.1/24]" + - nm_add_route_with_bfd.current[0].ipRouteP.attributes.ip == "10.1.0.1/24" + - nm_add_route_with_bfd.current[0].ipRouteP.attributes.rtCtrl == "bfd" + - nm_add_route_with_bfd.current[0].ipRouteP.children[0].ipRsRouteTrack.attributes.tDn == "uni/tn-ansible_tenant/tracklist-test" + when: version.current.0.topSystem.attributes.version is version('4.2', '>=') + + - name: Query for a specific MO under l3out + aci_l3out_static_routes: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + logical_node: lNode + node_id: 101 + pod_id: 1 + prefix: 10.1.0.1/24 + state: query + register: query_specific_mo + + - name: Verify query_specific_mo + assert: + that: + - query_specific_mo is not changed + - query_specific_mo.current|length == 1 + - query_specific_mo.current[0].ipRouteP.attributes.ip == "10.1.0.1/24" + + - name: Query all relationships + aci_l3out_static_routes: + <<: *aci_info + tenant: ansible_tenant + state: query + ignore_errors: true + register: query_all_relationships + + - name: Verify query_all_relationships + assert: + that: + - query_all_relationships is not changed + - query_all_relationships.current|length == 1 + - query_all_relationships.current[0].fvTenant.children[0].l3extOut.attributes.name == "ansible_l3out" + - query_all_relationships.current[0].fvTenant.children[0].l3extOut.children[0].l3extLNodeP.attributes.name == "lNode" + - query_all_relationships.current[0].fvTenant.children[0].l3extOut.children[0].l3extLNodeP.children[0].l3extRsNodeL3OutAtt.attributes.rtrId == "10.1.0.1" + - query_all_relationships.current[0].fvTenant.children[0].l3extOut.children[0].l3extLNodeP.children[0].l3extRsNodeL3OutAtt.attributes.rtrIdLoopBack == "yes" + - query_all_relationships.current[0].fvTenant.children[0].l3extOut.children[0].l3extLNodeP.children[0].l3extRsNodeL3OutAtt.children[0].ipRouteP.attributes.ip == "10.1.0.1/24" + - query_all_relationships.current[0].fvTenant.children[0].l3extOut.children[0].l3extLNodeP.children[0].l3extRsNodeL3OutAtt.attributes.tDn == "topology/pod-1/node-101" + + - name: Verify query_all_relationships for bfd + assert: + that: + - query_all_relationships.current[0].fvTenant.children[0].l3extOut.children[0].l3extLNodeP.children[0].l3extRsNodeL3OutAtt.children[0].ipRouteP.attributes.rtCtrl == "bfd" + when: version.current.0.topSystem.attributes.version is version('4.2', '>=') + + - name: Remove static routes (check_mode) + aci_l3out_static_routes: &route_absent + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + logical_node: lNode + node_id: 101 + pod_id: 1 + prefix: 10.1.0.1/24 + state: absent + check_mode: true + register: cm_remove_static_routes + + - name: Remove static routes (normal_mode) + aci_l3out_static_routes: + <<: *route_absent + register: nm_remove_static_routes + + - name: Verify cm_remove_static_routes and nm_remove_static_routes + assert: + that: + - cm_remove_static_routes is changed + - nm_remove_static_routes is changed + - cm_remove_static_routes.proposed == {} + - nm_remove_static_routes.current|length == 0 + + - name: Remove static routes again (check_mode) + aci_l3out_static_routes: + <<: *route_absent + check_mode: true + register: cm_remove_static_routes_again + + - name: Remove static routes again (normal_mode) + aci_l3out_static_routes: + <<: *route_absent + register: nm_remove_static_routes_again + + - name: Verify cm_remove_static_routes_again and nm_remove_static_routes_again + assert: + that: + - cm_remove_static_routes_again is not changed + - nm_remove_static_routes_again is not changed + - cm_remove_static_routes_again.proposed == {} + - nm_remove_static_routes_again.current|length == 0 + + - 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_l3out_static_routes_nexthop/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_static_routes_nexthop/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_static_routes_nexthop/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_static_routes_nexthop/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_static_routes_nexthop/tasks/main.yml new file mode 100644 index 000000000..7d4de1a09 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_l3out_static_routes_nexthop/tasks/main.yml @@ -0,0 +1,149 @@ +# Author: Marcel Zehnder (@maercu) +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# 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") }}' + +# CLEAN ENVIRONMENT +- name: Remove test tenant before we kickoff + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + tenant: ansible_test + 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 + # SETUP ENVIRONMENT + - name: Create domain + cisco.aci.aci_domain: &domain_present + <<: *aci_info + domain: l3outtest + domain_type: l3dom + state: present + + - name: Create tenant + cisco.aci.aci_tenant: &tenant_present + <<: *tenant_absent + state: present + + - name: Configure VRF + cisco.aci.aci_vrf: &vrf_present + <<: *tenant_present + vrf: l3outtest + + - name: Create L3Out + cisco.aci.aci_l3out: + <<: *vrf_present + l3out: l3outtest + domain: l3outtest + route_control: export + + - name: Crete node profile + cisco.aci.aci_l3out_logical_node_profile: &np_present + <<: *tenant_present + l3out: l3outtest + node_profile: NODES + + - name: Add node + cisco.aci.aci_l3out_logical_node: &node_present + <<: *np_present + pod_id: 1 + node_id: 111 + router_id: 111.111.111.111 + + - name: Add static route + cisco.aci.aci_l3out_static_routes: &prefix_present + <<: *np_present + pod_id: 1 + node_id: 111 + prefix: 10.10.0.0/16 + + # MODULE CHECKS + - name: Add a nexthop (check mode) + cisco.aci.aci_l3out_static_routes_nexthop: &nh_present + <<: *prefix_present + nexthop: 1.1.1.1 + check_mode: true + register: cm_add_nh + + - name: Add a nexthop (normal mode) + cisco.aci.aci_l3out_static_routes_nexthop: + <<: *nh_present + register: nm_add_nh + + - name: Verify nm_add_nh + assert: + that: + - cm_add_nh is changed + - nm_add_nh is changed + - cm_add_nh.previous == nm_add_nh.previous == [] + - cm_add_nh.sent.ipNexthopP.attributes.nhAddr == nm_add_nh.sent.ipNexthopP.attributes.nhAddr == '1.1.1.1' + - nm_add_nh.current.0.ipNexthopP.attributes.annotation == 'orchestrator:ansible' + + - name: Add nexthop again, check if idempotency works + cisco.aci.aci_l3out_static_routes_nexthop: + <<: *nh_present + register: add_nh_again + + - name: Verify add_nh_again + assert: + that: + - add_nh_again is not changed + + # ADD ANOTHER NH + - name: Add another nexthop + cisco.aci.aci_l3out_static_routes_nexthop: + <<: *nh_present + nexthop: 1.1.1.2 + + # QUERY ALL NHs + - name: Query all nodes + cisco.aci.aci_l3out_static_routes_nexthop: + <<: *aci_info + state: query + register: query_all_nhs + + - name: Verify query_all_nhs + assert: + that: + - query_all_nhs is not changed + - query_all_nhs.current|length >= 1 + + # QUERY A SPECIFIC NH + - name: Query a specific nexthop + cisco.aci.aci_l3out_static_routes_nexthop: + <<: *nh_present + state: query + register: query_spec_nh + + - name: Verify query_spec_node + assert: + that: + - query_spec_nh is not changed + - query_spec_nh.current|length == 1 + + # REMOVE NH + - name: Remove nexthop + cisco.aci.aci_l3out_static_routes_nexthop: + <<: *nh_present + state: absent + register: remove_nh + + - name: Verify remove_nh + assert: + that: + - remove_nh is changed + - remove_nh.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_lookup_interface_range/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_lookup_interface_range/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_lookup_interface_range/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_lookup_interface_range/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_lookup_interface_range/tasks/main.yml new file mode 100644 index 000000000..5660d0b87 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_lookup_interface_range/tasks/main.yml @@ -0,0 +1,148 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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 + 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: Sinlge string, single range + ansible.builtin.debug: + msg: "{{ item }}" + with_items: "{{ query('cisco.aci.interface_range', '5/0-2') }}" + register: single_string_single_range + +- name: Valid input assertions + assert: + that: + - single_string_single_range.results.0.item == "5/0" + - single_string_single_range.results.1.item == "5/1" + - single_string_single_range.results.2.item == "5/2" + +- name: Single string, multiple range + ansible.builtin.debug: + msg: "{{ item }}" + with_items: "{{ query('cisco.aci.interface_range', '1/1-4,2/10-15') }}" + register: single_string_multiple_interface + +- name: Valid input assertions + assert: + that: + - single_string_multiple_interface.results.0.item == "1/1" + - single_string_multiple_interface.results.1.item == "1/2" + - single_string_multiple_interface.results.2.item == "1/3" + - single_string_multiple_interface.results.3.item == "1/4" + - single_string_multiple_interface.results.4.item == "2/10" + - single_string_multiple_interface.results.5.item == "2/11" + - single_string_multiple_interface.results.6.item == "2/12" + - single_string_multiple_interface.results.7.item == "2/13" + - single_string_multiple_interface.results.8.item == "2/14" + - single_string_multiple_interface.results.9.item == "2/15" + +- name: Single string, single interface + ansible.builtin.debug: + msg: "{{ item }}" + with_items: "{{ query('cisco.aci.interface_range', '1/1') }}" + register: single_string_single_interface_as_range + +- name: Valid input assertions + assert: + that: + - single_string_single_interface_as_range.results.0.item == "1/1" + +- name: Multiple string, single and multiple range + ansible.builtin.debug: + msg: "{{ item }}" + with_items: "{{ query('cisco.aci.interface_range', '1/1-4,1/2/10-15', '2/3/4/5/2', '5/4-5') }}" + register: single_string_mix_ranges + +- name: Valid input assertions + assert: + that: + - single_string_mix_ranges.results.0.item == "1/1" + - single_string_mix_ranges.results.1.item == "1/2" + - single_string_mix_ranges.results.2.item == "1/2/10" + - single_string_mix_ranges.results.3.item == "1/2/11" + - single_string_mix_ranges.results.4.item == "1/2/12" + - single_string_mix_ranges.results.5.item == "1/2/13" + - single_string_mix_ranges.results.6.item == "1/2/14" + - single_string_mix_ranges.results.7.item == "1/2/15" + - single_string_mix_ranges.results.8.item == "1/3" + - single_string_mix_ranges.results.9.item == "1/4" + - single_string_mix_ranges.results.10.item == "2/3/4/5/2" + - single_string_mix_ranges.results.11.item == "5/4" + - single_string_mix_ranges.results.12.item == "5/5" + +- name: Invalid input not matching pattern + ansible.builtin.debug: + msg: "{{ item }}" + with_items: "{{ query('cisco.aci.interface_range', 'not matching pattern') }}" + ignore_errors: true + register: invalid_pattern + +- name: Invalid input end smaller than start + ansible.builtin.debug: + msg: "{{ item }}" + with_items: "{{ query('cisco.aci.interface_range', '1/4-1') }}" + ignore_errors: true + register: invalid_range_order + +- name: Invalid input assertions + assert: + that: + - "'Invalid range inputs,' in invalid_pattern.msg" + - "'Invalid range inputs,' in invalid_range_order.msg" + +- name: Leaf - Disable interfaces + cisco.aci.aci_interface_blacklist: + <<: *aci_info + pod_id: 1 + node_id: 1101 + interface: "{{ item }}" + state: present + with_items: "{{ query('cisco.aci.interface_range', '1/30-32') }}" + register: disable_leaf_int + +- name: Invalid input not matching pattern + ansible.builtin.debug: + msg: "{{ disable_leaf_int }}" + +- name: Valid disable interface assertions + assert: + that: + - disable_leaf_int.results.0.current.0.fabricRsOosPath.attributes.lc == "blacklist" + - disable_leaf_int.results.0.current.0.fabricRsOosPath.attributes.tDn == "topology/pod-1/paths-1101/pathep-[eth1/30]" + - disable_leaf_int.results.1.current.0.fabricRsOosPath.attributes.lc == "blacklist" + - disable_leaf_int.results.1.current.0.fabricRsOosPath.attributes.tDn == "topology/pod-1/paths-1101/pathep-[eth1/31]" + - disable_leaf_int.results.2.current.0.fabricRsOosPath.attributes.lc == "blacklist" + - disable_leaf_int.results.2.current.0.fabricRsOosPath.attributes.tDn == "topology/pod-1/paths-1101/pathep-[eth1/32]" + +- name: Leaf - Enable interfaces + cisco.aci.aci_interface_blacklist: + <<: *aci_info + pod_id: 1 + node_id: 1101 + interface: "{{ item }}" + state: absent + with_items: "{{ query('cisco.aci.interface_range', '1/30-32') }}" + register: enable_leaf_int + +- name: Valid enable interface assertions + assert: + that: + - enable_leaf_int.results.0.current == [] + - enable_leaf_int.results.1.current == [] + - enable_leaf_int.results.2.current == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_node_mgmt_epg/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_node_mgmt_epg/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_node_mgmt_epg/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_node_mgmt_epg/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_node_mgmt_epg/tasks/main.yml new file mode 100644 index 000000000..310fc822b --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_node_mgmt_epg/tasks/main.yml @@ -0,0 +1,251 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Shreyas Srish (@shrsr) + +# 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: Remove node mgmt in_band epg + aci_node_mgmt_epg: + <<: *aci_info + type: in_band + epg: "{{ item }}" + encap: vlan-1 + bd: bd1 + state: absent + loop: + - ansible-inband + - ansible-inband-2 + + - name: Remove node mgmt out_of_band epg + aci_node_mgmt_epg: + <<: *aci_info + type: out_of_band + epg: "{{ item }}" + state: absent + loop: + - ansible-outofband + - ansible-outofband-2 + + # Add operations + - name: Add node mgmt in_band epg in check mode + aci_node_mgmt_epg: + <<: *aci_info + type: in_band + epg: ansible-inband + encap: vlan-1 + bd: bd1 + state: present + check_mode: true + register: add_cm_inband + + - name: Add node mgmt out_of_band epg in check mode + aci_node_mgmt_epg: + <<: *aci_info + type: out_of_band + epg: ansible-outofband + state: present + check_mode: true + register: add_cm_outofband + + - name: Add node mgmt in_band epg in normal mode + aci_node_mgmt_epg: + <<: *aci_info + type: in_band + epg: ansible-inband + encap: vlan-1 + bd: bd1 + state: present + register: add_nm_inband + + - name: Add node mgmt out_of_band epg in normal mode + aci_node_mgmt_epg: + <<: *aci_info + type: out_of_band + epg: ansible-outofband + state: present + register: add_nm_outofband + + - name: Add node mgmt in_band epg in normal mode again + aci_node_mgmt_epg: + <<: *aci_info + type: in_band + epg: ansible-inband + encap: vlan-1 + bd: bd1 + state: present + register: add_nm_inband_again + + - name: Add node mgmt out_of_band epg in normal mode again + aci_node_mgmt_epg: + <<: *aci_info + type: out_of_band + epg: ansible-outofband + state: present + register: add_nm_outofband_again + + - name: Add another node mgmt in_band epg in normal mode + aci_node_mgmt_epg: + <<: *aci_info + type: in_band + epg: ansible-inband-2 + encap: vlan-2 + bd: bd2 + state: present + register: add_nm_inband_2 + + - name: Add another node mgmt out_of_band epg in normal mode + aci_node_mgmt_epg: + <<: *aci_info + type: out_of_band + epg: ansible-outofband-2 + state: present + register: add_nm_outofband_2 + + - name: Add another node mgmt in_band epg in normal mode with change made to bd + aci_node_mgmt_epg: + <<: *aci_info + type: in_band + epg: ansible-inband-2 + encap: vlan-2 + bd: bd4 + state: present + register: add_nm_inband_bd4 + + - name: Add another node mgmt in_band epg in normal mode with change made to encap + aci_node_mgmt_epg: + <<: *aci_info + type: in_band + epg: ansible-inband-2 + encap: vlan-104 + bd: bd4 + state: present + register: add_nm_inband_encap4 + + - name: Verify add operations + assert: + that: + - add_cm_inband is changed + - add_cm_inband.sent.mgmtInB.attributes.name == 'ansible-inband' + - add_cm_inband.sent.mgmtInB.children.0.mgmtRsMgmtBD.attributes.tnFvBDName == 'bd1' + - add_cm_outofband is changed + - add_cm_outofband.sent.mgmtOoB.attributes.name == 'ansible-outofband' + - add_nm_inband is changed + - add_nm_inband.current.0.mgmtInB.attributes.name == 'ansible-inband' + - add_nm_inband.current.0.mgmtInB.children.0.mgmtRsMgmtBD.attributes.tnFvBDName == 'bd1' + - add_nm_inband.current.0.mgmtInB.attributes.annotation == 'orchestrator:ansible' + - add_nm_outofband is changed + - add_nm_outofband.current.0.mgmtOoB.attributes.name == 'ansible-outofband' + - add_nm_inband_again is not changed + - add_nm_inband_again.current.0.mgmtInB.attributes.name == 'ansible-inband' + - add_nm_outofband_again is not changed + - add_nm_outofband_again.current.0.mgmtOoB.attributes.name == 'ansible-outofband' + - add_nm_inband_2 is changed + - add_nm_inband_2.current.0.mgmtInB.attributes.name == 'ansible-inband-2' + - add_nm_inband_2.current.0.mgmtInB.children.0.mgmtRsMgmtBD.attributes.tnFvBDName == 'bd2' + - add_nm_outofband_2 is changed + - add_nm_outofband_2.current.0.mgmtOoB.attributes.name == 'ansible-outofband-2' + - add_nm_inband_bd4 is changed + - add_nm_inband_bd4.current.0.mgmtInB.children.0.mgmtRsMgmtBD.attributes.tnFvBDName == 'bd4' + - add_nm_inband_encap4 is changed + - add_nm_inband_encap4.current.0.mgmtInB.attributes.encap == 'vlan-104' + + # Query operations + - name: Query node mgmt in_band epg + aci_node_mgmt_epg: + <<: *aci_info + type: in_band + epg: ansible-inband + encap: vlan-1 + bd: bd1 + state: query + register: query_inband + + - name: Query node mgmt out_of_band epg + aci_node_mgmt_epg: + <<: *aci_info + type: out_of_band + epg: ansible-outofband + state: query + register: query_outofband + + - name: Query all in band + aci_node_mgmt_epg: + <<: *aci_info + type: in_band + state: query + register: query_all_inband + + - name: Query all out of band + aci_node_mgmt_epg: + <<: *aci_info + type: out_of_band + state: query + register: query_all_outofband + + - name: Verify query operations + assert: + that: + - query_inband is not changed + - query_inband.current.0.mgmtInB.attributes.name == 'ansible-inband' + - query_inband.current.0.mgmtInB.children.0.mgmtRsMgmtBD.attributes.tnFvBDName == 'bd1' + - query_outofband is not changed + - query_outofband.current.0.mgmtOoB.attributes.name == 'ansible-outofband' + - query_all_inband.current.0.mgmtMgmtP.children | length == 2 + - query_all_outofband.current.0.mgmtMgmtP.children | length == 3 + + # Remove operations + - name: Remove node mgmt in_band epg + aci_node_mgmt_epg: + <<: *aci_info + type: in_band + epg: ansible-inband-2 + state: absent + register: remove_inband_2 + + - name: Remove node mgmt out_of_band epg + aci_node_mgmt_epg: + <<: *aci_info + type: out_of_band + epg: ansible-outofband-2 + state: absent + register: remove_outofband_2 + + - name: Remove node mgmt in_band epg again + aci_node_mgmt_epg: + <<: *aci_info + type: in_band + epg: ansible-inband-2 + state: absent + register: remove_inband_2_again + + - name: Verify remove operations + assert: + that: + - remove_inband_2 is changed + - remove_inband_2.previous.0.mgmtInB.attributes.name == 'ansible-inband-2' + - remove_outofband_2 is changed + - remove_outofband_2.previous.0.mgmtOoB.attributes.name == 'ansible-outofband-2' + - remove_inband_2_again is not changed + - remove_inband_2_again.previous == []
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_ntp_policy/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_ntp_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_ntp_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_ntp_policy/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_ntp_policy/tasks/main.yml new file mode 100644 index 000000000..ddc5b69e6 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_ntp_policy/tasks/main.yml @@ -0,0 +1,209 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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 any pre-existing NTP policy + cisco.aci.aci_ntp_policy: &policy_absent + <<: *aci_info + name: ansible_ntp_policy + state: absent + +# ADD NTP POLICY +- name: Add NTP policy (check_mode) + cisco.aci.aci_ntp_policy: &policy_present + <<: *aci_info + name: ansible_ntp_policy + description: 'Ansible test policy' + admin_state: enabled + server_state: disabled + auth_state: disabled + state: present + check_mode: true + register: cm_add_policy + +- name: Add NTP policy (normal mode) + cisco.aci.aci_ntp_policy: + <<: *policy_present + register: nm_add_policy + +- name: Add NTP policy again (check mode) + cisco.aci.aci_ntp_policy: + <<: *policy_present + check_mode: true + register: cm_add_policy_again + +- name: Add NTP policy again (normal mode) + cisco.aci.aci_ntp_policy: + <<: *policy_present + register: nm_add_policy_again + +- name: Verify add policy + assert: + that: + - cm_add_policy is changed + - nm_add_policy is changed + - nm_add_policy.current.0.datetimePol.attributes.dn == 'uni/fabric/time-ansible_ntp_policy' + - nm_add_policy.current.0.datetimePol.attributes.name == 'ansible_ntp_policy' + - nm_add_policy.current.0.datetimePol.attributes.descr == 'Ansible test policy' + - nm_add_policy.current.0.datetimePol.attributes.adminSt == 'enabled' + - nm_add_policy.current.0.datetimePol.attributes.serverState == 'disabled' + - nm_add_policy.current.0.datetimePol.attributes.authSt == 'disabled' + - cm_add_policy_again is not changed + - nm_add_policy_again is not changed + - nm_add_policy_again.current.0.datetimePol.attributes.dn == 'uni/fabric/time-ansible_ntp_policy' + - nm_add_policy_again.current.0.datetimePol.attributes.name == 'ansible_ntp_policy' + - nm_add_policy_again.current.0.datetimePol.attributes.descr == 'Ansible test policy' + - nm_add_policy_again.current.0.datetimePol.attributes.adminSt == 'enabled' + - nm_add_policy_again.current.0.datetimePol.attributes.serverState == 'disabled' + - nm_add_policy_again.current.0.datetimePol.attributes.authSt == 'disabled' + +# MODIFY POLICY +- name: Modify policy (check_mode) + cisco.aci.aci_ntp_policy: &policy_changed + <<: *aci_info + name: ansible_ntp_policy + description: 'Ansible updated test policy' + admin_state: enabled + server_state: enabled + auth_state: disabled + state: present + check_mode: true + register: cm_modify_policy + +- name: Modify policy (normal mode) + cisco.aci.aci_ntp_policy: + <<: *policy_changed + register: nm_modify_policy + +- name: Modify policy again (check mode) + cisco.aci.aci_ntp_policy: + <<: *policy_changed + check_mode: true + register: cm_modify_policy_again + +- name: Modify policy again (normal mode) + cisco.aci.aci_ntp_policy: + <<: *policy_changed + register: nm_modify_policy_again + +- name: Verify modify policy + assert: + that: + - cm_modify_policy is changed + - nm_modify_policy is changed + - nm_modify_policy.current.0.datetimePol.attributes.dn == 'uni/fabric/time-ansible_ntp_policy' + - nm_modify_policy.current.0.datetimePol.attributes.name == 'ansible_ntp_policy' + - nm_modify_policy.current.0.datetimePol.attributes.descr == 'Ansible updated test policy' + - nm_modify_policy.current.0.datetimePol.attributes.adminSt == 'enabled' + - nm_modify_policy.current.0.datetimePol.attributes.serverState == 'enabled' + - nm_modify_policy.current.0.datetimePol.attributes.authSt == 'disabled' + - cm_modify_policy_again is not changed + - nm_modify_policy_again is not changed + - nm_modify_policy_again.current.0.datetimePol.attributes.dn == 'uni/fabric/time-ansible_ntp_policy' + - nm_modify_policy_again.current.0.datetimePol.attributes.name == 'ansible_ntp_policy' + - nm_modify_policy_again.current.0.datetimePol.attributes.descr == 'Ansible updated test policy' + - nm_modify_policy_again.current.0.datetimePol.attributes.adminSt == 'enabled' + - nm_modify_policy_again.current.0.datetimePol.attributes.serverState == 'enabled' + - nm_modify_policy_again.current.0.datetimePol.attributes.authSt == 'disabled' + +# QUERY ALL POLICIES +- name: Query all policies (check_mode) + cisco.aci.aci_ntp_policy: &policy_query_all + <<: *aci_info + state: query + check_mode: true + register: cm_query_all_policies + +- name: Query all policies (normal mode) + cisco.aci.aci_ntp_policy: + <<: *policy_query_all + register: nm_query_all_policies + +- name: Verify query_all_policies + assert: + that: + - cm_query_all_policies is not changed + - nm_query_all_policies is not changed + +# QUERY OUR USER +- name: Query our policy (check_mode) + cisco.aci.aci_ntp_policy: + <<: *policy_query_all + name: ansible_ntp_policy + check_mode: true + register: cm_query_policy + +- name: Query our policy (normal mode) + cisco.aci.aci_ntp_policy: + <<: *policy_query_all + name: ansible_ntp_policy + register: nm_query_policy + +- name: Verify query_policy + assert: + that: + - cm_query_policy is not changed + - nm_query_policy is not changed + - cm_query_policy == nm_query_policy + - nm_query_policy.current.0.datetimePol.attributes.dn == 'uni/fabric/time-ansible_ntp_policy' + - nm_query_policy.current.0.datetimePol.attributes.name == 'ansible_ntp_policy' + - nm_query_policy.current.0.datetimePol.attributes.descr == 'Ansible updated test policy' + - nm_query_policy.current.0.datetimePol.attributes.adminSt == 'enabled' + - nm_query_policy.current.0.datetimePol.attributes.serverState == 'enabled' + - nm_query_policy.current.0.datetimePol.attributes.authSt == 'disabled' + +# REMOVE POLICY +- name: Remove policy (check_mode) + cisco.aci.aci_ntp_policy: + <<: *policy_absent + check_mode: true + register: cm_remove_policy + +- name: Remove policy (normal mode) + cisco.aci.aci_ntp_policy: + <<: *policy_absent + register: nm_remove_policy + +- name: Remove policy again (check_mode) + cisco.aci.aci_ntp_policy: + <<: *policy_absent + check_mode: true + register: cm_remove_policy_again + +- name: Remove policy again (normal mode) + cisco.aci.aci_ntp_policy: + <<: *policy_absent + register: nm_remove_policy_again + +- name: Verify remove_policy + assert: + that: + - cm_remove_policy is changed + - nm_remove_policy is changed + - nm_remove_policy.current == [] + - nm_remove_policy.previous.0.datetimePol.attributes.dn == 'uni/fabric/time-ansible_ntp_policy' + - nm_remove_policy.previous.0.datetimePol.attributes.name == 'ansible_ntp_policy' + - nm_remove_policy.previous.0.datetimePol.attributes.descr == 'Ansible updated test policy' + - nm_remove_policy.previous.0.datetimePol.attributes.adminSt == 'enabled' + - nm_remove_policy.previous.0.datetimePol.attributes.serverState == 'enabled' + - nm_remove_policy.previous.0.datetimePol.attributes.authSt == 'disabled' + - cm_remove_policy_again is not changed + - nm_remove_policy_again is not changed diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_ntp_server/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_ntp_server/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_ntp_server/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_ntp_server/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_ntp_server/tasks/main.yml new file mode 100644 index 000000000..15c6799cb --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_ntp_server/tasks/main.yml @@ -0,0 +1,237 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, 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 any pre-existing NTP policy + cisco.aci.aci_ntp_policy: &policy_absent + <<: *aci_info + name: ansible_ntp_policy + state: absent + +# ADD NTP POLICY +- name: Add NTP policy + cisco.aci.aci_ntp_policy: + <<: *aci_info + name: ansible_ntp_policy + description: 'Ansible test policy' + admin_state: enabled + server_state: disabled + auth_state: disabled + state: present + +# ADD NTP SERVER +- name: Add NTP server (check mode) + cisco.aci.aci_ntp_server: &server_present + <<: *aci_info + ntp_policy: ansible_ntp_policy + ntp_server: 10.20.30.40 + description: 'Ansible test server' + min_poll: 5 + max_poll: 10 + preferred: true + state: present + check_mode: true + register: cm_add_server + +- name: Add NTP server (normal mode) + cisco.aci.aci_ntp_server: + <<: *server_present + register: nm_add_server + +- name: Add NTP server again (check mode) + cisco.aci.aci_ntp_server: + <<: *server_present + check_mode: true + register: cm_add_server_again + +- name: Add NTP server again (normal mode) + cisco.aci.aci_ntp_server: + <<: *server_present + register: nm_add_server_again + +- name: Verify add server + assert: + that: + - cm_add_server is changed + - nm_add_server is changed + - nm_add_server.current.0.datetimeNtpProv.attributes.dn == 'uni/fabric/time-ansible_ntp_policy/ntpprov-10.20.30.40' + - nm_add_server.current.0.datetimeNtpProv.attributes.name == '10.20.30.40' + - nm_add_server.current.0.datetimeNtpProv.attributes.descr == 'Ansible test server' + - nm_add_server.current.0.datetimeNtpProv.attributes.minPoll == '5' + - nm_add_server.current.0.datetimeNtpProv.attributes.maxPoll == '10' + - nm_add_server.current.0.datetimeNtpProv.attributes.preferred == 'yes' + - cm_add_server_again is not changed + - nm_add_server_again is not changed + - nm_add_server_again.current.0.datetimeNtpProv.attributes.dn == 'uni/fabric/time-ansible_ntp_policy/ntpprov-10.20.30.40' + - nm_add_server_again.current.0.datetimeNtpProv.attributes.name == '10.20.30.40' + - nm_add_server_again.current.0.datetimeNtpProv.attributes.descr == 'Ansible test server' + - nm_add_server_again.current.0.datetimeNtpProv.attributes.minPoll == '5' + - nm_add_server_again.current.0.datetimeNtpProv.attributes.maxPoll == '10' + - nm_add_server_again.current.0.datetimeNtpProv.attributes.preferred == 'yes' + +# MODIFY SERVER +- name: Modify NTP server (check mode) + cisco.aci.aci_ntp_server: &server_changed + <<: *aci_info + ntp_policy: ansible_ntp_policy + ntp_server: 10.20.30.40 + description: 'Ansible test server' + min_poll: 6 + max_poll: 9 + preferred: true + epg_type: oob + epg_name: default + state: present + check_mode: true + register: cm_modify_server + +- name: Modify server (normal mode) + cisco.aci.aci_ntp_server: + <<: *server_changed + register: nm_modify_server + +- name: Modify server again (check mode) + cisco.aci.aci_ntp_server: + <<: *server_changed + check_mode: true + register: cm_modify_server_again + +- name: Modify server again (normal mode) + cisco.aci.aci_ntp_server: + <<: *server_changed + register: nm_modify_server_again + +- name: Verify modify policy + assert: + that: + - cm_modify_server is changed + - nm_modify_server is changed + - nm_modify_server.current.0.datetimeNtpProv.attributes.dn == 'uni/fabric/time-ansible_ntp_policy/ntpprov-10.20.30.40' + - nm_modify_server.current.0.datetimeNtpProv.attributes.name == '10.20.30.40' + - nm_modify_server.current.0.datetimeNtpProv.attributes.descr == 'Ansible test server' + - nm_modify_server.current.0.datetimeNtpProv.attributes.minPoll == '6' + - nm_modify_server.current.0.datetimeNtpProv.attributes.maxPoll == '9' + - nm_modify_server.current.0.datetimeNtpProv.attributes.preferred == 'yes' + - nm_modify_server.current.0.datetimeNtpProv.children.0.datetimeRsNtpProvToEpg.attributes.tDn == 'uni/tn-mgmt/mgmtp-default/oob-default' + - cm_modify_server_again is not changed + - nm_modify_server_again is not changed + - nm_modify_server_again.current.0.datetimeNtpProv.attributes.dn == 'uni/fabric/time-ansible_ntp_policy/ntpprov-10.20.30.40' + - nm_modify_server_again.current.0.datetimeNtpProv.attributes.name == '10.20.30.40' + - nm_modify_server_again.current.0.datetimeNtpProv.attributes.descr == 'Ansible test server' + - nm_modify_server_again.current.0.datetimeNtpProv.attributes.minPoll == '6' + - nm_modify_server_again.current.0.datetimeNtpProv.attributes.maxPoll == '9' + - nm_modify_server_again.current.0.datetimeNtpProv.attributes.preferred == 'yes' + - nm_modify_server_again.current.0.datetimeNtpProv.children.0.datetimeRsNtpProvToEpg.attributes.tDn == 'uni/tn-mgmt/mgmtp-default/oob-default' + +# QUERY ALL POLICIES +- name: Query all servers (check_mode) + cisco.aci.aci_ntp_server: &server_query_all + <<: *aci_info + ntp_policy: ansible_ntp_policy + state: query + check_mode: true + register: cm_query_all_servers + +- name: Query all servers (normal mode) + cisco.aci.aci_ntp_server: + <<: *server_query_all + register: nm_query_all_servers + +- name: Verify query_all_servers + assert: + that: + - cm_query_all_servers is not changed + - nm_query_all_servers is not changed + +# QUERY OUR SERVER +- name: Query our server (check_mode) + cisco.aci.aci_ntp_server: + <<: *server_query_all + ntp_server: 10.20.30.40 + check_mode: true + register: cm_query_server + +- name: Query our server (normal mode) + cisco.aci.aci_ntp_server: + <<: *server_query_all + ntp_server: 10.20.30.40 + register: nm_query_server + +- name: Verify query_server + assert: + that: + - cm_query_server is not changed + - nm_query_server is not changed + - cm_query_server == nm_query_server + - nm_query_server.current.0.datetimeNtpProv.attributes.dn == 'uni/fabric/time-ansible_ntp_policy/ntpprov-10.20.30.40' + - nm_query_server.current.0.datetimeNtpProv.attributes.name == '10.20.30.40' + - nm_query_server.current.0.datetimeNtpProv.attributes.descr == 'Ansible test server' + - nm_query_server.current.0.datetimeNtpProv.attributes.minPoll == '6' + - nm_query_server.current.0.datetimeNtpProv.attributes.maxPoll == '9' + - nm_query_server.current.0.datetimeNtpProv.attributes.preferred == 'yes' + +# REMOVE SERVER +- name: Remove server (check mode) + cisco.aci.aci_ntp_server: &server_absent + <<: *aci_info + ntp_policy: ansible_ntp_policy + ntp_server: 10.20.30.40 + state: absent + check_mode: true + register: cm_remove_server + +- name: Remove server (normal mode) + cisco.aci.aci_ntp_server: + <<: *server_absent + register: nm_remove_server + +- name: Remove server again (check mode) + cisco.aci.aci_ntp_server: + <<: *server_absent + check_mode: true + register: cm_remove_server_again + +- name: Remove server again (normal mode) + cisco.aci.aci_ntp_server: + <<: *server_absent + register: nm_remove_server_again + +- name: Verify remove_server + assert: + that: + - cm_remove_server is changed + - nm_remove_server is changed + - nm_remove_server.current == [] + - nm_remove_server.previous.0.datetimeNtpProv.attributes.dn == 'uni/fabric/time-ansible_ntp_policy/ntpprov-10.20.30.40' + - nm_remove_server.previous.0.datetimeNtpProv.attributes.name == '10.20.30.40' + - nm_remove_server.previous.0.datetimeNtpProv.attributes.descr == 'Ansible test server' + - nm_remove_server.previous.0.datetimeNtpProv.attributes.minPoll == '6' + - nm_remove_server.previous.0.datetimeNtpProv.attributes.maxPoll == '9' + - nm_remove_server.previous.0.datetimeNtpProv.attributes.preferred == 'yes' + - cm_remove_server_again is not changed + - nm_remove_server_again is not changed + +# CLEAN UP +- name: Remove NTP Policy + cisco.aci.aci_ntp_policy: + <<: *aci_info + name: ansible_ntp_policy + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..1c503c5f2 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/error_handling.yml @@ -0,0 +1,230 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + + +# PROVOKE ERRORS +- name: Error on name resolution + cisco.aci.aci_rest: + host: foo.bar.cisco.com + 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 + path: /api/mo/uni.json + method: post + content: + fvTenant: + attributes: + name: ansible_test + ignore_errors: true + register: error_on_name_resolution + +- name: Verify error_on_name_resolution + 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:") + - "'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 + 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: debug + method: post + content: + fvTenant: + attributes: + name: ansible_test + ignore_errors: true + register: error_on_missing_required_param + +- name: Verify error_on_missing_required_param + assert: + that: + - error_on_missing_required_param is failed + - 'error_on_missing_required_param.msg == "missing required arguments: path"' + - "'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 + 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: debug + path: /api/mo/uni/tn-ansible_test.json + method: post + content: + fvTenant: + children: + ignore_errors: true + register: error_on_missing_attributes + +- name: Verify error_on_missing_attributes + assert: + that: + - error_on_missing_attributes is failed + - error_on_missing_attributes.method == 'POST' + - "error_on_missing_attributes.msg == 'APIC Error 400: invalid data at line \\'1\\'. Attributes are missing, tag \\'attributes\\' must be specified first, before any other tag'" + - 'error_on_missing_attributes.response == "HTTP Error 400: Bad Request"' + - error_on_missing_attributes.status == 400 + - "'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 + 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: debug + path: /api/mo/uni.json + method: post + content: + fvTenant: + attributes: + name: ansible_test + descr: This is an [invalid] description + ignore_errors: true + register: error_on_input_validation + +- name: Verify error_on_input_validation + assert: + that: + - error_on_input_validation is failed + - error_on_input_validation.method == 'POST' + - "error_on_input_validation.msg == 'APIC Error 801: property descr of tn-ansible_test failed validation for value \\'This is an [invalid] description\\''" + - 'error_on_input_validation.response == "HTTP Error 400: Bad Request"' + - error_on_input_validation.status == 400 + - "'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 + 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: debug + path: /api/mo/uni.json + method: post + content: + fvTenant: + attributes: + name: ansible_test + description: This is an "invalid" description + ignore_errors: true + register: error_on_invalid_attributes + +- name: Verify error_on_invalid_attributes + assert: + that: + - error_on_invalid_attributes is failed + - error_on_invalid_attributes.method == 'POST' + - "error_on_invalid_attributes.msg == 'APIC Error 400: unknown attribute \\'description\\' in element \\'fvTenant\\''" + - 'error_on_invalid_attributes.response == "HTTP Error 400: Bad Request"' + - error_on_invalid_attributes.status == 400 + - "'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 + 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: debug + path: /api/mo/uni.json + method: post + content: + fvFoobar: + attributes: + name: ansible_test + ignore_errors: true + register: error_on_invalid_object + +- name: Verify error_on_invalid_object + assert: + that: + - error_on_invalid_object is failed + - error_on_invalid_object.method == 'POST' + - "error_on_invalid_object.msg == 'APIC Error 122: unknown managed object class fvFoobar'" + - 'error_on_invalid_object.response == "HTTP Error 400: Bad Request"' + - error_on_invalid_object.status == 400 + - "'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 +# Avoiding error: TypeError: must be str, not bytes +- name: Add user certificate + cisco.aci.aci_aaa_user_certificate: + 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: '{{ aci_username }}' + name: admin + certificate: "{{ lookup('file', 'pki/admin.crt') }}" + state: present + register: cm_add_cert + +- name: Create tenant + cisco.aci.aci_rest: &tenant + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + certificate_name: admin + private_key: "{{ lookup('file', 'pki/admin.key') }}" + 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="test_tenant_cert_auth"/> + +- name: Delete tenant + cisco.aci.aci_rest: + <<: *tenant + content: + <fvTenant name="test_tenant_cert_auth" status="deleted"/>
\ No newline at end of file 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 new file mode 100644 index 000000000..dd27525f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/json_inline.yml @@ -0,0 +1,166 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + + +# CLEAN ENVIRONMENT +- name: Remove tenant + cisco.aci.aci_rest: &tenant_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") }}' + path: /api/mo/uni/tn-[ansible_test].json + method: delete + +# ADD TENANT +- name: Add tenant (normal mode) + cisco.aci.aci_rest: &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: '{{ aci_output_level | default("info") }}' + path: /api/mo/uni.json + method: post + content: + { + "fvTenant": { + "attributes": { + "name": "ansible_test" + } + } + } + delegate_to: localhost + 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 + assert: + that: + - nm_add_tenant is changed + - nm_add_tenant_again is not changed + +# CHANGE TENANT +- name: Change description of tenant (normal mode) + cisco.aci.aci_rest: &tenant_changed + 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.json + method: post + content: + { + "fvTenant": { + "attributes": { + "descr": "Ansible test tenant", + "name": "ansible_test" + } + } + } + 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 + assert: + that: + - nm_add_tenant_descr is changed + - nm_add_tenant_descr_again is not changed + +# 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 + assert: + that: + - nm_add_tenant_again_no_descr is not changed + +# QUERY ALL TENANTS +- name: Query all tenants (normal mode) + cisco.aci.aci_rest: &tenant_query_all + 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/tn-[ansible_test].json + method: get + delegate_to: localhost + register: nm_query_all_tenants + +- name: Verify query_all_tenants + assert: + that: + - nm_query_all_tenants is not changed + +# QUERY A TENANT +- name: Query our tenant + cisco.aci.aci_rest: &tenant_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") }}' + path: /api/mo/uni/tn-[ansible_test].json + method: get + delegate_to: localhost + register: nm_query_tenant + +- name: Verify query_tenant + assert: + that: + - nm_query_tenant is not changed + +# 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 + assert: + that: + - nm_remove_tenant is changed + - nm_remove_tenant_again is not changed + +# 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 + assert: + that: + - nm_query_non_tenant is not changed 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 new file mode 100644 index 000000000..bbbd57cd4 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/json_string.yml @@ -0,0 +1,157 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + + +# CLEAN ENVIRONMENT +- name: Remove tenant + cisco.aci.aci_rest: &tenant_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") }}' + path: /api/mo/uni/tn-[ansible_test].json + method: delete + +# ADD TENANT +- name: Add tenant (normal mode) + cisco.aci.aci_rest: &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: '{{ aci_output_level | default("info") }}' + path: /api/mo/uni.json + method: post + content: | + { + "fvTenant": { + "attributes": { + "name": "ansible_test" + } + } + } + output_path: "/tmp/ansible_output_file.log" + register: nm_add_tenant + +- name: Add tenant again (normal mode) + cisco.aci.aci_rest: *tenant_present + register: nm_add_tenant_again + +- name: Verify add_tenant + assert: + that: + - nm_add_tenant is changed + - nm_add_tenant_again is not changed + +# CHANGE TENANT +- name: Change description of tenant (normal mode) + cisco.aci.aci_rest: &tenant_changed + 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.json + method: post + content: | + { + "fvTenant": { + "attributes": { + "descr": "Ansible test tenant", + "name": "ansible_test" + } + } + } + register: nm_add_tenant_descr + +- name: Change description of tenant again (normal mode) + cisco.aci.aci_rest: *tenant_changed + register: nm_add_tenant_descr_again + +- name: Verify add_tenant_descr + assert: + that: + - nm_add_tenant_descr is changed + - nm_add_tenant_descr_again is not changed + +# ADD TENANT AGAIN +- name: Add tenant again with no description (normal mode) + cisco.aci.aci_rest: *tenant_present + register: nm_add_tenant_again_no_descr + +- name: Verify add_tenant_again_no_descr + assert: + that: + - nm_add_tenant_again_no_descr is not changed + +# QUERY ALL TENANTS +- name: Query all tenants (normal mode) + cisco.aci.aci_rest: &tenant_query_all + 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/tn-[ansible_test].json + method: get + register: nm_query_all_tenants + +- name: Verify query_all_tenants + assert: + that: + - nm_query_all_tenants is not changed + +# QUERY A TENANT +- name: Query our tenant + cisco.aci.aci_rest: &tenant_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") }}' + path: /api/mo/uni/tn-[ansible_test].json + method: get + register: nm_query_tenant + +- name: Verify query_tenant + assert: + that: + - nm_query_tenant is not changed + +# REMOVE TENANT +- name: Remove tenant (normal mode) + cisco.aci.aci_rest: *tenant_absent + register: nm_remove_tenant + +- name: Remove tenant again (normal mode) + cisco.aci.aci_rest: *tenant_absent + register: nm_remove_tenant_again + +- name: Verify remove_tenant + assert: + that: + - nm_remove_tenant is changed + - nm_remove_tenant_again is not changed + +# QUERY NON-EXISTING TENANT +- name: Query non-existing tenant (normal mode) + cisco.aci.aci_rest: *tenant_query + register: nm_query_non_tenant + +- name: Verify query_non_tenant + assert: + that: + - nm_query_non_tenant is not changed 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 new file mode 100644 index 000000000..0952dd85b --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/main.yml @@ -0,0 +1,31 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com> +# Copyright: (c) 2020, Cindy Zhao (@cizhao) <cizhao@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 + +- include_tasks: yaml_inline.yml + tags: yaml_inline + +- include_tasks: yaml_string.yml + tags: yaml_string + +- include_tasks: json_inline.yml + tags: json_inline + +- include_tasks: json_string.yml + tags: json_string + +- include_tasks: xml_string.yml + tags: xml_string + +- include_tasks: error_handling.yml + tags: error_handling + +- include_tasks: xml_file.yml + tags: xml_file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/pki/admin.crt b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/pki/admin.crt new file mode 100644 index 000000000..cfac5531e --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/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_rest/tasks/pki/admin.key b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/pki/admin.key new file mode 100644 index 000000000..63bb00cc0 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/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_rest/tasks/xml_file.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_file.yml new file mode 100644 index 000000000..cdde037c4 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_file.yml @@ -0,0 +1,214 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, Sabari Jaganathan (@sajagana) <sajagana@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# 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("debug") }}' + output_path: "/tmp/ansible_output_file.log" + +- name: Ensure tenant does not exists using ans_test_delete xml template + cisco.aci.aci_rest: + <<: *aci_info + path: /api/mo/uni.xml + src: "./targets/aci_rest/tasks/xml_files/tn-ans_test_delete.xml" + method: post + +- name: Add tenant using ans_test_create xml template file with check mode + cisco.aci.aci_rest: + <<: *aci_info + path: /api/mo/uni.xml + src: "./targets/aci_rest/tasks/xml_files/tn-ans_test_create.xml" + method: post + check_mode: true + register: cm_add_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 + +- name: Add tenant using ans_test_create xml template file with normal mode + cisco.aci.aci_rest: + <<: *aci_info + path: /api/mo/uni.xml + src: "./targets/aci_rest/tasks/xml_files/tn-ans_test_create.xml" + method: post + register: nm_add_tenant + +- name: Assertions check for add tenant using ans_test_create xml template file with normal mode + assert: + that: + - nm_add_tenant is changed + - nm_add_tenant.imdata.0.fvTenant.attributes.name == "ans_test_create" + - nm_add_tenant.imdata.0.fvTenant.attributes.descr == "ans_test_create tenant created successfully" + - nm_add_tenant.imdata.0.fvTenant.attributes.dn == "uni/tn-ans_test_create" + - nm_add_tenant.imdata.0.fvTenant.children != [] + +- name: Add tenant using ans_test_create xml template file with normal mode - idempotency works + cisco.aci.aci_rest: + <<: *aci_info + path: /api/mo/uni.xml + src: "./targets/aci_rest/tasks/xml_files/tn-ans_test_create.xml" + method: post + register: idempotency_nm_add_tenant + +- name: Idempotency assertions check for add tenant using ans_test_create xml template file with normal mode + assert: + that: + - idempotency_nm_add_tenant is not changed + +- name: Query ans_test_create tenant using query string after the create + cisco.aci.aci_rest: + <<: *aci_info + path: "/api/node/mo/uni/tn-ans_test_create.json?query-target=self" + method: get + register: query_ans_test_create + +- name: Assertions check for querying ans_test_create tenant using query string after the create + assert: + that: + - query_ans_test_create is not changed + - query_ans_test_create.imdata != [] + - query_ans_test_create.imdata.0.fvTenant.attributes.name == "ans_test_create" + - query_ans_test_create.imdata.0.fvTenant.attributes.descr == "ans_test_create tenant created successfully" + - query_ans_test_create.imdata.0.fvTenant.attributes.dn == "uni/tn-ans_test_create" + +- name: Update tenant description using ans_test_update xml template file with check mode + cisco.aci.aci_rest: + <<: *aci_info + path: /api/mo/uni.xml + src: "./targets/aci_rest/tasks/xml_files/tn-ans_test_update.xml" + method: post + check_mode: true + register: cm_update_tenant + +- 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 + +- name: Update tenant description using ans_test_update xml template file with normal mode + cisco.aci.aci_rest: + <<: *aci_info + path: /api/mo/uni.xml + src: "./targets/aci_rest/tasks/xml_files/tn-ans_test_update.xml" + method: post + register: nm_update_tenant + +- name: Assertions check for update tenant description using ans_test_update xml template file with normal mode + assert: + that: + - nm_update_tenant is changed + - nm_update_tenant.imdata.0.fvTenant.attributes.name == "ans_test_create" + - nm_update_tenant.imdata.0.fvTenant.attributes.descr == "ans_test_create tenant updated successfully" + - nm_update_tenant.imdata.0.fvTenant.attributes.dn == "uni/tn-ans_test_create" + +- name: Update tenant description using ans_test_update xml template file with normal mode - idempotency works + cisco.aci.aci_rest: + <<: *aci_info + path: /api/mo/uni.xml + src: "./targets/aci_rest/tasks/xml_files/tn-ans_test_update.xml" + method: post + register: idempotency_nm_update_tenant + +- name: Idempotency assertions check for update tenant description using ans_test_update xml template file with normal mode + assert: + that: + - idempotency_nm_update_tenant is not changed + +- name: Query ans_test_create tenant using query string after the update + cisco.aci.aci_rest: + <<: *aci_info + path: "/api/node/mo/uni/tn-ans_test_create.json?query-target=self" + method: get + register: query_ans_test_update + +- name: Assertions check for querying ans_test_create tenant using query string after the update + assert: + that: + - query_ans_test_update is not changed + - query_ans_test_update.imdata != [] + - query_ans_test_update.imdata.0.fvTenant.attributes.name == "ans_test_create" + - query_ans_test_update.imdata.0.fvTenant.attributes.descr == "ans_test_create tenant updated successfully" + - query_ans_test_update.imdata.0.fvTenant.attributes.dn == "uni/tn-ans_test_create" + +- name: Update tenant name using ans_test_negative_update_check xml template file with normal mode + cisco.aci.aci_rest: + <<: *aci_info + path: /api/mo/uni.xml + src: "./targets/aci_rest/tasks/xml_files/tn-ans_test_negative_update_check.xml" + method: post + register: negative_update_tenant_check + ignore_errors: true + +- name: Assertions check for update tenant name using ans_test_negative_update_check xml template file with normal mode + assert: + that: + - negative_update_tenant_check is failed + +- name: Delete tenant using ans_test_delete xml template file with check mode + cisco.aci.aci_rest: + <<: *aci_info + path: /api/mo/uni.xml + src: "./targets/aci_rest/tasks/xml_files/tn-ans_test_delete.xml" + method: post + check_mode: true + register: cm_delete_tenant + +- name: Assertions check for delete tenant using ans_test_delete xml template file with check mode + assert: + that: + - cm_delete_tenant is not changed + +- name: Delete tenant using ans_test_delete xml template file with normal mode + cisco.aci.aci_rest: + <<: *aci_info + path: /api/mo/uni.xml + src: "./targets/aci_rest/tasks/xml_files/tn-ans_test_delete.xml" + method: post + register: nm_delete_tenant + +- name: Assertions check for delete tenant using ans_test_delete xml template file with normal mode + assert: + that: + - nm_delete_tenant is changed + - nm_delete_tenant.imdata.0.fvTenant.attributes.name == "ans_test_create" + - nm_delete_tenant.imdata.0.fvTenant.attributes.descr == "ans_test_create tenant updated successfully" + - nm_delete_tenant.imdata.0.fvTenant.attributes.dn == "uni/tn-ans_test_create" + +- name: Delete tenant using ans_test_delete xml template file with normal mode - idempotency works + cisco.aci.aci_rest: + <<: *aci_info + path: /api/mo/uni.xml + src: "./targets/aci_rest/tasks/xml_files/tn-ans_test_delete.xml" + method: post + register: idempotency_nm_delete_tenant + +- name: Idempotency assertions check for delete tenant using ans_test_delete xml template file with normal mode + assert: + that: + - idempotency_nm_delete_tenant is not changed + - idempotency_nm_delete_tenant.imdata == {} + +- name: Query ans_test_create tenant using query string after the delete + cisco.aci.aci_rest: + <<: *aci_info + path: "/api/node/mo/uni/tn-ans_test_create.json?query-target=self" + method: get + register: query_ans_test_delete + +- name: Assertions check for querying ans_test_create tenant using query string after the delete + assert: + that: + - query_ans_test_delete is not changed + - query_ans_test_delete.imdata == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/tn-ans_test_create.xml b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/tn-ans_test_create.xml new file mode 100644 index 000000000..b5d25b3d8 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/tn-ans_test_create.xml @@ -0,0 +1 @@ +<fvTenant descr="ans_test_create tenant created successfully" dn="uni/tn-ans_test_create" name="ans_test_create" status=""/>
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/tn-ans_test_delete.xml b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/tn-ans_test_delete.xml new file mode 100644 index 000000000..9e6c9028e --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/tn-ans_test_delete.xml @@ -0,0 +1 @@ +<fvTenant dn="uni/tn-ans_test_create" status="deleted"/>
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/tn-ans_test_negative_update_check.xml b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/tn-ans_test_negative_update_check.xml new file mode 100644 index 000000000..f2d5a040d --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/tn-ans_test_negative_update_check.xml @@ -0,0 +1 @@ +<fvTenant descr="ans_test_create tenant updated successfully" dn="uni/tn-ans_test_create" name="ans_test_update" status="modified"/>
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/tn-ans_test_update.xml b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/tn-ans_test_update.xml new file mode 100644 index 000000000..99b0a5911 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_files/tn-ans_test_update.xml @@ -0,0 +1 @@ +<fvTenant descr="ans_test_create tenant updated successfully" dn="uni/tn-ans_test_create" name="ans_test_create" status="modified"/>
\ 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 new file mode 100644 index 000000000..c87291779 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/xml_string.yml @@ -0,0 +1,167 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + + +# CLEAN ENVIRONMENT +- name: Remove tenant + cisco.aci.aci_rest: &tenant_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") }}' + path: /api/mo/uni/tn-[ansible_test].xml + method: delete + +# ADD TENANT +- name: Add tenant (normal mode) + cisco.aci.aci_rest: &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: '{{ aci_output_level | default("info") }}' + path: /api/mo/uni.xml + method: post + content: + { + "fvTenant": { + "attributes": { + "name": "ansible_test" + } + } + } + register: nm_add_tenant + +- name: Add tenant again (normal mode) + cisco.aci.aci_rest: + <<: *tenant_present + path: /api/mo/uni.xml + content: + <fvTenant name="ansible_test"/> + register: nm_add_tenant_again + +- name: Verify add_tenant + assert: + that: + - nm_add_tenant is changed + - nm_add_tenant_again is not changed + +# CHANGE TENANT +- name: Change description of tenant (normal mode) + cisco.aci.aci_rest: &tenant_changed + 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 + descr: Ansible test tenant + register: nm_add_tenant_descr + +- name: Change description of tenant again (normal mode) + cisco.aci.aci_rest: + <<: *tenant_changed + path: /api/mo/uni.xml + content: + fvTenant: + attributes: + name: ansible_test + descr: Ansible test tenant + register: nm_add_tenant_descr_again + +- name: Verify add_tenant_descr + assert: + that: + - nm_add_tenant_descr is changed + - nm_add_tenant_descr_again is not changed + +# ADD TENANT AGAIN +- name: Add tenant again with no description (normal mode) + cisco.aci.aci_rest: + <<: *tenant_present + path: /api/mo/uni.xml + content: + <fvTenant name="ansible_test"/> + register: nm_add_tenant_again_no_descr + +- name: Verify add_tenant_again_no_descr + assert: + that: + - nm_add_tenant_again_no_descr is not changed + +# QUERY ALL TENANTS +- name: Query all tenants (normal mode) + cisco.aci.aci_rest: &tenant_query_all + 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/tn-[ansible_test].xml + method: get + register: nm_query_all_tenants + +- name: Verify query_all_tenants + assert: + that: + - nm_query_all_tenants is not changed + +# QUERY A TENANT +- name: Query our tenant + cisco.aci.aci_rest: &tenant_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") }}' + path: /api/mo/uni/tn-[ansible_test].xml + method: get + register: nm_query_tenant + +- name: Verify query_tenant + assert: + that: + - nm_query_tenant is not changed + +# REMOVE TENANT +- name: Remove tenant (normal mode) + cisco.aci.aci_rest: *tenant_absent + register: nm_remove_tenant + +- name: Remove tenant again (normal mode) + cisco.aci.aci_rest: *tenant_absent + register: nm_remove_tenant_again + +- name: Verify remove_tenant + assert: + that: + - nm_remove_tenant is changed + - nm_remove_tenant_again is not changed + +# QUERY NON-EXISTING TENANT +- name: Query non-existing tenant (normal mode) + cisco.aci.aci_rest: *tenant_query + register: nm_query_non_tenant + +- name: Verify query_non_tenant + assert: + that: + - nm_query_non_tenant is not changed 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 new file mode 100644 index 000000000..d7538f9a6 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/yaml_inline.yml @@ -0,0 +1,148 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + + +# CLEAN ENVIRONMENT +- name: Remove tenant + cisco.aci.aci_rest: &tenant_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") }}' + path: /api/mo/uni/tn-[ansible_test].json + method: delete + +# ADD TENANT +- name: Add tenant (normal mode) + cisco.aci.aci_rest: &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: '{{ aci_output_level | default("info") }}' + path: /api/mo/uni.json + method: post + content: + fvTenant: + attributes: + name: ansible_test + register: nm_add_tenant + +- name: Add tenant again (normal mode) + cisco.aci.aci_rest: *tenant_present + register: nm_add_tenant_again + +- name: Verify add_tenant + assert: + that: + - nm_add_tenant is changed + - nm_add_tenant_again is not changed + +# CHANGE TENANT +- name: Change description of tenant (normal mode) + cisco.aci.aci_rest: &tenant_changed + 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.json + method: post + content: + fvTenant: + attributes: + name: ansible_test + descr: Ansible test tenant + register: nm_add_tenant_descr + +- name: Change description of tenant again (normal mode) + cisco.aci.aci_rest: *tenant_changed + register: nm_add_tenant_descr_again + +- name: Verify add_tenant_descr + assert: + that: + - nm_add_tenant_descr is changed + - nm_add_tenant_descr_again is not changed + +# ADD TENANT AGAIN +- name: Add tenant again with no description (normal mode) + cisco.aci.aci_rest: *tenant_present + register: nm_add_tenant_again_no_descr + +- name: Verify add_tenant_again_no_descr + assert: + that: + - nm_add_tenant_again_no_descr is not changed + +# QUERY ALL TENANTS +- name: Query all tenants (normal mode) + cisco.aci.aci_rest: &tenant_query_all + 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/tn-[ansible_test].json + method: get + register: nm_query_all_tenants + +- name: Verify query_all_tenants + assert: + that: + - nm_query_all_tenants is not changed + +# QUERY A TENANT +- name: Query our tenant + cisco.aci.aci_rest: &tenant_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") }}' + path: /api/mo/uni/tn-[ansible_test].json + method: get + register: nm_query_tenant + +- name: Verify query_tenant + assert: + that: + - nm_query_tenant is not changed + +# REMOVE TENANT +- name: Remove tenant (normal mode) + cisco.aci.aci_rest: *tenant_absent + register: nm_remove_tenant + +- name: Remove tenant again (normal mode) + cisco.aci.aci_rest: *tenant_absent + register: nm_remove_tenant_again + +- name: Verify remove_tenant + assert: + that: + - nm_remove_tenant is changed + - nm_remove_tenant_again is not changed + +# QUERY NON-EXISTING TENANT +- name: Query non-existing tenant (normal mode) + cisco.aci.aci_rest: *tenant_query + register: nm_query_non_tenant + +- name: Verify query_non_tenant + assert: + that: + - nm_query_non_tenant is not changed 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 new file mode 100644 index 000000000..d7538f9a6 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_rest/tasks/yaml_string.yml @@ -0,0 +1,148 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + + +# CLEAN ENVIRONMENT +- name: Remove tenant + cisco.aci.aci_rest: &tenant_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") }}' + path: /api/mo/uni/tn-[ansible_test].json + method: delete + +# ADD TENANT +- name: Add tenant (normal mode) + cisco.aci.aci_rest: &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: '{{ aci_output_level | default("info") }}' + path: /api/mo/uni.json + method: post + content: + fvTenant: + attributes: + name: ansible_test + register: nm_add_tenant + +- name: Add tenant again (normal mode) + cisco.aci.aci_rest: *tenant_present + register: nm_add_tenant_again + +- name: Verify add_tenant + assert: + that: + - nm_add_tenant is changed + - nm_add_tenant_again is not changed + +# CHANGE TENANT +- name: Change description of tenant (normal mode) + cisco.aci.aci_rest: &tenant_changed + 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.json + method: post + content: + fvTenant: + attributes: + name: ansible_test + descr: Ansible test tenant + register: nm_add_tenant_descr + +- name: Change description of tenant again (normal mode) + cisco.aci.aci_rest: *tenant_changed + register: nm_add_tenant_descr_again + +- name: Verify add_tenant_descr + assert: + that: + - nm_add_tenant_descr is changed + - nm_add_tenant_descr_again is not changed + +# ADD TENANT AGAIN +- name: Add tenant again with no description (normal mode) + cisco.aci.aci_rest: *tenant_present + register: nm_add_tenant_again_no_descr + +- name: Verify add_tenant_again_no_descr + assert: + that: + - nm_add_tenant_again_no_descr is not changed + +# QUERY ALL TENANTS +- name: Query all tenants (normal mode) + cisco.aci.aci_rest: &tenant_query_all + 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/tn-[ansible_test].json + method: get + register: nm_query_all_tenants + +- name: Verify query_all_tenants + assert: + that: + - nm_query_all_tenants is not changed + +# QUERY A TENANT +- name: Query our tenant + cisco.aci.aci_rest: &tenant_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") }}' + path: /api/mo/uni/tn-[ansible_test].json + method: get + register: nm_query_tenant + +- name: Verify query_tenant + assert: + that: + - nm_query_tenant is not changed + +# REMOVE TENANT +- name: Remove tenant (normal mode) + cisco.aci.aci_rest: *tenant_absent + register: nm_remove_tenant + +- name: Remove tenant again (normal mode) + cisco.aci.aci_rest: *tenant_absent + register: nm_remove_tenant_again + +- name: Verify remove_tenant + assert: + that: + - nm_remove_tenant is changed + - nm_remove_tenant_again is not changed + +# QUERY NON-EXISTING TENANT +- name: Query non-existing tenant (normal mode) + cisco.aci.aci_rest: *tenant_query + register: nm_query_non_tenant + +- name: Verify query_non_tenant + assert: + that: + - nm_query_non_tenant is not changed diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_client/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_client/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_client/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_client/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_client/tasks/main.yml new file mode 100644 index 000000000..e5c0ce185 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_client/tasks/main.yml @@ -0,0 +1,160 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_snmp_client_group if it already exists + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + state: absent + +# ADD snmp policy +- name: Add snmp policy + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + admin_state: enabled + state: present + +# ADD snmp client group +- name: Add snmp client group + aci_snmp_client_group: + <<: *aci_info + policy: ansible_snmp_policy + client_group: ansible_snmp_client_group + mgmt_epg: oob-default + state: present + +# ADD snmp client +- name: Add snmp client + aci_snmp_client: + <<: *aci_info + policy: ansible_snmp_policy + client_group: ansible_snmp_client_group + address: 10.20.30.0/24 + client_name: snmp_client_name + state: present + register: add_snmp_client + +- name: Verify that ansible_snmp_client has been created with correct attributes + assert: + that: + - add_snmp_client.current.0.snmpClientP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/clgrp-ansible_snmp_client_group/client-[10.20.30.0/24]" + - add_snmp_client.current.0.snmpClientP.attributes.addr == "10.20.30.0/24" + - add_snmp_client.current.0.snmpClientP.attributes.name == "snmp_client_name" + - add_snmp_client.current.0.snmpClientP.attributes.annotation == 'orchestrator:ansible' + +# ADD snmp client again to check idempotency +- name: Add snmp client again + aci_snmp_client: + <<: *aci_info + policy: ansible_snmp_policy + client_group: ansible_snmp_client_group + address: 10.20.30.0/24 + client_name: snmp_client_name + state: present + register: add_snmp_client_again + +- name: Verify that add_snmp_client_group_again stays the same + assert: + that: + - add_snmp_client_again is not changed + +# MODIFY snmp client +- name: Update snmp client + aci_snmp_client: + <<: *aci_info + policy: ansible_snmp_policy + client_group: ansible_snmp_client_group + address: 10.20.30.0/24 + client_name: new_snmp_client_name + state: present + register: update_snmp_client + +- name: Verify that ansible_snmp_client_group has been updated with correct attributes + assert: + that: + - update_snmp_client is changed + - update_snmp_client.current.0.snmpClientP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/clgrp-ansible_snmp_client_group/client-[10.20.30.0/24]" + - update_snmp_client.current.0.snmpClientP.attributes.addr == "10.20.30.0/24" + - update_snmp_client.current.0.snmpClientP.attributes.name == "new_snmp_client_name" + +# QUERY snmp client +- name: Query snmp client + aci_snmp_client: + <<: *aci_info + policy: ansible_snmp_policy + client_group: ansible_snmp_client_group + address: 10.20.30.0/24 + state: query + register: query_snmp_client + +- name: Verify the attributes under query_snmp_client + assert: + that: + - query_snmp_client is not changed + - query_snmp_client.current.0.snmpClientP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/clgrp-ansible_snmp_client_group/client-[10.20.30.0/24]" + - query_snmp_client.current.0.snmpClientP.attributes.addr == "10.20.30.0/24" + - query_snmp_client.current.0.snmpClientP.attributes.name == "new_snmp_client_name" + +- name: Query all snmp client + aci_snmp_client: + <<: *aci_info + state: query + register: query_snmp_client_all + +- name: Verify query_snmp_client_all + assert: + that: + - query_snmp_client_all is not changed + +# DELETE snmp client group +- name: Remove the snmp client + aci_snmp_client: + <<: *aci_info + policy: ansible_snmp_policy + client_group: ansible_snmp_client_group + address: 10.20.30.0/24 + state: absent + register: remove_snmp_client + +- name: Verify remove_snmp_client + assert: + that: + - remove_snmp_client is changed + - remove_snmp_client.previous.0.snmpClientP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/clgrp-ansible_snmp_client_group/client-[10.20.30.0/24]" + - remove_snmp_client.previous.0.snmpClientP.attributes.addr == "10.20.30.0/24" + +# DELETE snmp policy +- name: Remove the snmp policy + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + state: absent + +# DELETE snmp client group +- name: Remove the snmp client group + aci_snmp_client_group: + <<: *aci_info + policy: ansible_snmp_policy + client_group: ansible_snmp_client_group + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_client_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_client_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_client_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_snmp_client_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_client_group/tasks/main.yml new file mode 100644 index 000000000..f54a7841a --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_client_group/tasks/main.yml @@ -0,0 +1,162 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_snmp_client_group if it already exists + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + state: absent + +# ADD snmp policy +- name: Add snmp policy + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + admin_state: enabled + state: present + +# ADD snmp client group +- name: Add snmp client group + aci_snmp_client_group: + <<: *aci_info + policy: ansible_snmp_policy + client_group: ansible_snmp_client_group + mgmt_epg: oob-default + description: client group descr + state: present + register: add_snmp_client_group + +- name: Add snmp client group on default mgmt_epg + aci_snmp_client_group: + <<: *aci_info + policy: ansible_snmp_policy + client_group: ansible_snmp_client_group_no_epg + description: client group descr + state: present + register: add_snmp_client_group_no_epg + +- name: Verify that ansible_snmp_client_group has been created with correct attributes + assert: + that: + - add_snmp_client_group.current.0.snmpClientGrpP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/clgrp-ansible_snmp_client_group" + - add_snmp_client_group.current.0.snmpClientGrpP.attributes.name == "ansible_snmp_client_group" + - add_snmp_client_group.current.0.snmpClientGrpP.attributes.descr == "client group descr" + - add_snmp_client_group.current.0.snmpClientGrpP.attributes.annotation == 'orchestrator:ansible' + +- name: Verify that ansible_snmp_client_group_no_epg has been created with correct attributes + assert: + that: + - add_snmp_client_group_no_epg.current.0.snmpClientGrpP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/clgrp-ansible_snmp_client_group_no_epg" + - add_snmp_client_group_no_epg.current.0.snmpClientGrpP.attributes.name == "ansible_snmp_client_group_no_epg" + - add_snmp_client_group_no_epg.current.0.snmpClientGrpP.attributes.descr == "client group descr" + +- name: Verify that children of ansible_snmp_client_group have been created with correct values + assert: + that: + - add_snmp_client_group.current.0.snmpClientGrpP.children.0.snmpRsEpg.attributes.tDn == "uni/tn-mgmt/mgmtp-default/oob-default" + +# ADD snmp client group again to check idempotency +- name: Add snmp client group again + aci_snmp_client_group: + <<: *aci_info + policy: ansible_snmp_policy + client_group: ansible_snmp_client_group + mgmt_epg: oob-default + description: client group descr + state: present + register: add_snmp_client_group_again + +- name: Verify that add_snmp_client_group_again stays the same + assert: + that: + - add_snmp_client_group_again is not changed + +# MODIFY snmp client group +- name: Update snmp client group + aci_snmp_client_group: + <<: *aci_info + policy: ansible_snmp_policy + client_group: ansible_snmp_client_group + mgmt_epg: oob-default + description: new client group descr + state: present + register: update_snmp_client_group + +- name: Verify that ansible_snmp_client_group has been updated with correct attributes + assert: + that: + - update_snmp_client_group is changed + - update_snmp_client_group.current.0.snmpClientGrpP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/clgrp-ansible_snmp_client_group" + - update_snmp_client_group.current.0.snmpClientGrpP.attributes.name == "ansible_snmp_client_group" + - update_snmp_client_group.current.0.snmpClientGrpP.attributes.descr == "new client group descr" + +# QUERY snmp client group +- name: Query snmp client group + aci_snmp_client_group: + <<: *aci_info + policy: ansible_snmp_policy + client_group: ansible_snmp_client_group + state: query + register: query_snmp_client_group + +- name: Verify the attributes under query_snmp_client_group + assert: + that: + - query_snmp_client_group is not changed + - query_snmp_client_group.current.0.snmpClientGrpP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/clgrp-ansible_snmp_client_group" + - query_snmp_client_group.current.0.snmpClientGrpP.attributes.name == "ansible_snmp_client_group" + - query_snmp_client_group.current.0.snmpClientGrpP.attributes.descr == "new client group descr" + +- name: Query all snmp client groups + aci_snmp_client_group: + <<: *aci_info + state: query + register: query_snmp_client_group_all + +- name: Verify query_snmp_client_group_all + assert: + that: + - query_snmp_client_group_all is not changed + +# DELETE snmp client group +- name: Remove the snmp client group + aci_snmp_client_group: + <<: *aci_info + policy: ansible_snmp_policy + client_group: ansible_snmp_client_group + state: absent + register: remove_snmp_client_group + +- name: Verify remove_snmp_client_group + assert: + that: + - remove_snmp_client_group is changed + - remove_snmp_client_group.previous.0.snmpClientGrpP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/clgrp-ansible_snmp_client_group" + - remove_snmp_client_group.previous.0.snmpClientGrpP.attributes.name == "ansible_snmp_client_group" + +# DELETE snmp policy +- name: Remove the snmp policy + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_community_policy/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_community_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_community_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_snmp_community_policy/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_community_policy/tasks/main.yml new file mode 100644 index 000000000..570476d37 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_community_policy/tasks/main.yml @@ -0,0 +1,136 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_snmp_policy if it already exists + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + state: absent + +# ADD snmp policy +- name: Add snmp policy + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + admin_state: enabled + state: present + +# ADD snmp community +- name: Add snmp community + aci_snmp_community_policy: + <<: *aci_info + policy: ansible_snmp_policy + community: ansible_snmp_community + description: community description + register: add_snmp_community + +- name: Verify that ansible_snmp_community has been created with correct attributes + assert: + that: + - add_snmp_community.current.0.snmpCommunityP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/community-ansible_snmp_community" + - add_snmp_community.current.0.snmpCommunityP.attributes.name == "ansible_snmp_community" + - add_snmp_community.current.0.snmpCommunityP.attributes.descr == "community description" + - add_snmp_community.current.0.snmpCommunityP.attributes.annotation == 'orchestrator:ansible' + +# ADD snmp community again to check idempotency +- name: Add snmp client group again + aci_snmp_community_policy: + <<: *aci_info + policy: ansible_snmp_policy + community: ansible_snmp_community + description: community description + register: add_snmp_community_again + +- name: Verify that add_snmp_community_again stays the same + assert: + that: + - add_snmp_community_again is not changed + +# MODIFY snmp client community +- name: Update snmp community + aci_snmp_community_policy: + <<: *aci_info + policy: ansible_snmp_policy + community: ansible_snmp_community + description: new community description + register: update_snmp_community + +- name: Verify that ansible_snmp_community has been updated with correct attributes + assert: + that: + - update_snmp_community is changed + - update_snmp_community.current.0.snmpCommunityP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/community-ansible_snmp_community" + - update_snmp_community.current.0.snmpCommunityP.attributes.name == "ansible_snmp_community" + - update_snmp_community.current.0.snmpCommunityP.attributes.descr == "new community description" + +# QUERY snmp community +- name: Query snmp community + aci_snmp_community_policy: + <<: *aci_info + policy: ansible_snmp_policy + community: ansible_snmp_community + state: query + register: query_snmp_community + +- name: Verify the attributes under query_snmp_client_group + assert: + that: + - query_snmp_community is not changed + - query_snmp_community.current.0.snmpCommunityP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/community-ansible_snmp_community" + - query_snmp_community.current.0.snmpCommunityP.attributes.name == "ansible_snmp_community" + - query_snmp_community.current.0.snmpCommunityP.attributes.descr == "new community description" + +- name: Query all snmp communities + aci_snmp_community_policy: + <<: *aci_info + state: query + register: query_snmp_community_all + +- name: Verify query_snmp_community_all + assert: + that: + - query_snmp_community_all is not changed + +# DELETE snmp community +- name: Remove the snmp community + aci_snmp_community_policy: + <<: *aci_info + policy: ansible_snmp_policy + community: ansible_snmp_community + state: absent + register: remove_snmp_community + +- name: Verify remove_snmp_community + assert: + that: + - remove_snmp_community is changed + - remove_snmp_community.current == [] + - remove_snmp_community.previous.0.snmpCommunityP.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy/community-ansible_snmp_community" + - remove_snmp_community.previous.0.snmpCommunityP.attributes.name == "ansible_snmp_community" + +# DELETE snmp policy +- name: Remove the snmp policy + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_policy/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_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_snmp_policy/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_policy/tasks/main.yml new file mode 100644 index 000000000..823ea8f30 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_policy/tasks/main.yml @@ -0,0 +1,135 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_snmp_policy if it already exists + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + state: absent + +# ADD snmp policy +- name: Add snmp policy + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + admin_state: enabled + contact: snmp contact + location: snmp location + description: policy description + state: present + register: add_snmp_policy + +- name: Verify that ansible_snmp_policy has been created with correct attributes + assert: + that: + - add_snmp_policy.current.0.snmpPol.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy" + - add_snmp_policy.current.0.snmpPol.attributes.name == "ansible_snmp_policy" + - add_snmp_policy.current.0.snmpPol.attributes.contact == "snmp contact" + - add_snmp_policy.current.0.snmpPol.attributes.loc == "snmp location" + - add_snmp_policy.current.0.snmpPol.attributes.adminSt == "enabled" + - add_snmp_policy.current.0.snmpPol.attributes.descr == "policy description" + - add_snmp_policy.current.0.snmpPol.attributes.annotation == 'orchestrator:ansible' + +# ADD snmp policy again to check idempotency +- name: Add snmp policy + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + admin_state: enabled + contact: snmp contact + location: snmp location + description: policy description + state: present + register: add_snmp_policy_again + +- name: Verify that ansible_snmp_policy stays the same + assert: + that: + - add_snmp_policy_again is not changed + +# MODIFY snmp policy +- name: Update snmp policy + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + admin_state: disabled + contact: new snmp contact + location: new snmp location + description: new policy description + state: present + register: update_snmp_policy + +- name: Verify that ansible_snmp_policy has been updated with correct attributes + assert: + that: + - update_snmp_policy.current.0.snmpPol.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy" + - update_snmp_policy.current.0.snmpPol.attributes.name == "ansible_snmp_policy" + - update_snmp_policy.current.0.snmpPol.attributes.contact == "new snmp contact" + - update_snmp_policy.current.0.snmpPol.attributes.loc == "new snmp location" + - update_snmp_policy.current.0.snmpPol.attributes.adminSt == "disabled" + - update_snmp_policy.current.0.snmpPol.attributes.descr == "new policy description" + +# QUERY snmp policy +- name: Query snmp policy + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + state: query + register: query_snmp_policy + +- name: Verify the attributes under query_snmp_policy + assert: + that: + - query_snmp_policy is not changed + - query_snmp_policy.current.0.snmpPol.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy" + - query_snmp_policy.current.0.snmpPol.attributes.name == "ansible_snmp_policy" + - query_snmp_policy.current.0.snmpPol.attributes.contact == "new snmp contact" + - query_snmp_policy.current.0.snmpPol.attributes.loc == "new snmp location" + - query_snmp_policy.current.0.snmpPol.attributes.adminSt == "disabled" + - query_snmp_policy.current.0.snmpPol.attributes.descr == "new policy description" + +- name: Query all snmp policies + aci_snmp_policy: + <<: *aci_info + state: query + register: query_snmp_policy_all + +- name: Verify query_snmp_policy_all + assert: + that: + - query_snmp_policy_all is not changed + +# DELETE snmp policy +- name: Remove the snmp policy + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + state: absent + register: remove_snmp_policy + +- name: Verify remove_snmp_policy + assert: + that: + - remove_snmp_policy is changed + - remove_snmp_policy.previous.0.snmpPol.attributes.dn == "uni/fabric/snmppol-ansible_snmp_policy" + - remove_snmp_policy.previous.0.snmpPol.attributes.name == "ansible_snmp_policy" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_user/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_user/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_user/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..1b2608189 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_snmp_user/tasks/main.yml @@ -0,0 +1,111 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_snmp_policy if it already exists + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + state: absent + +# ADD snmp policy +- name: Add snmp policy + aci_snmp_policy: + <<: *aci_info + name: ansible_snmp_policy + admin_state: enabled + state: present + +# ADD snmp user +- name: Add snmp user + aci_snmp_user: + <<: *aci_info + policy: ansible_snmp_policy + name: ansible_snmp_user + auth_type: hmac-sha1-96 + auth_key: "auth-test-key" + privacy_type: aes-128 + privacy_key: "priv-test-key" + state: present + register: add_snmp_user + +- name: Verify that ansible_snmp_community has been created with correct attributes + 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: + <<: *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: + that: + - query_snmp_user is not changed + - 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: + <<: *aci_info + state: query + register: query_snmp_user_all + +- name: Verify query_snmp_user_all + assert: + that: + - query_snmp_user_all is not changed + +# DELETE snmp user +- name: Remove the snmp user + aci_snmp_user: + <<: *aci_info + policy: ansible_snmp_policy + name: ansible_snmp_user + state: absent + register: remove_snmp_user + +- name: Verify remove_snmp_user + 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" + +# DELETE snmp policy +- name: Remove the snmp policy + 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/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_static_binding_to_epg/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_static_binding_to_epg/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..180848e28 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_static_binding_to_epg/tasks/main.yml @@ -0,0 +1,391 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Bruno Calogero <bcalogero@cisco.com> +# Copyright: (c) 2021, Cindy <cizhao@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 + - name: Ensure static path to epg is deleted for test kick off + cisco.aci.aci_static_binding_to_epg: &aci_static_binding_to_epg_absent + <<: *aci_info + tenant: ansible_test + ap: anstest + epg: anstest + interface_type: switch_port + pod: 1 + leafs: 101 + interface: '1/7' + state: absent + + - name: Ensure static path to epg is deleted + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_absent + interface_type: fex_port_channel + extpaths: 1011 + + - name: Ensure static path to epg is deleted + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_absent + interface_type: fex_vpc + interface: 'ansible_test' + leafs: + - 101 + - 102 + extpaths: + - 103 + - 104 + + - 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 ap exists + cisco.aci.aci_ap: &aci_ap_present + <<: *aci_tenant_present + ap: anstest + register: ap_present + + - name: Ensure epg exists + cisco.aci.aci_epg: &aci_epg_present + <<: *aci_ap_present + epg: anstest + register: epg_present + + - name: Bind static-binding to epg - check mode works + cisco.aci.aci_static_binding_to_epg: &aci_static_binding_to_epg_present + <<: *aci_epg_present + encap_id: 222 + deploy_immediacy: lazy + interface_mode: trunk + interface_type: switch_port + pod: 1 + leafs: 101 + interface: '1/7' + check_mode: true + register: provide_present_check_mode + + - name: Bind static-binding to epg - provide works (creation w/o check-mode) + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_present + ignore_errors: true + register: provide_present + + - name: Bind static-binding to epg - switch port with multiple leafs + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_present + leafs: + - 101 + - 102 + ignore_errors: true + register: nm_multiple_leafs + + - name: Bind static-binding to epg - three leafs + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_present + leafs: + - 101 + - 102 + - 103 + ignore_errors: true + register: nm_multiple_leafs + + - name: Bind static-binding to epg - primary_encap_id works + cisco.aci.aci_static_binding_to_epg: &primary_encap_id_present + <<: *aci_static_binding_to_epg_present + primary_encap_id: 50 + register: primary_ecap_id_present + + - name: Bind contract to epg - primary_encap_id invalid + cisco.aci.aci_static_binding_to_epg: + <<: *primary_encap_id_present + primary_encap_id: invalid-vlan + ignore_errors: true + register: primary_encap_id_invalid + + - name: Bind contract to epg - idempotency works again + cisco.aci.aci_static_binding_to_epg: + <<: *primary_encap_id_present + register: idempotent_present + + - name: Bind contract to epg - update description (check mode) + cisco.aci.aci_static_binding_to_epg: + <<: *primary_encap_id_present + description: Binding description + check_mode: true + register: description_cm + + - name: Bind contract to epg - update description (run mode) + cisco.aci.aci_static_binding_to_epg: + <<: *primary_encap_id_present + description: Binding description + register: description + + - name: Bind contract to epg - update description (check mode) + cisco.aci.aci_static_binding_to_epg: + <<: *primary_encap_id_present + description: Binding description + register: idempotent_description_cm + + - name: Bind contract to epg - update description (run mode) + cisco.aci.aci_static_binding_to_epg: + <<: *primary_encap_id_present + description: Binding description + register: idempotent_description + + - name: Missing required param - failure message works + cisco.aci.aci_static_binding_to_epg: + <<: *aci_tenant_present + ignore_errors: true + register: missing_required_present + + - name: Present assertions + assert: + that: + - provide_present_check_mode is changed + - provide_present_check_mode.sent.fvRsPathAtt.attributes.encap == 'vlan-222' + - provide_present_check_mode.sent.fvRsPathAtt.attributes.instrImedcy == 'lazy' + - provide_present_check_mode.sent.fvRsPathAtt.attributes.mode == 'regular' + - provide_present_check_mode.sent.fvRsPathAtt.attributes.tDn == 'topology/pod-1/paths-101/pathep-[eth1/7]' + - provide_present is changed + - provide_present.sent == provide_present_check_mode.sent + - provide_present.current.0.fvRsPathAtt.attributes.annotation == 'orchestrator:ansible' + - provide_present.previous == [] + - primary_ecap_id_present is changed + - primary_ecap_id_present.sent.fvRsPathAtt.attributes.primaryEncap == 'vlan-50' + - description_cm is changed + - description is changed + - idempotent_description_cm is not changed + - idempotent_description is not changed + - missing_required_present is failed + - 'missing_required_present.msg == "state is present but all of the following are missing: ap, encap_id, epg, interface, leafs, pod_id"' + - missing_required_present is failed + - primary_encap_id_invalid is failed + + - name: Query specific binding + cisco.aci.aci_static_binding_to_epg: + <<: *primary_encap_id_present + state: query + register: query_static_binding + + - name: Query all bindings + cisco.aci.aci_static_binding_to_epg: + <<: *aci_tenant_present + state: query + register: query_all + + - name: Query assertions + assert: + that: + - query_static_binding is not changed + - query_static_binding.current != [] + - '"uni/tn-ansible_test/ap-anstest/epg-anstest/rspathAtt-[topology/pod-1/paths-101/pathep-[eth1/7]]" in query_static_binding.url' + - query_all is not changed + - '"uni/tn-ansible_test.json" in query_all.url' + + # Testing when primary_encap_id = unknown + - name: Bind static-binding to epg - unknown primary_encap_id + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_present + primary_encap_id: 'unknown' + register: primary_ecap_id_unknown + + - name: Bind static-binding to epg - omit primary_encap_id + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_present + primary_encap_id: "{{ item['primary_encap'] | default(omit) }}" + register: primary_ecap_id_omit + + - name: Bind static-binding to epg - out of range primary_encap_id + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_present + primary_encap_id: 4098 + ignore_errors: true + register: primary_ecap_id_range + + - name: Bind static-binding to epg - out of range encap_id + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_present + encap_id: 4098 + ignore_errors: true + register: encap_id_range + + - name: primary_ecap_id assertions + assert: + that: + - primary_ecap_id_unknown is changed + - primary_ecap_id_unknown.sent.fvRsPathAtt.attributes.primaryEncap == 'unknown' + - primary_ecap_id_omit is not changed + - primary_ecap_id_omit.sent == {} + - primary_ecap_id_range is not changed + - primary_ecap_id_range.msg == 'Valid VLAN assignments are from 1 to 4096 or unknown.' + - encap_id_range.msg == 'Valid VLAN assignments are from 1 to 4096' + + - name: Bind static-binding to epg - interface type fex_port_channel (check_mode) + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_present + interface_type: fex_port_channel + extpaths: 1011 + check_mode: true + register: cm_fex_port_channel + + - name: Bind static-binding to epg - interface type fex_port_channel (normal mode) + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_present + interface_type: fex_port_channel + extpaths: 1011 + register: nm_fex_port_channel + + - name: Bind static-binding to epg - interface type fex_vpc - incorrect extpaths (normal mode) + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_present + interface_type: fex_vpc + extpaths: + - 1012 + ignore_errors: true + + - name: Bind static-binding to epg - interface type fex_vpc (normal mode) + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_present + interface_type: fex_vpc + leafs: + - 101 + - 102 + interface: 'ansible_test' + extpaths: + - 103 + - 104 + register: nm_fex_vpc + + - name: Bind static-binding to epg - fex_vpc with one extpaths (normal mode) + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_present + interface_type: fex_vpc + leafs: + - 101 + - 102 + interface: 'ansible_test' + extpaths: + - 103 + ignore_errors: true + register: fex_vpc_one_extpaths + + - name: Bind static-binding to epg - fex_vpc with three extpaths (normal mode) + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_present + interface_type: fex_vpc + leafs: + - 101 + - 102 + interface: 'ansible_test' + extpaths: + - 103 + - 104 + - 105 + ignore_errors: true + 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: + <<: *aci_static_binding_to_epg_present + interface_type: fex_port_channel + extpaths: + - 101 + - 102 + check_mode: true + ignore_errors: true + register: cm_multiple_extpaths + + - name: Bind static-binding to epg - fex_port_channel with multiple extpaths (normal mode) + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_present + interface_type: fex_port_channel + extpaths: + - 101 + - 102 + ignore_errors: true + register: nm_multiple_extpaths + + - name: Verify interface type and extpaths + assert: + that: + - cm_fex_port_channel is changed + - nm_fex_port_channel is changed + - cm_fex_port_channel.previous == nm_fex_port_channel.previous == [] + - cm_fex_port_channel.proposed.fvRsPathAtt.attributes.dn == 'uni/tn-ansible_test/ap-anstest/epg-anstest/rspathAtt-[topology/pod-1/paths-101/extpaths-1011/pathep-[1/7]]' + - nm_fex_port_channel.current.0.fvRsPathAtt.attributes.dn == 'uni/tn-ansible_test/ap-anstest/epg-anstest/rspathAtt-[topology/pod-1/paths-101/extpaths-1011/pathep-[1/7]]' + - nm_fex_vpc is changed + - nm_fex_vpc.previous == [] + - nm_fex_vpc.current.0.fvRsPathAtt.attributes.dn == 'uni/tn-ansible_test/ap-anstest/epg-anstest/rspathAtt-[topology/pod-1/protpaths-101-102/extprotpaths-103-104/pathep-[ansible_test]]' + + - name: Delete provide binding - deletion works + cisco.aci.aci_static_binding_to_epg: + <<: *primary_encap_id_present + state: absent + register: provide_absent + + - name: Delete provide binding - idempotency works + cisco.aci.aci_static_binding_to_epg: + <<: *primary_encap_id_present + state: absent + register: provide_absent_idempotent + + - name: Missing param - failure message works + cisco.aci.aci_static_binding_to_epg: + <<: *aci_tenant_present + state: absent + ignore_errors: true + register: missing_param_absent + + - name: Absent assertions + assert: + that: + - provide_absent is changed + - provide_absent.previous.0.fvRsPathAtt is defined + - provide_absent_idempotent is not changed + - provide_absent_idempotent.previous == [] + - missing_param_absent is failed + - missing_param_absent is failed + - 'missing_param_absent.msg == "state is absent but all of the following are missing: ap, epg, interface, leafs, pod_id"' + + - name: Cleanup binding + cisco.aci.aci_static_binding_to_epg: + <<: *aci_static_binding_to_epg_absent + + - name: Cleanup epg + cisco.aci.aci_epg: + <<: *aci_epg_present + state: absent + + - name: Cleanup ap + cisco.aci.aci_ap: + <<: *aci_ap_present + state: absent + + - name: Cleanup tenant + cisco.aci.aci_tenant: + <<: *aci_tenant_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_static_node_mgmt_address/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_static_node_mgmt_address/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_static_node_mgmt_address/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_static_node_mgmt_address/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_static_node_mgmt_address/tasks/main.yml new file mode 100644 index 000000000..ce1553a45 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_static_node_mgmt_address/tasks/main.yml @@ -0,0 +1,322 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Shreyas Srish (@shrsr) + +# 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: Remove node mgmt in_band epg + aci_node_mgmt_epg: + <<: *aci_info + type: in_band + epg: ansible-inband + encap: vlan-1 + bd: bd1 + state: absent + + - name: Remove node mgmt out_of_band epg + aci_node_mgmt_epg: + <<: *aci_info + type: out_of_band + epg: ansible-outofband + state: absent + + # Add operations + - name: Add node mgmt in_band epg + aci_node_mgmt_epg: + <<: *aci_info + type: in_band + epg: ansible-inband + encap: vlan-1 + bd: bd1 + state: present + + - name: Add node mgmt out_of_band epg + aci_node_mgmt_epg: + <<: *aci_info + type: out_of_band + epg: ansible-outofband + state: present + + - name: Add ipv4 address to mgmt interface in band in check mode + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-inband + pod_id: 1 + type: in_band + node_id: 110 + ipv4_address: "3.1.1.2/24" + ipv4_gw: "3.1.1.1" + state: present + check_mode: true + register: cm_add_inb + + - name: Add ipv4 address to mgmt interface out of band in check mode + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-outofband + pod_id: 1 + type: out_of_band + node_id: 110 + ipv4_address: '3.1.1.3/24' + ipv4_gw: "3.1.1.1" + state: present + check_mode: true + register: cm_add_oob + + - name: Add ipv4 address to mgmt interface in band in normal mode + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-inband + pod_id: 1 + type: in_band + node_id: 110 + ipv4_address: "3.1.1.2/24" + ipv4_gw: "3.1.1.1" + state: present + register: nm_add_inb + + - name: Add ipv4 address to mgmt interface out of band in normal mode + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-outofband + pod_id: 1 + type: out_of_band + node_id: 110 + ipv4_address: "3.1.1.3/24" + ipv4_gw: "3.1.1.1" + state: present + register: nm_add_oob + + - name: Add ipv4 address to mgmt interface in band in normal mode again + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-inband + pod_id: 1 + type: in_band + node_id: 110 + ipv4_address: "3.1.1.2/24" + ipv4_gw: "3.1.1.1" + state: present + register: nm_add_inb_again + + - name: Add ipv4 address to mgmt interface out of band in normal mode again + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-outofband + pod_id: 1 + type: out_of_band + node_id: 110 + ipv4_address: "3.1.1.3/24" + ipv4_gw: "3.1.1.1" + state: present + register: nm_add_oob_again + + - name: Add another ipv4 address to mgmt interface in band in normal mode + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-inband + pod_id: 1 + type: in_band + node_id: 111 + ipv4_address: "2.1.1.4/24" + ipv4_gw: "2.1.1.1" + state: present + register: nm_add_inb_2 + + - name: Add another ipv4 address to mgmt interface out of band in normal mode + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-outofband + pod_id: 1 + type: out_of_band + node_id: 111 + ipv4_address: "4.1.1.3/24" + ipv4_gw: "4.1.1.1" + state: present + register: nm_add_oob_2 + + - name: Verify add operations + assert: + that: + - cm_add_inb is changed + - cm_add_inb.sent.mgmtRsInBStNode.attributes.addr == '3.1.1.2/24' + - cm_add_oob is changed + - cm_add_oob.sent.mgmtRsOoBStNode.attributes.addr == '3.1.1.3/24' + - nm_add_inb is changed + - nm_add_inb.current.0.mgmtRsInBStNode.attributes.addr == '3.1.1.2/24' + - nm_add_inb.current.0.mgmtRsInBStNode.attributes.annotation == 'orchestrator:ansible' + - nm_add_oob is changed + - nm_add_oob.current.0.mgmtRsOoBStNode.attributes.addr == '3.1.1.3/24' + - nm_add_inb_2 is changed + - nm_add_inb_2.current.0.mgmtRsInBStNode.attributes.addr == '2.1.1.4/24' + - nm_add_oob_2 is changed + - nm_add_oob_2.current.0.mgmtRsOoBStNode.attributes.addr == '4.1.1.3/24' + - nm_add_inb_again is not changed + - nm_add_oob_again is not changed + + - name: Query ipv4 address to mgmt interface in band in normal mode + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-inband + pod_id: 1 + type: in_band + node_id: 110 + ipv4_address: "3.1.1.2/24" + ipv4_gw: "3.1.1.1" + state: query + register: nm_query_inb + + - name: Query ipv4 address to mgmt interface out_of_band in normal mode + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-outofband + pod_id: 1 + type: out_of_band + node_id: 110 + ipv4_address: "3.1.1.3/24" + ipv4_gw: "3.1.1.1" + state: query + register: nm_query_oob + + - name: Query all addresses in epg in band + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-inband + type: in_band + state: query + register: query_all_epg_inb + + - name: Query all addresses in epg out of band + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-outofband + type: out_of_band + state: query + register: query_all_epg_oob + + - name: Query all in band addresses + aci_static_node_mgmt_address: + <<: *aci_info + type: in_band + state: query + register: query_all_inb + + - name: Query all out_of_band addresses + aci_static_node_mgmt_address: + <<: *aci_info + type: out_of_band + state: query + register: query_all_oob + + - name: Verify query operations + assert: + that: + - nm_query_inb is not changed + - nm_query_oob is not changed + - nm_query_inb.current.0.mgmtRsInBStNode.attributes.addr == '3.1.1.2/24' + - nm_query_oob.current.0.mgmtRsOoBStNode.attributes.addr == '3.1.1.3/24' + - query_all_epg_inb.current.0.mgmtInB.attributes.dn == 'uni/tn-mgmt/mgmtp-default/inb-ansible-inband' + - query_all_epg_inb.current.0.mgmtInB.children | length == 2 + - query_all_epg_oob.current.0.mgmtOoB.attributes.dn == 'uni/tn-mgmt/mgmtp-default/oob-ansible-outofband' + - query_all_epg_oob.current.0.mgmtOoB.children | length == 2 + - query_all_inb.current.0.mgmtMgmtP.children.0.mgmtInB.children | length == 2 + - query_all_oob.current.0.mgmtMgmtP.children.0.mgmtOoB.children | length == 2 + + - name: Remove ipv4 address to mgmt interface in-band + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-inband + pod_id: 1 + type: in_band + node_id: 111 + ipv4_address: "2.1.1.4/24" + ipv4_gw: "2.1.1.1" + state: absent + register: remove_in_band + + - name: Remove ipv4 address to mgmt interface out of band + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-outofband + pod_id: 1 + type: out_of_band + node_id: 111 + ipv4_address: "4.1.1.3/24" + ipv4_gw: "4.1.1.1" + state: absent + register: remove_out_of_band + + - name: Remove ipv4 address to mgmt interface in-band again + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-inband + pod_id: 1 + type: in_band + node_id: 111 + ipv4_address: "2.1.1.4/24" + ipv4_gw: "2.1.1.1" + state: absent + register: remove_in_band_again + + - name: Remove ipv4 address to mgmt interface out of band again + aci_static_node_mgmt_address: + <<: *aci_info + epg: ansible-outofband + pod_id: 1 + type: out_of_band + node_id: 111 + ipv4_address: "4.1.1.3/24" + ipv4_gw: "4.1.1.1" + state: absent + register: remove_out_of_band_again + + - name: Verify remove operations + assert: + that: + - remove_in_band is changed + - remove_in_band.previous.0.mgmtRsInBStNode.attributes.addr == '2.1.1.4/24' + - remove_out_of_band is changed + - remove_out_of_band.previous.0.mgmtRsOoBStNode.attributes.addr == '4.1.1.3/24' + - remove_out_of_band_again is not changed + - remove_out_of_band_again.previous == [] + - remove_in_band_again is not changed + - remove_in_band_again.previous == [] + + # Clean environment for other ci test cases + - name: Remove node mgmt in_band epg + aci_node_mgmt_epg: + <<: *aci_info + type: in_band + epg: ansible-inband + encap: vlan-1 + bd: bd1 + state: absent + + - name: Remove node mgmt out_of_band epg + aci_node_mgmt_epg: + <<: *aci_info + type: out_of_band + epg: ansible-outofband + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_switch_leaf_selector/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_switch_leaf_selector/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_switch_leaf_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_switch_leaf_selector/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_switch_leaf_selector/tasks/main.yml new file mode 100644 index 000000000..d57239e49 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_switch_leaf_selector/tasks/main.yml @@ -0,0 +1,149 @@ +# Test code for the ACI modules +# 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) + +- 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 + block: # block specifies execution of tasks within, based on conditions + - name: Deleting Switch Policy Leaf profile exists for kick off + cisco.aci.aci_switch_policy_leaf_profile: + 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") }}' + leaf_profile: sw_name_test + state: absent + + - name: Ensuring Switch Policy Leaf profile exists for kick off + cisco.aci.aci_switch_policy_leaf_profile: &aci_switch_policy_leaf_profile_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 + leaf_profile: sw_name_test + state: present + register: leaf_profile_present + + # TODO: Ensure that leaf Policy Group Exists (module missing) (infra:AccPortGrp) + + - name: Adding a switch policy leaf profile selector associated Node Block range (w/o policy group) - check mode works + cisco.aci.aci_switch_leaf_selector: &aci_switch_leaf_selector_present + <<: *aci_switch_policy_leaf_profile_present + leaf: leaf_selector_name + leaf_node_blk: node_blk_name + from: 1011 + to: 1011 + check_mode: true + register: sw_leaf_selec_check_mode_present + + - name: Adding a switch policy leaf profile selector associated Node Block range (w/o policy group) - creation works + cisco.aci.aci_switch_leaf_selector: + <<: *aci_switch_leaf_selector_present + register: sw_leaf_selec_present + + - name: Adding a switch policy leaf profile selector associated Node Block range (w/o policy group) - idempotency works + cisco.aci.aci_switch_leaf_selector: + <<: *aci_switch_leaf_selector_present + register: sw_leaf_selec_idempotent + + - name: Adding a switch policy leaf profile selector associated Node Block range (w/ policy group) - update works + cisco.aci.aci_switch_leaf_selector: + <<: *aci_switch_leaf_selector_present + policy_group: anstest_policygroupname + register: sw_leaf_selec_update + + # TODO: also test for errors + - name: present assertions + assert: + that: + - sw_leaf_selec_check_mode_present is changed + - sw_leaf_selec_present is changed + - sw_leaf_selec_present.previous == [] + - sw_leaf_selec_present.sent.infraLeafS.attributes.name == 'leaf_selector_name' + - sw_leaf_selec_present.sent.infraLeafS.children.0.infraNodeBlk.attributes.from_ == '1011' + - sw_leaf_selec_present.sent.infraLeafS.children.0.infraNodeBlk.attributes.to_ == '1011' + - sw_leaf_selec_present.sent.infraLeafS.children.0.infraNodeBlk.attributes.name == 'node_blk_name' + - sw_leaf_selec_present.current.0.infraLeafS.attributes.annotation == 'orchestrator:ansible' + - sw_leaf_selec_idempotent is not changed + - sw_leaf_selec_idempotent.sent == {} + - sw_leaf_selec_update is changed + - sw_leaf_selec_update.sent.infraLeafS.attributes == {} + - sw_leaf_selec_update.sent.infraLeafS.children.0.infraRsAccNodePGrp.attributes.tDn == 'uni/infra/funcprof/accnodepgrp-anstest_policygroupname' + + - name: Query Specific switch policy leaf profile selector + cisco.aci.aci_switch_leaf_selector: + <<: *aci_switch_policy_leaf_profile_present + leaf: leaf_selector_name # "{{ fake_var | default(omit) }}" ? + state: query + register: binding_query + + - name: present assertions + assert: + that: + - binding_query is not changed + - binding_query.current | length >= 1 + - '"api/mo/uni/infra/nprof-sw_name_test/leaves-leaf_selector_name-typ-range.json" in binding_query.url' + + - name: Remove binding of interface access port selector and Interface Policy Leaf Profile - check mode + cisco.aci.aci_switch_leaf_selector: &aci_switch_leaf_selector_absent + <<: *aci_switch_policy_leaf_profile_present + leaf: leaf_selector_name + state: absent + check_mode: true + register: sw_leaf_selec_check_mode_absent + + - name: Remove switch policy leaf profile selector - delete works + cisco.aci.aci_switch_leaf_selector: + <<: *aci_switch_leaf_selector_absent + register: sw_leaf_selec_absent + + - name: Remove switch policy leaf profile selector - idempotency works + cisco.aci.aci_switch_leaf_selector: + <<: *aci_switch_leaf_selector_absent + register: sw_leaf_selec_absent_idempotent + + - name: Remove switch policy leaf profile selector - check mode + cisco.aci.aci_switch_leaf_selector: + <<: *aci_switch_policy_leaf_profile_present + #access_port_selector: anstest_accessportselector + state: absent + ignore_errors: true + register: sw_leaf_selec_absent_missing_param + + - name: absent assertions + assert: + that: + - sw_leaf_selec_check_mode_absent is changed + - sw_leaf_selec_check_mode_absent.previous != [] + - sw_leaf_selec_absent is changed + - sw_leaf_selec_absent.previous == sw_leaf_selec_check_mode_absent.previous + - sw_leaf_selec_absent_idempotent is not changed + - sw_leaf_selec_absent_idempotent.previous == [] + - sw_leaf_selec_absent_missing_param is failed + - 'sw_leaf_selec_absent_missing_param.msg == "state is absent but all of the following are missing: leaf"' + + + - name: Remove switch policy leaf profile selector - Clean up + cisco.aci.aci_switch_leaf_selector: + <<: *aci_switch_leaf_selector_absent + state: absent + + - name: Deleting Switch Policy Leaf profile exists for kick off + cisco.aci.aci_switch_policy_leaf_profile: + <<: *aci_switch_policy_leaf_profile_present + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_switch_policy_leaf_profile/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_switch_policy_leaf_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_switch_policy_leaf_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_switch_policy_leaf_profile/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_switch_policy_leaf_profile/tasks/main.yml new file mode 100644 index 000000000..2bed3b67c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_switch_policy_leaf_profile/tasks/main.yml @@ -0,0 +1,219 @@ +# Test code for the ACI modules +# 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) + +- 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 + block: # block specifies execution of tasks within, based on conditions + # CLEAN ENVIRONMENT + - name: Remove leaf profile + cisco.aci.aci_switch_policy_leaf_profile: &aci_switch_policy_leaf_profile_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") }}' + leaf_profile: ansible_test + state: absent + + + # ADD LEAF PROFILE + - name: Add switch policy leaf profile (check_mode) + cisco.aci.aci_switch_policy_leaf_profile: &aci_switch_policy_leaf_profile_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") }}' + leaf_profile: ansible_test + state: present + check_mode: true + register: cm_add_switch_leaf_profile + + - name: Add leaf profile (normal mode) + cisco.aci.aci_switch_policy_leaf_profile: *aci_switch_policy_leaf_profile_present + register: nm_add_switch_leaf_profile + + - name: Add leaf profile again (check_mode) + cisco.aci.aci_switch_policy_leaf_profile: *aci_switch_policy_leaf_profile_present + check_mode: true + register: cm_add_switch_leaf_profile_again + + - name: Add leaf profile again (normal mode) + cisco.aci.aci_switch_policy_leaf_profile: *aci_switch_policy_leaf_profile_present + register: nm_add_switch_leaf_profile_again + + - name: Verify add_switch_leaf_profile + assert: + that: + - cm_add_switch_leaf_profile is changed + - nm_add_switch_leaf_profile is changed + - nm_add_switch_leaf_profile.current.0.infraNodeP.attributes.annotation == 'orchestrator:ansible' + - cm_add_switch_leaf_profile_again is not changed + - nm_add_switch_leaf_profile_again is not changed + + + # CHANGE SWITCH LEAF PROFILE + - name: Change description of leaf profile (check_mode) + cisco.aci.aci_switch_policy_leaf_profile: + <<: *aci_switch_policy_leaf_profile_present + description: Ansible test leaf profile + check_mode: true + register: cm_add_switch_leaf_profile_descr + + - name: Change description of leaf profile (normal mode) + cisco.aci.aci_switch_policy_leaf_profile: + <<: *aci_switch_policy_leaf_profile_present + description: Ansible test leaf profile + register: nm_add_switch_leaf_profile_descr + + - name: Change description of leaf profile again (check_mode) + cisco.aci.aci_switch_policy_leaf_profile: + <<: *aci_switch_policy_leaf_profile_present + description: Ansible test leaf profile + check_mode: true + register: cm_add_switch_leaf_profile_descr_again + + - name: Change description of leaf profile again (normal mode) + cisco.aci.aci_switch_policy_leaf_profile: + <<: *aci_switch_policy_leaf_profile_present + description: Ansible test leaf profile + register: nm_add_switch_leaf_profile_descr_again + + - name: Verify add_switch_leaf_profile_descr + assert: + that: + - cm_add_switch_leaf_profile_descr is changed + - nm_add_switch_leaf_profile_descr is changed + - cm_add_switch_leaf_profile_descr_again is not changed + - nm_add_switch_leaf_profile_descr_again is not changed + + + # ADD LEAF PROFILE AGAIN + - name: Add leaf profile again with no description (check_mode) + cisco.aci.aci_switch_policy_leaf_profile: *aci_switch_policy_leaf_profile_present + check_mode: true + register: cm_add_switch_leaf_profile_again_no_descr + + - name: Add leaf profile again with no description (normal mode) + cisco.aci.aci_switch_policy_leaf_profile: *aci_switch_policy_leaf_profile_present + register: nm_add_switch_leaf_profile_again_no_descr + + - name: Verify add_switch_leaf_profile_again_no_descr + assert: + that: + - cm_add_switch_leaf_profile_again_no_descr is not changed + - nm_add_switch_leaf_profile_again_no_descr is not changed + + + # QUERY ALL LEAF PROFILES + - name: Query all profiles (check_mode) + cisco.aci.aci_switch_policy_leaf_profile: &aci_switch_policy_leaf_profile_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") }}' + state: query + check_mode: true + register: cm_query_all_switch_leaf_profiles + + - name: Query all switch_leaf_profiles (normal mode) + cisco.aci.aci_switch_policy_leaf_profile: *aci_switch_policy_leaf_profile_query + register: nm_query_all_switch_leaf_profiles + + - name: Verify query_all_switch_leaf_profiles + assert: + that: + - cm_query_all_switch_leaf_profiles is not changed + - nm_query_all_switch_leaf_profiles is not changed + # NOTE: Order of switch_leaf_profiles is not stable between calls + #- cm_query_all_switch_leaf_profiles == nm_query_all_switch_leaf_profiles + + + # QUERY A LEAF PROFILE + - name: Query our switch_leaf_profile + cisco.aci.aci_switch_policy_leaf_profile: + <<: *aci_switch_policy_leaf_profile_query + leaf_profile: ansible_test + check_mode: true + register: cm_query_switch_leaf_profile + + - name: Query our switch_leaf_profile + cisco.aci.aci_switch_policy_leaf_profile: + <<: *aci_switch_policy_leaf_profile_query + leaf_profile: ansible_test + register: nm_query_switch_leaf_profile + + - name: Verify query_switch_leaf_profile + assert: + that: + - cm_query_switch_leaf_profile is not changed + - nm_query_switch_leaf_profile is not changed + - cm_query_switch_leaf_profile == nm_query_switch_leaf_profile + + + # REMOVE LEAF PROFILE + - name: Remove switch_leaf_profile (check_mode) + cisco.aci.aci_switch_policy_leaf_profile: *aci_switch_policy_leaf_profile_absent + check_mode: true + register: cm_remove_switch_leaf_profile + + - name: Remove switch_leaf_profile (normal mode) + cisco.aci.aci_switch_policy_leaf_profile: *aci_switch_policy_leaf_profile_absent + register: nm_remove_switch_leaf_profile + + - name: Remove switch_leaf_profile again (check_mode) + cisco.aci.aci_switch_policy_leaf_profile: *aci_switch_policy_leaf_profile_absent + check_mode: true + register: cm_remove_switch_leaf_profile_again + + - name: Remove switch_leaf_profile again (normal mode) + cisco.aci.aci_switch_policy_leaf_profile: *aci_switch_policy_leaf_profile_absent + register: nm_remove_switch_leaf_profile_again + + - name: Verify remove_switch_leaf_profile + assert: + that: + - cm_remove_switch_leaf_profile is changed + - nm_remove_switch_leaf_profile is changed + - cm_remove_switch_leaf_profile_again is not changed + - nm_remove_switch_leaf_profile_again is not changed + + + # QUERY NON-EXISTING LEAF PROFILE + - name: Query non-existing switch_leaf_profile (check_mode) + cisco.aci.aci_switch_policy_leaf_profile: + <<: *aci_switch_policy_leaf_profile_query + leaf_profile: ansible_test + check_mode: true + register: cm_query_non_switch_leaf_profile + + - name: Query non-existing switch_leaf_profile (normal mode) + cisco.aci.aci_switch_policy_leaf_profile: + <<: *aci_switch_policy_leaf_profile_query + leaf_profile: ansible_test + register: nm_query_non_switch_leaf_profile + + # TODO: Implement more tests + - name: Verify query_non_switch_leaf_profile + assert: + that: + - cm_query_non_switch_leaf_profile is not changed + - nm_query_non_switch_leaf_profile is not changed + - cm_query_non_switch_leaf_profile == nm_query_non_switch_leaf_profile diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_switch_policy_vpc_protection_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_switch_policy_vpc_protection_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_switch_policy_vpc_protection_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_switch_policy_vpc_protection_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_switch_policy_vpc_protection_group/tasks/main.yml new file mode 100644 index 000000000..c0ef39cfe --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_switch_policy_vpc_protection_group/tasks/main.yml @@ -0,0 +1,214 @@ +# Test code for the ACI modules +# 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) + +- 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 + +# CLEAN ENVIRONMENT +- name: Remove vpc protection group + cisco.aci.aci_switch_policy_vpc_protection_group: &aci_switch_policy_vpc_protection_group_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") }}' + protection_group: ansible_test + state: absent + + +# ADD VPC PROTECTION GROUP +- name: Add vpc protection group (check_mode) + cisco.aci.aci_switch_policy_vpc_protection_group: &aci_switch_policy_vpc_protection_group_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") }}' + protection_group: ansible_test + protection_group_id: 6 + switch_1_id: 3811 + switch_2_id: 3812 + state: present + check_mode: true + register: cm_add_vpc_prot_grp + +- name: Add vpc protection group (normal mode) + cisco.aci.aci_switch_policy_vpc_protection_group: *aci_switch_policy_vpc_protection_group_present + register: nm_add_vpc_prot_grp + +- name: Add vpc protection group again (check_mode) + cisco.aci.aci_switch_policy_vpc_protection_group: *aci_switch_policy_vpc_protection_group_present + check_mode: true + register: cm_add_vpc_prot_grp_again + +- name: Add vpc protection group again (normal mode) + cisco.aci.aci_switch_policy_vpc_protection_group: *aci_switch_policy_vpc_protection_group_present + register: nm_add_vpc_prot_grp_again + +- name: Verify add_vpc_prot_grp_again + assert: + that: + - cm_add_vpc_prot_grp is changed + - nm_add_vpc_prot_grp is changed + - nm_add_vpc_prot_grp.current.0.fabricExplicitGEp.attributes.annotation == 'orchestrator:ansible' + - cm_add_vpc_prot_grp_again is not changed + - nm_add_vpc_prot_grp_again is not changed + + +# CHANGE VPC PROTECTION GROUP +- name: Change vpc domain policy of vpc protection group (check_mode) + cisco.aci.aci_switch_policy_vpc_protection_group: + <<: *aci_switch_policy_vpc_protection_group_present + vpc_domain_policy: ansible_test_pol + check_mode: true + register: cm_add_vpc_prot_grp_pol + +- name: Change vpc domain policy of vpc protection group (normal mode) + cisco.aci.aci_switch_policy_vpc_protection_group: + <<: *aci_switch_policy_vpc_protection_group_present + vpc_domain_policy: ansible_test_pol + register: nm_add_vpc_prot_grp_pol + +- name: Change vpc domain policy of vpc protection group again (check_mode) + cisco.aci.aci_switch_policy_vpc_protection_group: + <<: *aci_switch_policy_vpc_protection_group_present + vpc_domain_policy: ansible_test_pol + check_mode: true + register: cm_add_vpc_prot_grp_pol_again + +- name: Change vpc domain policy of vpc protection group again (normal mode) + cisco.aci.aci_switch_policy_vpc_protection_group: + <<: *aci_switch_policy_vpc_protection_group_present + vpc_domain_policy: ansible_test_pol + register: nm_add_vpc_prot_grp_pol_again + +- name: Verify add_vpc_prot_grp_pol + assert: + that: + - cm_add_vpc_prot_grp_pol is changed + - nm_add_vpc_prot_grp_pol is changed + - cm_add_vpc_prot_grp_pol_again is not changed + - nm_add_vpc_prot_grp_pol_again is not changed + + +# ADD FABRIC NODE AGAIN +- name: Add vpc protection group again with no domain policy (check_mode) + cisco.aci.aci_switch_policy_vpc_protection_group: *aci_switch_policy_vpc_protection_group_present + check_mode: true + register: cm_add_vpc_prot_grp_again_no_pol + +- name: Add vpc protection group again with no domain policy (normal mode) + cisco.aci.aci_switch_policy_vpc_protection_group: *aci_switch_policy_vpc_protection_group_present + register: nm_add_vpc_prot_grp_again_no_pol + +- name: Verify add_vpc_prot_grp_again_no_pol + assert: + that: + - cm_add_vpc_prot_grp_again_no_pol is not changed + - nm_add_vpc_prot_grp_again_no_pol is not changed + + +# QUERY ALL VPC PROTECTION GROUPS +- name: Query vpc protection groups (check_mode) + cisco.aci.aci_switch_policy_vpc_protection_group: &aci_switch_policy_vpc_protection_group_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") }}' + state: query + check_mode: true + register: cm_query_all_vpc_prot_grps + +- name: Query all vpc protection groups (normal mode) + cisco.aci.aci_switch_policy_vpc_protection_group: *aci_switch_policy_vpc_protection_group_query + register: nm_query_all_vpc_prot_grps + +- name: Verify query_all_vpc_prot_grps + assert: + that: + - cm_query_all_vpc_prot_grps is not changed + - nm_query_all_vpc_prot_grps is not changed + - cm_query_all_vpc_prot_grps == nm_query_all_vpc_prot_grps + + +# QUERY A VPC PROTECTION GROUP +- name: Query our vpc protection group + cisco.aci.aci_switch_policy_vpc_protection_group: + <<: *aci_switch_policy_vpc_protection_group_query + protection_group: ansible_test # might need node_id too + check_mode: true + register: cm_query_vpc_prot_grp + +- name: Query our vpc protection group + cisco.aci.aci_switch_policy_vpc_protection_group: + <<: *aci_switch_policy_vpc_protection_group_query + protection_group: ansible_test + register: nm_query_vpc_prot_grp + +- name: Verify query_vpc_prot_grp + assert: + that: + - cm_query_vpc_prot_grp is not changed + - nm_query_vpc_prot_grp is not changed + - cm_query_vpc_prot_grp == nm_query_vpc_prot_grp + + +# REMOVE FABRIC NODE +- name: Remove vpc protection group (check_mode) + cisco.aci.aci_switch_policy_vpc_protection_group: *aci_switch_policy_vpc_protection_group_absent + check_mode: true + register: cm_remove_vpc_prot_grp + +- name: Remove vpc protection group (normal mode) + cisco.aci.aci_switch_policy_vpc_protection_group: *aci_switch_policy_vpc_protection_group_absent + register: nm_remove_vpc_prot_grp + +- name: Remove vpc protection group again (check_mode) + cisco.aci.aci_switch_policy_vpc_protection_group: *aci_switch_policy_vpc_protection_group_absent + check_mode: true + register: cm_remove_vpc_prot_grp_again + +- name: Remove vpc protection group again (normal mode) + cisco.aci.aci_switch_policy_vpc_protection_group: *aci_switch_policy_vpc_protection_group_absent + register: nm_remove_vpc_prot_grp_again + +- name: Verify remove_vpc_prot_grp + assert: + that: + - cm_remove_vpc_prot_grp is changed + - nm_remove_vpc_prot_grp is changed + - cm_remove_vpc_prot_grp_again is not changed + - nm_remove_vpc_prot_grp_again is not changed + + +# QUERY NON-EXISTING LEAF PROFILE +- name: Query non-existing vpc protection group (check_mode) + cisco.aci.aci_switch_policy_vpc_protection_group: + <<: *aci_switch_policy_vpc_protection_group_query + protection_group: ansible_test + check_mode: true + register: cm_query_non_vpc_prot_grp + +- name: Query non-existing vpc protection group (normal mode) + cisco.aci.aci_switch_policy_vpc_protection_group: + <<: *aci_switch_policy_vpc_protection_group_query + protection_group: ansible_test + register: nm_query_non_vpc_prot_grp + +- name: Verify query_non_vpc_prot_grp + assert: + that: + - cm_query_non_vpc_prot_grp is not changed + - nm_query_non_vpc_prot_grp is not changed + - cm_query_non_vpc_prot_grp == nm_query_non_vpc_prot_grp diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_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_syslog_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_group/tasks/main.yml new file mode 100644 index 000000000..f80ca35d2 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_group/tasks/main.yml @@ -0,0 +1,245 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_syslog_group if it already exists + cisco.aci.aci_syslog_group: + <<: *aci_info + name: ansible_syslog_group + state: absent + +# ADD syslog group +- name: Add syslog group (version >= 4) + cisco.aci.aci_syslog_group: &aci_syslog_present + <<: *aci_info + name: ansible_syslog_group + admin_state: enabled + format: aci + local_file_logging: enabled + local_file_log_severity: warnings + console_logging: enabled + console_log_severity: critical + include_ms: true + include_time_zone: true + state: present + register: add_syslog_group + when: version.current.0.topSystem.attributes.version is version('4', '>=') + +- name: Add syslog group (version < 4) + cisco.aci.aci_syslog_group: &aci_syslog_present_32 + <<: *aci_info + name: ansible_syslog_group + admin_state: enabled + format: aci + local_file_logging: enabled + local_file_log_severity: warnings + console_logging: enabled + console_log_severity: critical + include_ms: true + state: present + register: add_syslog_group_32 + when: version.current.0.topSystem.attributes.version is version('4', '<') + +- name: Verify that ansible_syslog_group has been created with correct attributes (version > 4) + assert: + that: + - add_syslog_group.current.0.syslogGroup.attributes.dn == "uni/fabric/slgroup-ansible_syslog_group" + - add_syslog_group.current.0.syslogGroup.attributes.name == "ansible_syslog_group" + - add_syslog_group.current.0.syslogGroup.attributes.format == "aci" + - add_syslog_group.current.0.syslogGroup.attributes.includeMilliSeconds == "yes" + - add_syslog_group.current.0.syslogGroup.attributes.includeTimeZone == "yes" + - add_syslog_group.current.0.syslogGroup.attributes.annotation == 'orchestrator:ansible' + when: version.current.0.topSystem.attributes.version is version('4', '>=') + +- name: Verify that ansible_syslog_group has been created with correct attributes (version < 4) + assert: + that: + - add_syslog_group_32.current.0.syslogGroup.attributes.dn == "uni/fabric/slgroup-ansible_syslog_group" + - add_syslog_group_32.current.0.syslogGroup.attributes.name == "ansible_syslog_group" + - add_syslog_group_32.current.0.syslogGroup.attributes.format == "aci" + - add_syslog_group_32.current.0.syslogGroup.attributes.includeMilliSeconds == "yes" + - add_syslog_group_32.current.0.syslogGroup.attributes.annotation == 'orchestrator:ansible' + when: version.current.0.topSystem.attributes.version is version('4', '<') + +- name: Verify that ansible_syslog_group children have correct attributes (version >= 4) + assert: + that: + - add_syslog_group.current.0.syslogGroup.children.0.syslogConsole.attributes.adminState == "enabled" + - add_syslog_group.current.0.syslogGroup.children.0.syslogConsole.attributes.severity == "critical" + - add_syslog_group.current.0.syslogGroup.children.1.syslogFile.attributes.adminState == "enabled" + - add_syslog_group.current.0.syslogGroup.children.1.syslogFile.attributes.severity == "warnings" + - add_syslog_group.current.0.syslogGroup.children.2.syslogProf.attributes.adminState == "enabled" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + +- name: Verify that ansible_syslog_group children have correct attributes (version < 4) + assert: + that: + - add_syslog_group_32.current.0.syslogGroup.children.0.syslogConsole.attributes.adminState == "enabled" + - add_syslog_group_32.current.0.syslogGroup.children.0.syslogConsole.attributes.severity == "critical" + - add_syslog_group_32.current.0.syslogGroup.children.1.syslogFile.attributes.adminState == "enabled" + - add_syslog_group_32.current.0.syslogGroup.children.1.syslogFile.attributes.severity == "warnings" + - add_syslog_group_32.current.0.syslogGroup.children.2.syslogProf.attributes.adminState == "enabled" + when: version.current.0.topSystem.attributes.version is version('4', '<') + +# ADD syslog group again to check idempotency +- name: Add syslog group again (version >= 4) + cisco.aci.aci_syslog_group: + <<: *aci_syslog_present + register: add_syslog_group_again + when: version.current.0.topSystem.attributes.version is version('4', '>=') + +- name: Add syslog group again (version < 4) + cisco.aci.aci_syslog_group: + <<: *aci_syslog_present_32 + register: add_syslog_group_again_32 + when: version.current.0.topSystem.attributes.version is version('4', '<') + +- name: Verify that ansible_syslog_group stays the same (version >= 4) + assert: + that: + - add_syslog_group_again is not changed + when: version.current.0.topSystem.attributes.version is version('4', '>=') + +- name: Verify that ansible_syslog_group stays the same (version < 4) + assert: + that: + - add_syslog_group_again_32 is not changed + when: version.current.0.topSystem.attributes.version is version('4', '<') + +# MODIFY syslog group +- name: Update syslog group (version >= 4) + cisco.aci.aci_syslog_group: + <<: *aci_info + name: ansible_syslog_group + admin_state: disabled + format: nxos + local_file_logging: enabled + local_file_log_severity: debugging + console_logging: disabled + console_log_severity: emergencies + include_ms: false + include_time_zone: false + state: present + register: update_syslog_group + when: version.current.0.topSystem.attributes.version is version('4', '>=') + +- name: Update syslog group (version < 4) + cisco.aci.aci_syslog_group: + <<: *aci_info + name: ansible_syslog_group + admin_state: disabled + format: nxos + local_file_logging: enabled + local_file_log_severity: debugging + console_logging: disabled + console_log_severity: emergencies + include_ms: false + state: present + register: update_syslog_group_32 + when: version.current.0.topSystem.attributes.version is version('4', '<') + +- name: Verify that ansible_syslog_group has been updated with correct attributes (version >= 4) + assert: + that: + - update_syslog_group.current.0.syslogGroup.attributes.dn == "uni/fabric/slgroup-ansible_syslog_group" + - update_syslog_group.current.0.syslogGroup.attributes.name == "ansible_syslog_group" + - update_syslog_group.current.0.syslogGroup.attributes.format == "nxos" + - update_syslog_group.current.0.syslogGroup.attributes.includeMilliSeconds == "no" + - update_syslog_group.current.0.syslogGroup.attributes.includeTimeZone == "no" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + +- name: Verify that ansible_syslog_group has been updated with correct attributes (version < 4) + assert: + that: + - update_syslog_group_32.current.0.syslogGroup.attributes.dn == "uni/fabric/slgroup-ansible_syslog_group" + - update_syslog_group_32.current.0.syslogGroup.attributes.name == "ansible_syslog_group" + - update_syslog_group_32.current.0.syslogGroup.attributes.format == "nxos" + - update_syslog_group_32.current.0.syslogGroup.attributes.includeMilliSeconds == "no" + when: version.current.0.topSystem.attributes.version is version('4', '<') + +- name: Verify that ansible_syslog_group children have correct attributes (version >= 4) + assert: + that: + - update_syslog_group.current.0.syslogGroup.children.0.syslogConsole.attributes.adminState == "disabled" + - update_syslog_group.current.0.syslogGroup.children.0.syslogConsole.attributes.severity == "emergencies" + - update_syslog_group.current.0.syslogGroup.children.1.syslogFile.attributes.adminState == "enabled" + - update_syslog_group.current.0.syslogGroup.children.1.syslogFile.attributes.severity == "debugging" + - update_syslog_group.current.0.syslogGroup.children.2.syslogProf.attributes.adminState == "disabled" + when: version.current.0.topSystem.attributes.version is version('4', '>=') + +- name: Verify that ansible_syslog_group children have correct attributes (version < 4) + assert: + that: + - update_syslog_group_32.current.0.syslogGroup.children.0.syslogConsole.attributes.adminState == "disabled" + - update_syslog_group_32.current.0.syslogGroup.children.0.syslogConsole.attributes.severity == "emergencies" + - update_syslog_group_32.current.0.syslogGroup.children.1.syslogFile.attributes.adminState == "enabled" + - update_syslog_group_32.current.0.syslogGroup.children.1.syslogFile.attributes.severity == "debugging" + - update_syslog_group_32.current.0.syslogGroup.children.2.syslogProf.attributes.adminState == "disabled" + when: version.current.0.topSystem.attributes.version is version('4', '<') + +# QUERY syslog group +- name: Query the syslog group + cisco.aci.aci_syslog_group: + <<: *aci_info + name: ansible_syslog_group + state: query + register: query_syslog_group + +- name: Verify the attributes under query_syslog_group + assert: + that: + - query_syslog_group is not changed + - query_syslog_group.current.0.syslogGroup.attributes.dn == "uni/fabric/slgroup-ansible_syslog_group" + - query_syslog_group.current.0.syslogGroup.attributes.name == "ansible_syslog_group" + +- name: Query all syslog groups + cisco.aci.aci_syslog_group: + <<: *aci_info + state: query + register: query_syslog_group_all + +- name: Verify query_syslog_group_all + assert: + that: + - query_syslog_group_all is not changed + +# DELETE syslog group +- name: Remove the syslog group + cisco.aci.aci_syslog_group: + <<: *aci_info + name: ansible_syslog_group + state: absent + register: remove_syslog_group + +- name: Verify remove_syslog_group + assert: + that: + - remove_syslog_group is changed + - remove_syslog_group.previous.0.syslogGroup.attributes.dn == "uni/fabric/slgroup-ansible_syslog_group" + - remove_syslog_group.previous.0.syslogGroup.attributes.name == "ansible_syslog_group" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_remote_dest/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_remote_dest/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_remote_dest/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..0840aec20 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_remote_dest/tasks/main.yml @@ -0,0 +1,197 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_syslog_src if it already exists + aci_syslog_remote_dest: + <<: *aci_info + group: ansible_syslog_group + destination: "10.20.30.40" + state: absent + +# ADD syslog group +- name: Add syslog group + aci_syslog_group: + <<: *aci_info + name: ansible_syslog_group + admin_state: enabled + state: present + +# ADD syslog remote destination +- name: Add syslog remote destination + aci_syslog_remote_dest: + <<: *aci_info + group: ansible_syslog_group + destination: "10.20.30.40" + name: remote_destination_name + facility: local1 + syslog_port: 5678 + description: ansible syslog remote destination + mgmt_epg: oob-default + format: aci + admin_state: enabled + severity: warnings + state: present + register: add_syslog_remote_dest + +- name: Verify that ansible_syslog_src has been created with correct attributes + assert: + that: + - add_syslog_remote_dest.current.0.syslogRemoteDest.attributes.dn == "uni/fabric/slgroup-ansible_syslog_group/rdst-10.20.30.40" + - add_syslog_remote_dest.current.0.syslogRemoteDest.attributes.name == "remote_destination_name" + - add_syslog_remote_dest.current.0.syslogRemoteDest.attributes.descr == "ansible syslog remote destination" + - add_syslog_remote_dest.current.0.syslogRemoteDest.attributes.format == "aci" + - add_syslog_remote_dest.current.0.syslogRemoteDest.attributes.forwardingFacility == "local1" + - add_syslog_remote_dest.current.0.syslogRemoteDest.attributes.host == "10.20.30.40" + - add_syslog_remote_dest.current.0.syslogRemoteDest.attributes.port == "5678" + - 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" + +# ADD syslog remote dest again to check idempotency +- name: Add syslog remote dest + aci_syslog_remote_dest: + <<: *aci_info + group: ansible_syslog_group + destination: "10.20.30.40" + name: remote_destination_name + facility: local1 + syslog_port: 5678 + description: ansible syslog remote destination + mgmt_epg: oob-default + format: aci + admin_state: enabled + severity: warnings + state: present + register: add_syslog_remote_dest_again + +- name: Verify that ansible_syslog_remote_dest stays the same + assert: + that: + - add_syslog_remote_dest_again is not changed + +# MODIFY syslog remote destination +- name: Update the syslog remote destination + aci_syslog_remote_dest: + <<: *aci_info + group: ansible_syslog_group + destination: "10.20.30.40" + name: new_remote_destination_name + facility: local7 + syslog_port: 5679 + description: new ansible syslog remote destination + mgmt_epg: oob-default + format: nxos + admin_state: disabled + severity: information + state: present + register: update_syslog_remote_dest + +- name: Verify that ansible_syslog_src has been updated with correct attributes + assert: + that: + - update_syslog_remote_dest.current.0.syslogRemoteDest.attributes.dn == "uni/fabric/slgroup-ansible_syslog_group/rdst-10.20.30.40" + - update_syslog_remote_dest.current.0.syslogRemoteDest.attributes.name == "new_remote_destination_name" + - update_syslog_remote_dest.current.0.syslogRemoteDest.attributes.descr == "new ansible syslog remote destination" + - update_syslog_remote_dest.current.0.syslogRemoteDest.attributes.format == "nxos" + - update_syslog_remote_dest.current.0.syslogRemoteDest.attributes.forwardingFacility == "local7" + - update_syslog_remote_dest.current.0.syslogRemoteDest.attributes.host == "10.20.30.40" + - update_syslog_remote_dest.current.0.syslogRemoteDest.attributes.port == "5679" + - update_syslog_remote_dest.current.0.syslogRemoteDest.attributes.adminState == "disabled" + - update_syslog_remote_dest.current.0.syslogRemoteDest.attributes.severity == "information" + +# QUERY syslog source +- name: Query the syslog source + aci_syslog_remote_dest: + <<: *aci_info + group: ansible_syslog_group + destination: "10.20.30.40" + state: query + register: query_syslog_remote_dest + +- name: Verify the attributes under query_syslog_src + assert: + that: + - query_syslog_remote_dest is not changed + - query_syslog_remote_dest.current.0.syslogRemoteDest.attributes.dn == "uni/fabric/slgroup-ansible_syslog_group/rdst-10.20.30.40" + - query_syslog_remote_dest.current.0.syslogRemoteDest.attributes.name == "new_remote_destination_name" + - query_syslog_remote_dest.current.0.syslogRemoteDest.attributes.descr == "new ansible syslog remote destination" + - query_syslog_remote_dest.current.0.syslogRemoteDest.attributes.format == "nxos" + - query_syslog_remote_dest.current.0.syslogRemoteDest.attributes.forwardingFacility == "local7" + - query_syslog_remote_dest.current.0.syslogRemoteDest.attributes.host == "10.20.30.40" + - query_syslog_remote_dest.current.0.syslogRemoteDest.attributes.port == "5679" + - query_syslog_remote_dest.current.0.syslogRemoteDest.attributes.adminState == "disabled" + - query_syslog_remote_dest.current.0.syslogRemoteDest.attributes.severity == "information" + +- name: Query all syslog remote destinations + aci_syslog_remote_dest: + <<: *aci_info + state: query + register: query_syslog_remote_dest_all + +- name: Verify query_syslog_remote_dest_all + assert: + that: + - query_syslog_remote_dest_all is not changed + +# DELETE syslog remote destination +- name: Remove the syslog remote dest + aci_syslog_remote_dest: + <<: *aci_info + group: ansible_syslog_group + destination: "10.20.30.40" + state: absent + register: remove_syslog_remote_dest + +- name: Verify remove_syslog_remote_dest + assert: + that: + - remove_syslog_remote_dest is changed + - remove_syslog_remote_dest.current == [] + - remove_syslog_remote_dest.previous.0.syslogRemoteDest.attributes.dn == "uni/fabric/slgroup-ansible_syslog_group/rdst-10.20.30.40" + +# DELETE syslog remote destination again to test idempotence +- name: Remove the syslog remote dest again + aci_syslog_remote_dest: + <<: *aci_info + group: ansible_syslog_group + destination: "10.20.30.40" + state: absent + register: remove_syslog_remote_dest_again + +- name: Verify remove_syslog_remote_dest idempotence + assert: + that: + - remove_syslog_remote_dest_again is not changed + +# DELETE syslog group +- name: Remove syslog group + aci_syslog_group: + <<: *aci_info + name: ansible_syslog_group + admin_state: enabled + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_source/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_source/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_source/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..c237d17fe --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_syslog_source/tasks/main.yml @@ -0,0 +1,168 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# CLEAN ENVIRONMENT +- name: Remove ansible_syslog_src if it already exists + aci_syslog_source: + <<: *aci_info + name: ansible_syslog_src + state: absent + +# ADD syslog group +- name: Add syslog group + aci_syslog_group: + <<: *aci_info + name: ansible_syslog_group + admin_state: enabled + state: present + +# ADD syslog source +- name: Add syslog source + aci_syslog_source: + <<: *aci_info + name: ansible_syslog_src + include: + - audit + - events + - faults + min_severity: errors + destination_group: ansible_syslog_group + state: present + register: add_syslog_src + +- name: Verify that ansible_syslog_src has been created with correct attributes + assert: + 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.minSev == "errors" + - add_syslog_src.current.0.syslogSrc.attributes.annotation == 'orchestrator:ansible' + +- name: Verify that ansible_syslog_src children have correct attributes + assert: + that: + - add_syslog_src.current.0.syslogSrc.children.0.syslogRsDestGroup.attributes.tDn == "uni/fabric/slgroup-ansible_syslog_group" + +# ADD syslog source again to check idempotency +- name: Add syslog source + aci_syslog_source: + <<: *aci_info + name: ansible_syslog_src + include: + - audit + - events + - faults + min_severity: errors + destination_group: ansible_syslog_group + state: present + register: add_syslog_src_again + +- name: Verify that ansible_syslog_src stays the same + assert: + that: + - add_syslog_src_again is not changed + +# MODIFY syslog source +- name: Update the syslog source + aci_syslog_source: + <<: *aci_info + name: ansible_syslog_src + include: + - faults + min_severity: information + destination_group: ansible_syslog_group + state: present + register: update_syslog_src + +- name: Verify that ansible_syslog_src has been updated with correct attributes + assert: + 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.minSev == "information" + +# QUERY syslog source +- name: Query the syslog source + aci_syslog_source: + <<: *aci_info + name: ansible_syslog_src + state: query + register: query_syslog_src + +- name: Verify the attributes under query_syslog_src + assert: + that: + - 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.minSev == "information" + +- name: Query all syslog sources + aci_syslog_source: + <<: *aci_info + state: query + register: query_syslog_src_all + +- name: Verify query_syslog_src_all + assert: + that: + - query_syslog_src_all is not changed + +# DELETE syslog source +- name: Remove the syslog source + aci_syslog_source: + <<: *aci_info + name: ansible_syslog_src + state: absent + register: remove_syslog_src + +- name: Verify remove_syslog_src + assert: + that: + - remove_syslog_src is changed + - remove_syslog_src.current == [] + - remove_syslog_src.previous.0.syslogSrc.attributes.dn == "uni/fabric/moncommon/slsrc-ansible_syslog_src" + - remove_syslog_src.previous.0.syslogSrc.attributes.name == "ansible_syslog_src" + +# DELETE syslog source again to test idempotence +- name: Remove the syslog source + aci_syslog_source: + <<: *aci_info + name: ansible_syslog_src + state: absent + register: remove_syslog_src_again + +- name: Verify remove_syslog_src idempotence + assert: + that: + - remove_syslog_src_again is not changed + +# DELETE syslog group +- name: Remove syslog group + aci_syslog_group: + <<: *aci_info + name: ansible_syslog_group + admin_state: enabled + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_system/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_system/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_system/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/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_system/tasks/main.yml new file mode 100644 index 000000000..6be69c245 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_system/tasks/main.yml @@ -0,0 +1,63 @@ +# Test code for the ACI modules +# Copyright: (c) 2020, Lionel Hercot (@lhercot) <lhercot@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 + +# CLEAN ENVIRONMENT +- 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") }}' + +# QUERY OBJECTS +- name: Query all controllers system information + aci_system: + <<: *aci_info + state: query + register: query_all + +- name: Verify query_all + assert: + that: + - query_all is not changed + - query_all.current.0.topSystem.attributes.id == "1" + - '"version" in query_all.current.0.topSystem.attributes' + + +- name: Query a specific controller system information + aci_system: + <<: *aci_info + id: 1 + state: query + register: query_controller + +- name: Verify query_controller + assert: + that: + - query_controller is not changed + - query_controller.current.0.topSystem.attributes.id == "1" + - '"version" in query_controller.current.0.topSystem.attributes' + +- name: Query non_existing controller + aci_system: + <<: *aci_info + id: 99 + state: query + register: query_non_existing + +- name: Verify query_non_existing + assert: + that: + - query_non_existing is not changed + - query_non_existing.current == []
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_taboo_contract/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_taboo_contract/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_taboo_contract/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_taboo_contract/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_taboo_contract/tasks/main.yml new file mode 100644 index 000000000..8a5bb5911 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_taboo_contract/tasks/main.yml @@ -0,0 +1,290 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + + +# CLEAN ENVIRONMENT +- name: Remove taboo contract + cisco.aci.aci_taboo_contract: &taboo_contract_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 + taboo_contract: taboo_contract_test + state: absent + +- name: Add 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") }}' + tenant: ansible_test + state: present + + +# ADD TABOO CONTRACT +- name: Add taboo contract (check_mode) + cisco.aci.aci_taboo_contract: &taboo_contract_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 + taboo_contract: taboo_contract_test + state: present + check_mode: true + register: cm_add_taboo_contract + +- name: Add taboo contract (normal mode) + cisco.aci.aci_taboo_contract: *taboo_contract_present + register: nm_add_taboo_contract + +- name: Verify add_taboo_contract + assert: + that: + - cm_add_taboo_contract is changed + - nm_add_taboo_contract is changed + - cm_add_taboo_contract.sent.vzTaboo.attributes.name == nm_add_taboo_contract.sent.vzTaboo.attributes.name == 'taboo_contract_test' + - cm_add_taboo_contract.proposed.vzTaboo.attributes.name == nm_add_taboo_contract.proposed.vzTaboo.attributes.name == 'taboo_contract_test' + - cm_add_taboo_contract.previous == nm_add_taboo_contract.previous == [] + # NOTE: We cannot fix this easily + - cm_add_taboo_contract.current == [] + - nm_add_taboo_contract.current.0.vzTaboo.attributes.descr == '' + - nm_add_taboo_contract.current.0.vzTaboo.attributes.dn == 'uni/tn-ansible_test/taboo-taboo_contract_test' + - nm_add_taboo_contract.current.0.vzTaboo.attributes.name == 'taboo_contract_test' + - nm_add_taboo_contract.current.0.vzTaboo.attributes.annotation == 'orchestrator:ansible' + +- name: Add taboo_contract again (check_mode) + cisco.aci.aci_taboo_contract: *taboo_contract_present + check_mode: true + register: cm_add_taboo_contract_again + +- name: Add taboo contract again (normal mode) + cisco.aci.aci_taboo_contract: *taboo_contract_present + register: nm_add_taboo_contract_again + +- name: Verify add_taboo_contract_again + assert: + that: + - cm_add_taboo_contract_again is not changed + - nm_add_taboo_contract_again is not changed + - cm_add_taboo_contract_again.current == nm_add_taboo_contract_again.current == nm_add_taboo_contract.current + + +# CHANGE TABOO CONTRACT +- name: Change description of taboo contract (check_mode) + cisco.aci.aci_taboo_contract: + <<: *taboo_contract_present + description: Ansible test taboo contract + check_mode: true + register: cm_add_taboo_contract_descr + +- name: Change description of taboo contract (normal mode) + cisco.aci.aci_taboo_contract: + <<: *taboo_contract_present + description: Ansible test taboo contract + register: nm_add_taboo_contract_descr + +- name: Verify add_taboo_contract_descr + assert: + that: + - cm_add_taboo_contract_descr is changed + - nm_add_taboo_contract_descr is changed + - cm_add_taboo_contract_descr.sent.vzTaboo.attributes.descr == nm_add_taboo_contract_descr.sent.vzTaboo.attributes.descr == 'Ansible test taboo contract' + - cm_add_taboo_contract_descr.proposed.vzTaboo.attributes.descr == nm_add_taboo_contract_descr.proposed.vzTaboo.attributes.descr == 'Ansible test taboo contract' + - cm_add_taboo_contract_descr.proposed.vzTaboo.attributes.name == nm_add_taboo_contract_descr.proposed.vzTaboo.attributes.name == 'taboo_contract_test' + - cm_add_taboo_contract_descr.previous == nm_add_taboo_contract_descr.previous == cm_add_taboo_contract_descr.current == nm_add_taboo_contract.current + - nm_add_taboo_contract_descr.current.0.vzTaboo.attributes.descr == 'Ansible test taboo contract' + - nm_add_taboo_contract_descr.current.0.vzTaboo.attributes.dn == 'uni/tn-ansible_test/taboo-taboo_contract_test' + - nm_add_taboo_contract_descr.current.0.vzTaboo.attributes.name == 'taboo_contract_test' + +- name: Change description of taboo contract again (check_mode) + cisco.aci.aci_taboo_contract: + <<: *taboo_contract_present + description: Ansible test taboo contract + check_mode: true + register: cm_add_taboo_contract_descr_again + +- name: Change description of taboo contract again (normal mode) + cisco.aci.aci_taboo_contract: + <<: *taboo_contract_present + description: Ansible test taboo contract + register: nm_add_taboo_contract_descr_again + +- name: Verify add_taboo_contract_descr_again + assert: + that: + - cm_add_taboo_contract_descr_again is not changed + - nm_add_taboo_contract_descr_again is not changed + - cm_add_taboo_contract_descr_again.current == nm_add_taboo_contract_descr_again.current == nm_add_taboo_contract_descr.current + + +# ADD TABOO CONTRACT AGAIN +- name: Add taboo contract again with no description (check_mode) + cisco.aci.aci_taboo_contract: *taboo_contract_present + check_mode: true + register: cm_add_taboo_contract_again_no_descr + +- name: Add taboo contract again with no description (normal mode) + cisco.aci.aci_taboo_contract: *taboo_contract_present + register: nm_add_taboo_contract_again_no_descr + +- name: Verify add_taboo_contract_again_no_descr + assert: + that: + - cm_add_taboo_contract_again_no_descr is not changed + - nm_add_taboo_contract_again_no_descr is not changed + - cm_add_taboo_contract_again_no_descr.current == nm_add_taboo_contract_again_no_descr.current == nm_add_taboo_contract_descr.current + + +# QUERY ALL TABOO CONTRACTS +- name: Query all taboo contracts (check_mode) + cisco.aci.aci_taboo_contract: &taboo_contract_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") }}' + state: query + check_mode: true + register: cm_query_all_taboo_contracts + +- name: Query all taboo contracts (normal mode) + cisco.aci.aci_taboo_contract: *taboo_contract_query + register: nm_query_all_taboo_contracts + +- name: Verify query_all_taboo_contracts + assert: + that: + - cm_query_all_taboo_contracts is not changed + - nm_query_all_taboo_contracts is not changed + - cm_query_all_taboo_contracts == nm_query_all_taboo_contracts + - cm_query_all_taboo_contracts.current|length >= 1 + + +# QUERY A TABOO CONTRACT +- name: Query our taboo contract + cisco.aci.aci_taboo_contract: + <<: *taboo_contract_query + tenant: ansible_test + taboo_contract: taboo_contract_test + check_mode: true + register: cm_query_taboo_contract + +- name: Query our taboo contract + cisco.aci.aci_taboo_contract: + <<: *taboo_contract_query + tenant: ansible_test + taboo_contract: taboo_contract_test + register: nm_query_taboo_contract + +- name: Verify query_taboo_contract + assert: + that: + - cm_query_taboo_contract is not changed + - nm_query_taboo_contract is not changed + - cm_query_taboo_contract == nm_query_taboo_contract + - nm_query_taboo_contract.current.0.vzTaboo.attributes.descr == 'Ansible test taboo contract' + - nm_query_taboo_contract.current.0.vzTaboo.attributes.dn == 'uni/tn-ansible_test/taboo-taboo_contract_test' + - nm_query_taboo_contract.current.0.vzTaboo.attributes.name == 'taboo_contract_test' + + +# REMOVE TABOO CONTRACT +- name: Remove taboo contract (check_mode) + cisco.aci.aci_taboo_contract: *taboo_contract_absent + check_mode: true + register: cm_remove_taboo_contract + +- name: Remove taboo contract (normal mode) + cisco.aci.aci_taboo_contract: *taboo_contract_absent + register: nm_remove_taboo_contract + +- name: Verify remove_taboo_contract + assert: + that: + - cm_remove_taboo_contract is changed + - nm_remove_taboo_contract is changed + - cm_remove_taboo_contract.current.0.vzTaboo.attributes.descr == cm_remove_taboo_contract.previous.0.vzTaboo.attributes.descr == nm_remove_taboo_contract.previous.0.vzTaboo.attributes.descr == 'Ansible test taboo contract' + - cm_remove_taboo_contract.current.0.vzTaboo.attributes.name == cm_remove_taboo_contract.previous.0.vzTaboo.attributes.name == nm_remove_taboo_contract.previous.0.vzTaboo.attributes.name == 'taboo_contract_test' + - cm_remove_taboo_contract.current.0.vzTaboo.attributes.dn == cm_remove_taboo_contract.previous.0.vzTaboo.attributes.dn == nm_remove_taboo_contract.previous.0.vzTaboo.attributes.dn == 'uni/tn-ansible_test/taboo-taboo_contract_test' + - nm_remove_taboo_contract.current == [] + +- name: Remove taboo contract again (check_mode) + cisco.aci.aci_taboo_contract: *taboo_contract_absent + check_mode: true + register: cm_remove_taboo_contract_again + +- name: Remove taboo contract again (normal mode) + cisco.aci.aci_taboo_contract: *taboo_contract_absent + register: nm_remove_taboo_contract_again + +- name: Verify remove_taboo_contract_again + assert: + that: + - cm_remove_taboo_contract_again is not changed + - nm_remove_taboo_contract_again is not changed + - cm_remove_taboo_contract_again.proposed == nm_remove_taboo_contract_again.proposed == {} + - cm_remove_taboo_contract_again.sent == nm_remove_taboo_contract_again.sent == {} + - cm_remove_taboo_contract_again.previous == nm_remove_taboo_contract_again.previous == [] + - cm_remove_taboo_contract_again.current == nm_remove_taboo_contract_again.current == [] + + +# QUERY NON-EXISTING TABOO CONTRACT +- name: Query non-existing taboo contract (check_mode) + cisco.aci.aci_taboo_contract: + <<: *taboo_contract_query + tenant: ansible_test + taboo_contract: taboo_contract_test + check_mode: true + register: cm_query_non_taboo_contract + +- name: Query non-existing taboo contract (normal mode) + cisco.aci.aci_taboo_contract: + <<: *taboo_contract_query + tenant: ansible_test + taboo_contract: taboo_contract_test + register: nm_query_non_taboo_contract + +# TODO: Implement more tests +- name: Verify query_non_taboo_contract + assert: + that: + - cm_query_non_taboo_contract is not changed + - nm_query_non_taboo_contract is not changed + - cm_remove_taboo_contract_again.previous == nm_remove_taboo_contract_again.previous == [] + - cm_remove_taboo_contract_again.current == nm_remove_taboo_contract_again.current == [] + + +# PROVOKE ERRORS +- name: Error when required parameter is missing + cisco.aci.aci_taboo_contract: + 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") }}' + state: present + ignore_errors: true + register: error_on_missing_required_param + +- name: Verify error_on_missing_required_param + assert: + that: + - error_on_missing_required_param is failed + - 'error_on_missing_required_param.msg == "state is present but all of the following are missing: tenant, taboo_contract"' diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tag/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_tag/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tag/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tag/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_tag/tasks/main.yml new file mode 100644 index 000000000..e5a13ba7b --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tag/tasks/main.yml @@ -0,0 +1,424 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) +# Copyright: (c) 2020, Shreyas Srish (@shrsr) + +# 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: Remove tenant to cleanup + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_test + state: absent + +- name: Add tenant + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_test + state: present + register: query_result + +- name: Get DN + set_fact: + dn: "{{ query_result.current[0].fvTenant.attributes.dn }}" + +- name: Annotation Create tag (check_mode) + cisco.aci.aci_tag: &annotation_present + <<: *aci_info + tag_key: foo + tag_value: bar + tag_type: annotation + dn: "{{ dn }}" + state: present + check_mode: true + register: cm_annotation_create + +- name: Annotation Create tag (normal_mode) + cisco.aci.aci_tag: + <<: *annotation_present + state: present + register: nm_annotation_create + +- name: Annotation tag created + assert: + that: + - cm_annotation_create is changed + - cm_annotation_create.proposed.tagAnnotation.attributes.value == "bar" + - nm_annotation_create is changed + - nm_annotation_create.current.0.tagAnnotation.attributes.key == "foo" + - nm_annotation_create.current.0.tagAnnotation.attributes.value == "bar" + +- name: Annotation Create tag again (check_mode) + cisco.aci.aci_tag: + <<: *annotation_present + state: present + check_mode: true + register: cm_annotation_create_again + +- name: Annotation Create tag (normal_mode) + cisco.aci.aci_tag: + <<: *annotation_present + state: present + register: nm_annotation_create_again + +- name: Annotation tag create again + assert: + that: + - cm_annotation_create_again is not changed + - cm_annotation_create_again.current.0.tagAnnotation.attributes.key == "foo" + - cm_annotation_create_again.current.0.tagAnnotation.attributes.value == "bar" + - nm_annotation_create_again is not changed + - nm_annotation_create_again.current.0.tagAnnotation.attributes.key == "foo" + - nm_annotation_create_again.current.0.tagAnnotation.attributes.value == "bar" + +- name: Annotation Query tag + cisco.aci.aci_tag: + <<: *annotation_present + state: query + register: annotation_query_result + +- name: Annotation tag query verification + assert: + that: + - annotation_query_result is not changed + - annotation_query_result.current.0.tagAnnotation.attributes.key == "foo" + - annotation_query_result.current.0.tagAnnotation.attributes.value == "bar" + +- name: Annotation Query all tags + cisco.aci.aci_tag: + <<: *annotation_present + dn: "{{ fake_var | default(omit) }}" + tag_key: "{{ fake_var | default(omit) }}" + state: query + register: annotation_query_all + +- name: Annotation tag query verification + assert: + that: + - annotation_query_all is not changed + +- name: Annotation tag query verification (continued) + assert: + that: + - annotation_query_all.current.0.tagAnnotation.attributes.key == "foo" + - annotation_query_all.current.0.tagAnnotation.attributes.value == "bar" + when: query_cloud.current == [] # This condition will skip execution for cloud sites + +- name: Annotation Delete tag (check_mode) + cisco.aci.aci_tag: &annotation_absent + <<: *annotation_present + tag_value: "{{ fake_var | default(omit) }}" + state: absent + check_mode: true + register: cm_annotation_delete + +- name: Annotation Delete tag (normal_mode) + cisco.aci.aci_tag: + <<: *annotation_absent + state: absent + register: nm_annotation_delete + +- name: Annotation tag deleted + assert: + that: + - cm_annotation_delete is changed + - nm_annotation_delete is changed + - cm_annotation_delete.proposed.tagAnnotation is not defined + - nm_annotation_delete.current.0.tagAnnotation is not defined + - cm_annotation_delete.previous.0.tagAnnotation.attributes.key == "foo" + - nm_annotation_delete.previous.0.tagAnnotation.attributes.key == "foo" + - cm_annotation_delete.previous.0.tagAnnotation.attributes.value == "bar" + - nm_annotation_delete.previous.0.tagAnnotation.attributes.value == "bar" + +- name: Annotation Delete tag again (check_mode) + cisco.aci.aci_tag: + <<: *annotation_absent + state: absent + check_mode: true + register: cm_annotation_delete_again + +- name: Annotation Delete tag again (normal_mode) + cisco.aci.aci_tag: + <<: *annotation_absent + state: absent + register: nm_annotation_delete_again + +- name: Annotation tag deleted again + assert: + that: + - cm_annotation_delete_again is not changed + - nm_annotation_delete_again is not changed + - cm_annotation_delete_again.current.0.tagAnnotation is not defined + - nm_annotation_delete_again.current.0.tagAnnotation is not defined + - cm_annotation_delete_again.previous.0.tagAnnotation is not defined + - nm_annotation_delete_again.previous.0.tagAnnotation is not defined + +- name: Instance Create tag (check_mode) + cisco.aci.aci_tag: &instance_present + <<: *aci_info + tag_key: foo + tag_type: instance + dn: "{{ dn }}" + state: present + check_mode: true + register: cm_instance_create + +- name: Instance Create tag (normal_mode) + cisco.aci.aci_tag: + <<: *instance_present + state: present + register: nm_instance_create + +- name: Instance tag created + assert: + that: + - cm_instance_create is changed + - nm_instance_create is changed + - nm_instance_create.current.0.tagInst.attributes.name == "foo" + +- name: Instance Create tag again (check_mode) + cisco.aci.aci_tag: + <<: *instance_present + state: present + check_mode: true + register: cm_instance_create_again + +- name: Instance Create tag (normal_mode) + cisco.aci.aci_tag: + <<: *instance_present + state: present + register: nm_instance_create_again + +- name: Instance tag create again + assert: + that: + - cm_instance_create_again is not changed + - cm_instance_create_again.current.0.tagInst.attributes.name == "foo" + - nm_instance_create_again is not changed + - nm_instance_create_again.current.0.tagInst.attributes.name == "foo" + +- name: Instance Query tag + cisco.aci.aci_tag: + <<: *instance_present + state: query + register: instance_query_result + +- name: Instance tag query verification + assert: + that: + - instance_query_result is not changed + - instance_query_result.current.0.tagInst.attributes.name == "foo" + +- name: Instance Query all tags + cisco.aci.aci_tag: + <<: *instance_present + dn: "{{ fake_var | default(omit) }}" + tag_key: "{{ fake_var | default(omit) }}" + state: query + register: instance_query_all + +- name: Instance tag query verification + assert: + that: + - instance_query_all is not changed + +- name: Instance tag query verification (continued) + assert: + that: + - instance_query_all.current.0.tagInst.attributes.name == "foo" + when: query_cloud.current == [] # This condition will skip execution for cloud sites + +- name: Instance Delete tag (check_mode) + cisco.aci.aci_tag: &instance_absent + <<: *instance_present + tag_value: "{{ fake_var | default(omit) }}" + state: absent + check_mode: true + register: cm_instance_delete + +- name: Instance Delete tag (normal_mode) + cisco.aci.aci_tag: + <<: *instance_absent + state: absent + register: nm_instance_delete + +- name: Instance tag deleted + assert: + that: + - cm_instance_delete is changed + - nm_instance_delete is changed + - cm_instance_delete.proposed.tagInst is not defined + - nm_instance_delete.current.0.tagInst is not defined + - cm_instance_delete.previous.0.tagInst.attributes.name == "foo" + - nm_instance_delete.previous.0.tagInst.attributes.name == "foo" + +- name: Instance Delete tag again (check_mode) + cisco.aci.aci_tag: + <<: *instance_absent + state: absent + check_mode: true + register: cm_instance_delete_again + +- name: Instance Delete tag again (normal_mode) + cisco.aci.aci_tag: + <<: *instance_absent + state: absent + register: nm_instance_delete_again + +- name: Instance tag deleted again + assert: + that: + - cm_instance_delete_again is not changed + - nm_instance_delete_again is not changed + - cm_instance_delete_again.current.0.tagInst is not defined + - nm_instance_delete_again.current.0.tagInst is not defined + - cm_instance_delete_again.previous.0.tagInst is not defined + - nm_instance_delete_again.previous.0.tagInst is not defined + +- name: Tag Create tag (check_mode) + cisco.aci.aci_tag: &tag_present + <<: *aci_info + tag_key: foo + tag_value: bar + tag_type: tag + dn: "{{ dn }}" + state: present + check_mode: true + register: cm_tag_create + +- name: Tag Create tag (normal_mode) + cisco.aci.aci_tag: + <<: *tag_present + state: present + register: nm_tag_create + +- name: Tag tag created + assert: + that: + - cm_tag_create is changed + - cm_tag_create.proposed.tagTag.attributes.value == "bar" + - nm_tag_create is changed + - nm_tag_create.current.0.tagTag.attributes.key == "foo" + - nm_tag_create.current.0.tagTag.attributes.value == "bar" + +- name: Tag Create tag again (check_mode) + cisco.aci.aci_tag: + <<: *tag_present + state: present + check_mode: true + register: cm_tag_create_again + +- name: Tag Create tag (normal_mode) + cisco.aci.aci_tag: + <<: *tag_present + state: present + register: nm_tag_create_again + +- name: Tag tag create again + assert: + that: + - cm_tag_create_again is not changed + - cm_tag_create_again.current.0.tagTag.attributes.key == "foo" + - cm_tag_create_again.current.0.tagTag.attributes.value == "bar" + - nm_tag_create_again is not changed + - nm_tag_create_again.current.0.tagTag.attributes.key == "foo" + - nm_tag_create_again.current.0.tagTag.attributes.value == "bar" + +- name: Tag Query tag + cisco.aci.aci_tag: + <<: *tag_present + state: query + register: tag_query_result + +- name: Tag tag query verification + assert: + that: + - tag_query_result is not changed + - tag_query_result.current.0.tagTag.attributes.key == "foo" + - tag_query_result.current.0.tagTag.attributes.value == "bar" + +- name: Tag Query all tags + cisco.aci.aci_tag: + <<: *tag_present + dn: "{{ fake_var | default(omit) }}" + tag_key: "{{ fake_var | default(omit) }}" + state: query + register: tag_query_all + +- name: Tag tag query verification + assert: + that: + - tag_query_all is not changed + +- name: Tag tag query verification (continued) + assert: + that: + - tag_query_all.current.0.tagTag.attributes.key == "foo" + - tag_query_all.current.0.tagTag.attributes.value == "bar" + when: query_cloud.current == [] # This condition will skip execution for cloud sites + +- name: Tag Delete tag (check_mode) + cisco.aci.aci_tag: &tag_absent + <<: *tag_present + tag_value: "{{ fake_var | default(omit) }}" + state: absent + check_mode: true + register: cm_tag_delete + +- name: Tag Delete tag (normal_mode) + cisco.aci.aci_tag: + <<: *tag_absent + state: absent + register: nm_tag_delete + +- name: Tag tag deleted + assert: + that: + - cm_tag_delete is changed + - nm_tag_delete is changed + - cm_tag_delete.proposed.tagTag is not defined + - nm_tag_delete.current.0.tagTag is not defined + - cm_tag_delete.previous.0.tagTag.attributes.key == "foo" + - nm_tag_delete.previous.0.tagTag.attributes.key == "foo" + - cm_tag_delete.previous.0.tagTag.attributes.value == "bar" + - nm_tag_delete.previous.0.tagTag.attributes.value == "bar" + +- name: Tag Delete tag again (check_mode) + cisco.aci.aci_tag: + <<: *tag_absent + state: absent + check_mode: true + register: cm_tag_delete_again + +- name: Tag Delete tag again (normal_mode) + cisco.aci.aci_tag: + <<: *tag_absent + state: absent + register: nm_tag_delete_again + +- name: Tag tag deleted again + assert: + that: + - cm_tag_delete_again is not changed + - nm_tag_delete_again is not changed + - cm_tag_delete_again.current.0.tagTag is not defined + - nm_tag_delete_again.current.0.tagTag is not defined + - cm_tag_delete_again.previous.0.tagTag is not defined + - nm_tag_delete_again.previous.0.tagTag is not defined diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/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/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/tasks/main.yml new file mode 100644 index 000000000..f3eba556e --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant/tasks/main.yml @@ -0,0 +1,366 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com> +# Copyright: (c) 2020, Lionel Hercot (@lhercot) <lhercot@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: 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" + +# CLEAN ENVIRONMENT +- name: Remove tenant + cisco.aci.aci_tenant: &tenant_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 + state: absent + + +# ADD TENANT +- name: Add tenant (check_mode) + cisco.aci.aci_tenant: &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: '{{ aci_output_level | default("info") }}' + tenant: ansible_test + state: present + annotation: ansible_test + owner_key: ansible_key + owner_tag: ansible_tag + output_path: "{{ ansible_host }}_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')}}" + +- name: Add tenant (normal mode) + cisco.aci.aci_tenant: + <<: *tenant_present + output_path: "{{ ansible_host }}_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" + 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" + register: nm_add_tenant_again + +- name: Dump content of files + debug: + msg: "{{ lookup('file', ansible_host + '_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') }}" + +- name: Log file content verification for create object + assert: + that: + - fc_cm_add_tenant.0.fvTenant.attributes.name == 'ansible_test' + - fc_cm_add_tenant.0.fvTenant.attributes.dn == 'uni/tn-ansible_test' + - fc_nm_add_tenant.0.fvTenant.attributes.name == 'ansible_test' + - fc_nm_add_tenant.0.fvTenant.attributes.dn == 'uni/tn-ansible_test' + - fc_cm_add_tenant_again == '' + - fc_nm_add_tenant_again == '' + +- name: Verify add_tenant + assert: + that: + - cm_add_tenant is changed + - nm_add_tenant is changed + - cm_add_tenant_again is not changed + - nm_add_tenant_again is not changed + - nm_add_tenant.current[0].fvTenant.attributes.annotation == 'ansible_test' + - cm_add_tenant.proposed.fvTenant.attributes.annotation == 'ansible_test' + - nm_add_tenant.current[0].fvTenant.attributes.ownerKey == 'ansible_key' + - cm_add_tenant.proposed.fvTenant.attributes.ownerKey == 'ansible_key' + - 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: + <<: *tenant_present + description: Ansible test tenant + annotation: ansible_test_changed + owner_key: ansible_key_changed + owner_tag: ansible_tag_changed + output_path: "{{ ansible_host }}_cm_add_tenant_descr.json" + check_mode: true + register: cm_add_tenant_descr + +- name: Change description and annotation/owner_tag/owner_key of tenant (normal mode) + cisco.aci.aci_tenant: + <<: *tenant_present + description: Ansible test tenant + annotation: ansible_test_changed + owner_key: ansible_key_changed + owner_tag: ansible_tag_changed + output_path: "{{ ansible_host }}_nm_add_tenant_descr.json" + register: nm_add_tenant_descr + +- name: Change description and annotation/owner_tag/owner_key of tenant again (check_mode) + cisco.aci.aci_tenant: + <<: *tenant_present + description: Ansible test tenant + annotation: ansible_test_changed + owner_key: ansible_key_changed + owner_tag: ansible_tag_changed + output_path: "{{ ansible_host }}_cm_add_tenant_descr_again.json" + check_mode: true + register: cm_add_tenant_descr_again + +- name: Change description and annotation of tenant again (normal mode) + cisco.aci.aci_tenant: + <<: *tenant_present + description: Ansible test tenant + annotation: ansible_test_changed + owner_key: ansible_key_changed + owner_tag: ansible_tag_changed + output_path: "{{ ansible_host }}_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') }}" + +- name: Log file content verification for update object + assert: + that: + - fc_cm_add_tenant_descr.0.fvTenant.attributes.descr == 'Ansible test tenant' + - fc_nm_add_tenant_descr.0.fvTenant.attributes.descr == 'Ansible test tenant' + - fc_cm_add_tenant_descr_again == '' + - fc_nm_add_tenant_descr_again == '' + +- name: Verify add_tenant_descr + assert: + that: + - cm_add_tenant_descr is changed + - nm_add_tenant_descr is changed + - cm_add_tenant_descr_again is not changed + - nm_add_tenant_descr_again is not changed + - cm_add_tenant_descr.proposed.fvTenant.attributes.annotation == 'ansible_test_changed' + - nm_add_tenant_descr.current[0].fvTenant.attributes.annotation == 'ansible_test_changed' + - cm_add_tenant_descr_again.proposed.fvTenant.attributes.annotation == 'ansible_test_changed' + - nm_add_tenant_descr_again.current[0].fvTenant.attributes.annotation == 'ansible_test_changed' + - nm_add_tenant_descr.current[0].fvTenant.attributes.ownerKey == 'ansible_key_changed' + - cm_add_tenant_descr.proposed.fvTenant.attributes.ownerKey == 'ansible_key_changed' + - nm_add_tenant_descr_again.current[0].fvTenant.attributes.ownerKey == 'ansible_key_changed' + - cm_add_tenant_descr_again.proposed.fvTenant.attributes.ownerKey == 'ansible_key_changed' + - nm_add_tenant_descr.current[0].fvTenant.attributes.ownerTag == 'ansible_tag_changed' + - cm_add_tenant_descr.proposed.fvTenant.attributes.ownerTag == 'ansible_tag_changed' + - nm_add_tenant_descr_again.current[0].fvTenant.attributes.ownerTag == 'ansible_tag_changed' + - cm_add_tenant_descr_again.proposed.fvTenant.attributes.ownerTag == 'ansible_tag_changed' + + +# ADD TENANT AGAIN +- name: Add tenant again with no description (check_mode) + cisco.aci.aci_tenant: + <<: *tenant_present + annotation: ansible_test_changed + owner_key: ansible_key_changed + owner_tag: ansible_tag_changed + check_mode: true + register: cm_add_tenant_again_no_descr + +- name: Add tenant again with no description (normal mode) + cisco.aci.aci_tenant: + <<: *tenant_present + annotation: ansible_test_changed + owner_key: ansible_key_changed + owner_tag: ansible_tag_changed + register: nm_add_tenant_again_no_descr + +- name: Verify add_tenant_again_no_descr + assert: + that: + - cm_add_tenant_again_no_descr is not changed + - nm_add_tenant_again_no_descr is not changed + + +# QUERY ALL TENANTS +- name: Query all tenants (check_mode) + cisco.aci.aci_tenant: &tenant_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") }}' + state: query + check_mode: true + register: cm_query_all_tenants + +- name: Query all tenants (normal mode) + cisco.aci.aci_tenant: *tenant_query + register: nm_query_all_tenants + +- name: Verify query_all_tenants + assert: + that: + - cm_query_all_tenants is not changed + - nm_query_all_tenants is not changed + # NOTE: Order of tenants is not stable between calls + #- cm_query_all_tenants == nm_query_all_tenants + + +# QUERY A TENANT +- name: Query our tenant + cisco.aci.aci_tenant: + <<: *tenant_query + tenant: ansible_test + check_mode: true + register: cm_query_tenant + +- name: Query our tenant + cisco.aci.aci_tenant: + <<: *tenant_query + tenant: ansible_test + register: nm_query_tenant + +- name: Verify query_tenant + assert: + that: + - cm_query_tenant is not changed + - nm_query_tenant is not changed + - cm_query_tenant == nm_query_tenant + - cm_query_tenant.current[0].fvTenant.attributes.annotation == 'ansible_test_changed' + - nm_query_tenant.current[0].fvTenant.attributes.annotation == 'ansible_test_changed' + - nm_query_tenant.current[0].fvTenant.attributes.ownerKey == 'ansible_key_changed' + - cm_query_tenant.current[0].fvTenant.attributes.ownerKey == 'ansible_key_changed' + - nm_query_tenant.current[0].fvTenant.attributes.ownerTag == 'ansible_tag_changed' + - cm_query_tenant.current[0].fvTenant.attributes.ownerTag == 'ansible_tag_changed' + + +- name: Update tenant with default annotation + cisco.aci.aci_tenant: + <<: *tenant_present + annotation: "{{ fake_var | default(omit) }}" + register: default_annotation + +- name: Assertion check for update tenant with default annotation + assert: + that: + - default_annotation is changed + - default_annotation.current.0.fvTenant.attributes.annotation == 'orchestrator:ansible' + +# REMOVE TENANT +- name: Remove tenant (check_mode) + cisco.aci.aci_tenant: + <<: *tenant_absent + output_path: "{{ ansible_host }}_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" + 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" + 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" + 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') }}" + +- name: Log file content verification for delete object + assert: + that: + - fc_cm_remove_tenant.0.fvTenant.attributes.status == 'deleted' + - fc_cm_remove_tenant.0.fvTenant.attributes.dn == 'uni/tn-ansible_test' + - fc_nm_remove_tenant == [{}] + - fc_cm_remove_tenant_again == '' + - fc_nm_remove_tenant_again == '' + +- name: Verify remove_tenant + assert: + that: + - cm_remove_tenant is changed + - nm_remove_tenant is changed + - cm_remove_tenant_again is not changed + - nm_remove_tenant_again is not changed + + +# QUERY NON-EXISTING TENANT +- name: Query non-existing tenant (check_mode) + cisco.aci.aci_tenant: + <<: *tenant_query + tenant: ansible_test + check_mode: true + register: cm_query_non_tenant + +- name: Query non-existing tenant (normal mode) + cisco.aci.aci_tenant: + <<: *tenant_query + tenant: ansible_test + register: nm_query_non_tenant + +# TODO: Implement more tests +- name: Verify query_non_tenant + assert: + that: + - cm_query_non_tenant is not changed + - nm_query_non_tenant is not changed + - cm_query_non_tenant == nm_query_non_tenant diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_dst_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_dst_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_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_tenant_span_dst_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_dst_group/tasks/main.yml new file mode 100644 index 000000000..d7d807ad8 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_dst_group/tasks/main.yml @@ -0,0 +1,241 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, Shreyas Srish (@shrsr) + +# 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: 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 == [] diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_src_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_src_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_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_tenant_span_src_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_src_group/tasks/main.yml new file mode 100644 index 000000000..9f83d0344 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_src_group/tasks/main.yml @@ -0,0 +1,184 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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: 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: Add a new tenant + cisco.aci.aci_tenant: &aci_tenant + <<: *aci_info + tenant: ansible_tenant + state: present + + - name: Add new bd + cisco.aci.aci_bd: &aci_bd + <<: *aci_tenant + bd: anstest + register: bd_present + + - name: Add a new source ap + cisco.aci.aci_ap: + <<: *aci_tenant + ap: ansible_source_ap + + - name: Add a new dest ap + cisco.aci.aci_ap: + <<: *aci_tenant + ap: ansible_dest_ap + + - name: Add a new dest epg + cisco.aci.aci_epg: + <<: *aci_bd + ap: ansible_dest_ap + epg: ansible_dest_epg + + - name: Add a new source epg + cisco.aci.aci_epg: + <<: *aci_bd + ap: ansible_dest_ap + epg: ansible_source_epg + + - name: Add span dest group + cisco.aci.aci_tenant_span_dst_group: + <<: *aci_info + destination_group: ansible_dest_group + destination_ip: 10.0.0.1 + source_ip: 10.0.2.1 + tenant: ansible_tenant + ttl: 2 + mtu: 1500 + flow_id: 1 + dscp: "CS1" + destination_epg: + tenant: ansible_tenant + ap: ansible_dest_ap + epg: ansible_dest_epg + state: present + + - name: Create a source group (check mode) + cisco.aci.aci_tenant_span_src_group: &aci_span + <<: *aci_tenant + name: ansible_span + description: ansible test description + dst_group: ansible_dest_group + check_mode: true + register: cm_create_with_dest + + - name: Create a source group + cisco.aci.aci_tenant_span_src_group: + <<: *aci_span + register: nm_create_with_dest + + - name: Create a source group again + cisco.aci.aci_tenant_span_src_group: + <<: *aci_span + register: nm_create_with_dest_again + + - name: Create second source group + cisco.aci.aci_tenant_span_src_group: + <<: *aci_tenant + name: ansible_span_2 + description: ansible test description + register: create_without_dest + + - name: Change second source group + cisco.aci.aci_tenant_span_src_group: + <<: *aci_tenant + name: ansible_span_2 + description: ansible test description 2 + register: change_without_dest + + - name: Verify create of source groups + ansible.builtin.assert: + that: + - cm_create_with_dest is changed + - nm_create_with_dest is changed + - nm_create_with_dest.current.0.spanSrcGrp.attributes.name == "ansible_span" + - nm_create_with_dest.current.0.spanSrcGrp.attributes.descr == "ansible test description" + - nm_create_with_dest.current.0.spanSrcGrp.children.0.spanSpanLbl.attributes.name == "ansible_dest_group" + - nm_create_with_dest_again is not changed + - nm_create_with_dest_again.current.0.spanSrcGrp.attributes.name == "ansible_span" + - nm_create_with_dest_again.current.0.spanSrcGrp.attributes.descr == "ansible test description" + - nm_create_with_dest_again.current.0.spanSrcGrp.children.0.spanSpanLbl.attributes.name == "ansible_dest_group" + - create_without_dest is changed + - create_without_dest.current.0.spanSrcGrp.attributes.name == "ansible_span_2" + - create_without_dest.current.0.spanSrcGrp.attributes.descr == "ansible test description" + - '"children" not in create_without_dest.current.0.spanSrcGrp' + - change_without_dest is changed + - change_without_dest.current.0.spanSrcGrp.attributes.name == "ansible_span_2" + - change_without_dest.current.0.spanSrcGrp.attributes.descr == "ansible test description 2" + - '"children" not in change_without_dest.current.0.spanSrcGrp' + + - name: Query a source groups + cisco.aci.aci_tenant_span_src_group: + <<: *aci_span + state: query + register: query_one + + - name: Query all source groups + cisco.aci.aci_tenant_span_src_group: + <<: *aci_info + state: query + register: query_all + + - name: Verify queries to source groups + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current.0.spanSrcGrp.attributes.name == "ansible_span" + - query_one.current.0.spanSrcGrp.attributes.descr == "ansible test description" + - query_one.current.0.spanSrcGrp.children.0.spanSpanLbl.attributes.name == "ansible_dest_group" + - query_all is not changed + - query_all.current | length == 2 + + - name: Delete a source group + cisco.aci.aci_tenant_span_src_group: + <<: *aci_span + state: absent + register: delete + + - name: Delete a source group again + cisco.aci.aci_tenant_span_src_group: + <<: *aci_span + state: absent + register: delete_again + + - name: Verify delete of source group + ansible.builtin.assert: + that: + - delete is changed + - delete_again is not changed + - delete.current == [] + + - name: Remove the ansible_tenant + cisco.aci.aci_tenant: + <<: *aci_tenant + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_src_group_src/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_src_group_src/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_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_tenant_span_src_group_src/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_src_group_src/tasks/main.yml new file mode 100644 index 000000000..65b8722f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_src_group_src/tasks/main.yml @@ -0,0 +1,204 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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: 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: Add a new tenant + cisco.aci.aci_tenant: &aci_tenant + <<: *aci_info + tenant: ansible_tenant + state: present + + - name: Add new bd + cisco.aci.aci_bd: &aci_bd + <<: *aci_tenant + bd: anstest + register: bd_present + + - name: Add a new source ap + cisco.aci.aci_ap: + <<: *aci_tenant + ap: ansible_source_ap + + - name: Add a new dest ap + cisco.aci.aci_ap: + <<: *aci_tenant + ap: ansible_dest_ap + + - name: Add a new dest epg + cisco.aci.aci_epg: + <<: *aci_bd + ap: ansible_dest_ap + epg: ansible_dest_epg + + - name: Add a new source epg + cisco.aci.aci_epg: + <<: *aci_bd + ap: ansible_dest_ap + epg: ansible_source_epg + + - name: Add span dest group + cisco.aci.aci_tenant_span_dst_group: + <<: *aci_info + destination_group: ansible_dest_group + destination_ip: 10.0.0.1 + source_ip: 10.0.2.1 + tenant: ansible_tenant + ttl: 2 + mtu: 1500 + flow_id: 1 + dscp: "CS1" + destination_epg: + tenant: ansible_tenant + ap: ansible_dest_ap + epg: ansible_dest_epg + state: present + + - name: Create a source group + cisco.aci.aci_tenant_span_src_group: + <<: *aci_tenant + name: ansible_span + description: ansible test description + dst_group: ansible_dest_group + register: nm_create_with_dest + + - name: Create a ansible_source SPAN Source (check mode) + cisco.aci.aci_tenant_span_src_group_src: &aci_src + <<: *aci_tenant + name: ansible_source + description: ansible test description + direction: incoming + src_ap: ansible_source_ap + src_epg: ansible_source_epg + src_group: ansible_span + check_mode: true + register: cm_create_with_epg + + - name: Create a ansible_source SPAN Source + cisco.aci.aci_tenant_span_src_group_src: + <<: *aci_src + register: nm_create_with_epg + + - name: Create a ansible_source SPAN Source again + cisco.aci.aci_tenant_span_src_group_src: + <<: *aci_src + register: nm_create_with_epg_again + + - name: Create second ansible_source SPAN Source + cisco.aci.aci_tenant_span_src_group_src: + <<: *aci_tenant + name: ansible_source_2 + description: ansible test description 2 + direction: outgoing + src_group: ansible_span + register: create_without_epg_direction_outgoing + + - name: Change second ansible_source SPAN Source + cisco.aci.aci_tenant_span_src_group_src: + <<: *aci_tenant + name: ansible_source_2 + description: ansible test description 3 + direction: both + src_group: ansible_span + register: change_without_epg_direction_both + + - name: Verify create and changes of sources + ansible.builtin.assert: + that: + - cm_create_with_epg is changed + - nm_create_with_epg is changed + - nm_create_with_epg.current.0.spanSrc.attributes.name == "ansible_source" + - nm_create_with_epg.current.0.spanSrc.attributes.descr == "ansible test description" + - nm_create_with_epg.current.0.spanSrc.attributes.dir == "in" + - nm_create_with_epg.current.0.spanSrc.children.0.spanRsSrcToEpg.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_source_ap/epg-ansible_source_epg" + - nm_create_with_epg_again is not changed + - nm_create_with_epg_again.current.0.spanSrc.attributes.name == "ansible_source" + - nm_create_with_epg_again.current.0.spanSrc.attributes.descr == "ansible test description" + - nm_create_with_epg_again.current.0.spanSrc.attributes.dir == "in" + - nm_create_with_epg_again.current.0.spanSrc.children.0.spanRsSrcToEpg.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_source_ap/epg-ansible_source_epg" + - create_without_epg_direction_outgoing is changed + - create_without_epg_direction_outgoing.current.0.spanSrc.attributes.name == "ansible_source_2" + - create_without_epg_direction_outgoing.current.0.spanSrc.attributes.descr == "ansible test description 2" + - create_without_epg_direction_outgoing.current.0.spanSrc.attributes.dir == "out" + - '"children" not in create_without_epg_direction_outgoing.current.0.spanSrc' + - change_without_epg_direction_both is changed + - change_without_epg_direction_both.current.0.spanSrc.attributes.name == "ansible_source_2" + - change_without_epg_direction_both.current.0.spanSrc.attributes.descr == "ansible test description 3" + - change_without_epg_direction_both.current.0.spanSrc.attributes.dir == "both" + - '"children" not in change_without_epg_direction_both.current.0.spanSrc' + + - name: Query a ansible_source SPAN Source + cisco.aci.aci_tenant_span_src_group_src: + <<: *aci_src + state: query + register: query_one + + - name: Query all ansible_source SPAN Sources + cisco.aci.aci_tenant_span_src_group_src: + <<: *aci_info + state: query + register: query_all + + - name: Verify queries of ansible_source SPAN Sources + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current.0.spanSrc.attributes.name == "ansible_source" + - query_one.current.0.spanSrc.attributes.descr == "ansible test description" + - query_one.current.0.spanSrc.attributes.dir == "in" + - query_one.current.0.spanSrc.children.0.spanRsSrcToEpg.attributes.tDn == "uni/tn-ansible_tenant/ap-ansible_source_ap/epg-ansible_source_epg" + - query_all is not changed + - query_all.current | length == 2 + + - name: Delete a ansible_source SPAN Source + cisco.aci.aci_tenant_span_src_group_src: + <<: *aci_src + state: absent + register: delete + + - name: Delete a ansible_source SPAN Source again + cisco.aci.aci_tenant_span_src_group_src: + <<: *aci_src + state: absent + register: delete_again + + - name: Verify delete of ansible_source SPAN Source + ansible.builtin.assert: + that: + - delete is changed + - delete_again is not changed + - delete.current == [] + + - name: Remove the ansible_tenant + cisco.aci.aci_tenant: + <<: *aci_tenant + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_src_group_to_dst_group/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_src_group_to_dst_group/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_src_group_to_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_tenant_span_src_group_to_dst_group/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_src_group_to_dst_group/tasks/main.yml new file mode 100644 index 000000000..e9dac612d --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_tenant_span_src_group_to_dst_group/tasks/main.yml @@ -0,0 +1,202 @@ +# Test code for the ACI modules +# Copyright: (c) 2022, 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: 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: Add a new tenant + cisco.aci.aci_tenant: &aci_tenant + <<: *aci_info + tenant: ansible_tenant + state: present + + - name: Add new bd + cisco.aci.aci_bd: &aci_bd + <<: *aci_tenant + bd: anstest + register: bd_present + + - name: Add a new source ap + cisco.aci.aci_ap: + <<: *aci_tenant + ap: ansible_source_ap + + - name: Add a new dest ap + cisco.aci.aci_ap: + <<: *aci_tenant + ap: ansible_dest_ap + + - name: Add a new dest epg + cisco.aci.aci_epg: + <<: *aci_bd + ap: ansible_dest_ap + epg: ansible_dest_epg + + - name: Add a new source epg + cisco.aci.aci_epg: + <<: *aci_bd + ap: ansible_dest_ap + epg: ansible_source_epg + + - name: Add span dest group + cisco.aci.aci_tenant_span_dst_group: + <<: *aci_info + destination_group: ansible_dest_group + destination_ip: 10.0.0.1 + source_ip: 10.0.2.1 + tenant: ansible_tenant + ttl: 2 + mtu: 1500 + flow_id: 1 + dscp: "CS1" + destination_epg: + tenant: ansible_tenant + ap: ansible_dest_ap + epg: ansible_dest_epg + state: present + + - name: Add span dest group + cisco.aci.aci_tenant_span_dst_group: + <<: *aci_info + destination_group: ansible_dest_group_2 + destination_ip: 20.0.0.1 + source_ip: 20.0.2.1 + tenant: ansible_tenant + ttl: 2 + mtu: 1500 + flow_id: 1 + dscp: "CS1" + destination_epg: + tenant: ansible_tenant + ap: ansible_dest_ap + epg: ansible_dest_epg + state: present + + - name: Create a source group + cisco.aci.aci_tenant_span_src_group: + <<: *aci_tenant + name: ansible_span + description: ansible test description + + - name: Create another source group + cisco.aci.aci_tenant_span_src_group: + <<: *aci_tenant + name: ansible_span_2 + description: ansible test description + + - name: Create a source group to destination (check mode) + cisco.aci.aci_tenant_span_src_group_to_dst_group: &aci_source_to_dest + <<: *aci_tenant + src_group: ansible_span + dst_group: ansible_dest_group + check_mode: true + register: cm_create + + - name: Create a source group to destination + cisco.aci.aci_tenant_span_src_group_to_dst_group: + <<: *aci_source_to_dest + register: nm_create + + - name: Create a source group to destination again + cisco.aci.aci_tenant_span_src_group_to_dst_group: + <<: *aci_source_to_dest + register: nm_create_again + + - name: Create another source group to destination + cisco.aci.aci_tenant_span_src_group_to_dst_group: + <<: *aci_tenant + src_group: ansible_span_2 + dst_group: ansible_dest_group_2 + register: nm_create_another + + - name: Change a source group to destination (error not allowed) + cisco.aci.aci_tenant_span_src_group_to_dst_group: + <<: *aci_source_to_dest + dst_group: ansible_dest_group_2 + ignore_errors: true + register: error_change + + - name: Verify create source groups to destination + ansible.builtin.assert: + that: + - cm_create is changed + - nm_create is changed + - nm_create.current.0.spanSpanLbl.attributes.name == "ansible_dest_group" + - nm_create_again is not changed + - nm_create_again.current.0.spanSpanLbl.attributes.name == "ansible_dest_group" + - nm_create_another is changed + - nm_create_another.current.0.spanSpanLbl.attributes.name == "ansible_dest_group_2" + - error_change is not changed + - 'error_change.msg == "APIC Error 105: Only one span destination is supported per session"' + + - name: Query a a source group to destination + cisco.aci.aci_tenant_span_src_group_to_dst_group: + <<: *aci_source_to_dest + state: query + register: query_one + + - name: Query all a source group to destinations + cisco.aci.aci_tenant_span_src_group_to_dst_group: + <<: *aci_info + state: query + register: query_all + + - name: Verify queries of source group to destination + ansible.builtin.assert: + that: + - query_one is not changed + - query_one.current.0.spanSpanLbl.attributes.name == "ansible_dest_group" + - query_all is not changed + - query_all.current | length == 2 + + - name: Delete a source group to destination + cisco.aci.aci_tenant_span_src_group_to_dst_group: + <<: *aci_source_to_dest + state: absent + register: delete + + - name: Delete a source group to destination again + cisco.aci.aci_tenant_span_src_group_to_dst_group: + <<: *aci_source_to_dest + state: absent + register: delete_again + + - name: Verify delete of source group to destinations + ansible.builtin.assert: + that: + - delete is changed + - delete_again is not changed + - delete.current == [] + + - name: Remove the ansible_tenant + cisco.aci.aci_tenant: + <<: *aci_tenant + state: absent
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool/tasks/dynamic.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool/tasks/dynamic.yml new file mode 100644 index 000000000..0469210f8 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool/tasks/dynamic.yml @@ -0,0 +1,304 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# CLEAN ENVIRONMENT +- name: Remove dynamic vlan pool + cisco.aci.aci_vlan_pool: &dynamic_vlan_pool_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") }}' + pool: anstest + pool_allocation_mode: dynamic + state: absent + + +# ADD VLAN POOL +- name: Add dynamic vlan pool (check_mode) + cisco.aci.aci_vlan_pool: &dynamic_vlan_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") }}' + pool: anstest + pool_allocation_mode: dynamic + state: present + check_mode: true + register: cm_add_dynamic_vlan_pool + +- name: Add dynamic vlan pool (normal mode) + cisco.aci.aci_vlan_pool: *dynamic_vlan_pool_present + register: nm_add_dynamic_vlan_pool + +- name: Verify add_dynamic_vlan_pool + assert: + that: + - cm_add_dynamic_vlan_pool is changed + - nm_add_dynamic_vlan_pool is changed + - cm_add_dynamic_vlan_pool.sent.fvnsVlanInstP.attributes.allocMode == nm_add_dynamic_vlan_pool.sent.fvnsVlanInstP.attributes.allocMode == 'dynamic' + - cm_add_dynamic_vlan_pool.sent.fvnsVlanInstP.attributes.name == nm_add_dynamic_vlan_pool.sent.fvnsVlanInstP.attributes.name == 'anstest' + - cm_add_dynamic_vlan_pool.proposed.fvnsVlanInstP.attributes.allocMode == nm_add_dynamic_vlan_pool.proposed.fvnsVlanInstP.attributes.allocMode == 'dynamic' + - cm_add_dynamic_vlan_pool.proposed.fvnsVlanInstP.attributes.name == nm_add_dynamic_vlan_pool.proposed.fvnsVlanInstP.attributes.name == 'anstest' + - cm_add_dynamic_vlan_pool.previous == nm_add_dynamic_vlan_pool.previous == [] + # NOTE: We cannot fix this easily + - cm_add_dynamic_vlan_pool.current == [] + - nm_add_dynamic_vlan_pool.current.0.fvnsVlanInstP.attributes.allocMode == 'dynamic' + - nm_add_dynamic_vlan_pool.current.0.fvnsVlanInstP.attributes.descr == '' + - nm_add_dynamic_vlan_pool.current.0.fvnsVlanInstP.attributes.dn == 'uni/infra/vlanns-[anstest]-dynamic' + - nm_add_dynamic_vlan_pool.current.0.fvnsVlanInstP.attributes.name == 'anstest' + - nm_add_dynamic_vlan_pool.current.0.fvnsVlanInstP.attributes.annotation == 'orchestrator:ansible' + +- name: Add dynamic_vlan_pool again (check_mode) + cisco.aci.aci_vlan_pool: *dynamic_vlan_pool_present + check_mode: true + register: cm_add_dynamic_vlan_pool_again + +- name: Add dynamic vlan pool again (normal mode) + cisco.aci.aci_vlan_pool: *dynamic_vlan_pool_present + register: nm_add_dynamic_vlan_pool_again + +- name: Verify add_dynamic_vlan_pool_again + assert: + that: + - cm_add_dynamic_vlan_pool_again is not changed + - nm_add_dynamic_vlan_pool_again is not changed + - cm_add_dynamic_vlan_pool_again.current == nm_add_dynamic_vlan_pool_again.current == nm_add_dynamic_vlan_pool.current + + +# CHANGE VLAN POOL +- name: Change description of dynamic vlan pool (check_mode) + cisco.aci.aci_vlan_pool: + <<: *dynamic_vlan_pool_present + description: Ansible test dynamic vlan pool + check_mode: true + register: cm_add_dynamic_vlan_pool_descr + +- name: Change description of dynamic vlan pool (normal mode) + cisco.aci.aci_vlan_pool: + <<: *dynamic_vlan_pool_present + description: Ansible test dynamic vlan pool + register: nm_add_dynamic_vlan_pool_descr + +- name: Verify add_dynamic_vlan_pool_descr + assert: + that: + - cm_add_dynamic_vlan_pool_descr is changed + - nm_add_dynamic_vlan_pool_descr is changed + - cm_add_dynamic_vlan_pool_descr.sent.fvnsVlanInstP.attributes.descr == nm_add_dynamic_vlan_pool_descr.sent.fvnsVlanInstP.attributes.descr == 'Ansible test dynamic vlan pool' + - cm_add_dynamic_vlan_pool_descr.proposed.fvnsVlanInstP.attributes.allocMode == nm_add_dynamic_vlan_pool_descr.proposed.fvnsVlanInstP.attributes.allocMode == 'dynamic' + - cm_add_dynamic_vlan_pool_descr.proposed.fvnsVlanInstP.attributes.descr == nm_add_dynamic_vlan_pool_descr.proposed.fvnsVlanInstP.attributes.descr == 'Ansible test dynamic vlan pool' + - cm_add_dynamic_vlan_pool_descr.proposed.fvnsVlanInstP.attributes.name == nm_add_dynamic_vlan_pool_descr.proposed.fvnsVlanInstP.attributes.name == 'anstest' + - cm_add_dynamic_vlan_pool_descr.previous == nm_add_dynamic_vlan_pool_descr.previous == cm_add_dynamic_vlan_pool_descr.current == nm_add_dynamic_vlan_pool.current + - nm_add_dynamic_vlan_pool_descr.current.0.fvnsVlanInstP.attributes.allocMode == 'dynamic' + - nm_add_dynamic_vlan_pool_descr.current.0.fvnsVlanInstP.attributes.descr == 'Ansible test dynamic vlan pool' + - nm_add_dynamic_vlan_pool_descr.current.0.fvnsVlanInstP.attributes.dn == 'uni/infra/vlanns-[anstest]-dynamic' + - nm_add_dynamic_vlan_pool_descr.current.0.fvnsVlanInstP.attributes.name == 'anstest' + +- name: Change description of dynamic vlan pool again (check_mode) + cisco.aci.aci_vlan_pool: + <<: *dynamic_vlan_pool_present + description: Ansible test dynamic vlan pool + check_mode: true + register: cm_add_dynamic_vlan_pool_descr_again + +- name: Change description of dynamic vlan pool again (normal mode) + cisco.aci.aci_vlan_pool: + <<: *dynamic_vlan_pool_present + description: Ansible test dynamic vlan pool + register: nm_add_dynamic_vlan_pool_descr_again + +- name: Verify add_dynamic_vlan_pool_descr_again + assert: + that: + - cm_add_dynamic_vlan_pool_descr_again is not changed + - nm_add_dynamic_vlan_pool_descr_again is not changed + - cm_add_dynamic_vlan_pool_descr_again.current == nm_add_dynamic_vlan_pool_descr_again.current == nm_add_dynamic_vlan_pool_descr.current + + +# ADD VLAN POOL AGAIN +- name: Add dynamic vlan pool again with no description (check_mode) + cisco.aci.aci_vlan_pool: *dynamic_vlan_pool_present + check_mode: true + register: cm_add_dynamic_vlan_pool_again_no_descr + +- name: Add dynamic vlan pool again with no description (normal mode) + cisco.aci.aci_vlan_pool: *dynamic_vlan_pool_present + register: nm_add_dynamic_vlan_pool_again_no_descr + +- name: Verify add_dynamic_vlan_pool_again_no_descr + assert: + that: + - cm_add_dynamic_vlan_pool_again_no_descr is not changed + - nm_add_dynamic_vlan_pool_again_no_descr is not changed + - cm_add_dynamic_vlan_pool_again_no_descr.current == nm_add_dynamic_vlan_pool_again_no_descr.current == nm_add_dynamic_vlan_pool_descr.current + + +# QUERY ALL VLAN POOLS +- name: Query all dynamic vlan pools (check_mode) + cisco.aci.aci_vlan_pool: &dynamic_vlan_pool_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") }}' + state: query + check_mode: true + register: cm_query_all_dynamic_vlan_pools + +- name: Query all dynamic vlan pools (normal mode) + cisco.aci.aci_vlan_pool: *dynamic_vlan_pool_query + register: nm_query_all_dynamic_vlan_pools + +- name: Verify query_all_dynamic_vlan_pools + assert: + that: + - cm_query_all_dynamic_vlan_pools is not changed + - nm_query_all_dynamic_vlan_pools is not changed + - cm_query_all_dynamic_vlan_pools == nm_query_all_dynamic_vlan_pools + - cm_query_all_dynamic_vlan_pools.current|length >= 1 + + +# QUERY A VLAN POOL +- name: Query our dynamic vlan pool + cisco.aci.aci_vlan_pool: + <<: *dynamic_vlan_pool_query + pool: anstest + pool_allocation_mode: dynamic + check_mode: true + register: cm_query_dynamic_vlan_pool + +- name: Query our dynamic vlan pool + cisco.aci.aci_vlan_pool: + <<: *dynamic_vlan_pool_query + pool: anstest + pool_allocation_mode: dynamic + register: nm_query_dynamic_vlan_pool + +- name: Verify query_dynamic_vlan_pool + assert: + that: + - cm_query_dynamic_vlan_pool is not changed + - nm_query_dynamic_vlan_pool is not changed + - cm_query_dynamic_vlan_pool == nm_query_dynamic_vlan_pool + - nm_query_dynamic_vlan_pool.current.0.fvnsVlanInstP.attributes.allocMode == 'dynamic' + - nm_query_dynamic_vlan_pool.current.0.fvnsVlanInstP.attributes.descr == 'Ansible test dynamic vlan pool' + - nm_query_dynamic_vlan_pool.current.0.fvnsVlanInstP.attributes.dn == 'uni/infra/vlanns-[anstest]-dynamic' + - nm_query_dynamic_vlan_pool.current.0.fvnsVlanInstP.attributes.name == 'anstest' + + +# REMOVE VLAN POOL +- name: Remove dynamic vlan pool (check_mode) + cisco.aci.aci_vlan_pool: *dynamic_vlan_pool_absent + check_mode: true + register: cm_remove_dynamic_vlan_pool + +- name: Remove dynamic vlan pool (normal mode) + cisco.aci.aci_vlan_pool: *dynamic_vlan_pool_absent + register: nm_remove_dynamic_vlan_pool + +- name: Verify remove_dynamic_vlan_pool + assert: + that: + - cm_remove_dynamic_vlan_pool is changed + - nm_remove_dynamic_vlan_pool is changed + - cm_remove_dynamic_vlan_pool.current.0.fvnsVlanInstP.attributes.allocMode == cm_remove_dynamic_vlan_pool.previous.0.fvnsVlanInstP.attributes.allocMode == nm_remove_dynamic_vlan_pool.previous.0.fvnsVlanInstP.attributes.allocMode == 'dynamic' + - cm_remove_dynamic_vlan_pool.current.0.fvnsVlanInstP.attributes.descr == cm_remove_dynamic_vlan_pool.previous.0.fvnsVlanInstP.attributes.descr == nm_remove_dynamic_vlan_pool.previous.0.fvnsVlanInstP.attributes.descr == 'Ansible test dynamic vlan pool' + - cm_remove_dynamic_vlan_pool.current.0.fvnsVlanInstP.attributes.dn == cm_remove_dynamic_vlan_pool.previous.0.fvnsVlanInstP.attributes.dn == nm_remove_dynamic_vlan_pool.previous.0.fvnsVlanInstP.attributes.dn == 'uni/infra/vlanns-[anstest]-dynamic' + - cm_remove_dynamic_vlan_pool.current.0.fvnsVlanInstP.attributes.name == cm_remove_dynamic_vlan_pool.previous.0.fvnsVlanInstP.attributes.name == nm_remove_dynamic_vlan_pool.previous.0.fvnsVlanInstP.attributes.name == 'anstest' + - nm_remove_dynamic_vlan_pool.current == [] + +- name: Remove dynamic vlan pool again (check_mode) + cisco.aci.aci_vlan_pool: *dynamic_vlan_pool_absent + check_mode: true + register: cm_remove_dynamic_vlan_pool_again + +- name: Remove dynamic vlan pool again (normal mode) + cisco.aci.aci_vlan_pool: *dynamic_vlan_pool_absent + register: nm_remove_dynamic_vlan_pool_again + +- name: Verify remove_dynamic_vlan_pool_again + assert: + that: + - cm_remove_dynamic_vlan_pool_again is not changed + - nm_remove_dynamic_vlan_pool_again is not changed + - cm_remove_dynamic_vlan_pool_again.proposed == nm_remove_dynamic_vlan_pool_again.proposed == {} + - cm_remove_dynamic_vlan_pool_again.sent == nm_remove_dynamic_vlan_pool_again.sent == {} + - cm_remove_dynamic_vlan_pool_again.previous == nm_remove_dynamic_vlan_pool_again.previous == [] + - cm_remove_dynamic_vlan_pool_again.current == nm_remove_dynamic_vlan_pool_again.current == [] + + +# QUERY NON-EXISTING VLAN POOL +- name: Query non-existing dynamic vlan pool (check_mode) + cisco.aci.aci_vlan_pool: + <<: *dynamic_vlan_pool_query + pool: anstest + pool_allocation_mode: dynamic + check_mode: true + register: cm_query_non_dynamic_vlan_pool + +- name: Query non-existing dynamic vlan pool (normal mode) + cisco.aci.aci_vlan_pool: + <<: *dynamic_vlan_pool_query + pool: anstest + pool_allocation_mode: dynamic + register: nm_query_non_dynamic_vlan_pool + +# TODO: Implement more tests +- name: Verify query_non_dynamic_vlan_pool + assert: + that: + - cm_query_non_dynamic_vlan_pool is not changed + - nm_query_non_dynamic_vlan_pool is not changed + - cm_remove_dynamic_vlan_pool_again.previous == nm_remove_dynamic_vlan_pool_again.previous == [] + - cm_remove_dynamic_vlan_pool_again.current == nm_remove_dynamic_vlan_pool_again.current == [] + + +# PROVOKE ERRORS +- name: Error when required parameter is missing + 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") }}' + state: present + ignore_errors: true + register: error_on_missing_required_param + +- name: Verify error_on_missing_required_param + assert: + that: + - error_on_missing_required_param is failed + - 'error_on_missing_required_param.msg == "state is present but all of the following are missing: pool"' + +- name: Error when together parameter is missing + 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") }}' + pool: anstest + state: present + ignore_errors: true + register: error_on_missing_together_param + +- name: Verify error_on_missing_together_param + assert: + that: + - error_on_missing_together_param is failed + - error_on_missing_together_param.msg == "ACI requires the 'pool_allocation_mode' when 'pool' is provided" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool/tasks/main.yml new file mode 100644 index 000000000..0bac9032c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool/tasks/main.yml @@ -0,0 +1,21 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (dagwieers) <dag@wieers.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: 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 + - include_tasks: static.yml + when: static is not defined or static + + - include_tasks: dynamic.yml + when: dynamic is not defined or dynamic diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool/tasks/static.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool/tasks/static.yml new file mode 100644 index 000000000..3ddae4c47 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool/tasks/static.yml @@ -0,0 +1,303 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# CLEAN ENVIRONMENT +- name: Remove static vlan pool + cisco.aci.aci_vlan_pool: &static_vlan_pool_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") }}' + pool: anstest + pool_allocation_mode: static + state: absent + +# ADD VLAN POOL +- name: Add static vlan pool (check_mode) + cisco.aci.aci_vlan_pool: &static_vlan_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") }}' + pool: anstest + pool_allocation_mode: static + state: present + check_mode: true + register: cm_add_static_vlan_pool + +- name: Add static vlan pool (normal mode) + cisco.aci.aci_vlan_pool: *static_vlan_pool_present + register: nm_add_static_vlan_pool + +- name: Verify add_static_vlan_pool + assert: + that: + - cm_add_static_vlan_pool is changed + - nm_add_static_vlan_pool is changed + - cm_add_static_vlan_pool.sent.fvnsVlanInstP.attributes.allocMode == nm_add_static_vlan_pool.sent.fvnsVlanInstP.attributes.allocMode == 'static' + - cm_add_static_vlan_pool.sent.fvnsVlanInstP.attributes.name == nm_add_static_vlan_pool.sent.fvnsVlanInstP.attributes.name == 'anstest' + - cm_add_static_vlan_pool.proposed.fvnsVlanInstP.attributes.allocMode == nm_add_static_vlan_pool.proposed.fvnsVlanInstP.attributes.allocMode == 'static' + - cm_add_static_vlan_pool.proposed.fvnsVlanInstP.attributes.name == nm_add_static_vlan_pool.proposed.fvnsVlanInstP.attributes.name == 'anstest' + - cm_add_static_vlan_pool.previous == nm_add_static_vlan_pool.previous == [] + # NOTE: We cannot fix this easily + - cm_add_static_vlan_pool.current == [] + - nm_add_static_vlan_pool.current.0.fvnsVlanInstP.attributes.allocMode == 'static' + - nm_add_static_vlan_pool.current.0.fvnsVlanInstP.attributes.descr == '' + - nm_add_static_vlan_pool.current.0.fvnsVlanInstP.attributes.dn == 'uni/infra/vlanns-[anstest]-static' + - nm_add_static_vlan_pool.current.0.fvnsVlanInstP.attributes.name == 'anstest' + - nm_add_static_vlan_pool.current.0.fvnsVlanInstP.attributes.annotation == 'orchestrator:ansible' + +- name: Add static_vlan_pool again (check_mode) + cisco.aci.aci_vlan_pool: *static_vlan_pool_present + check_mode: true + register: cm_add_static_vlan_pool_again + +- name: Add static vlan pool again (normal mode) + cisco.aci.aci_vlan_pool: *static_vlan_pool_present + register: nm_add_static_vlan_pool_again + +- name: Verify add_static_vlan_pool_again + assert: + that: + - cm_add_static_vlan_pool_again is not changed + - nm_add_static_vlan_pool_again is not changed + - cm_add_static_vlan_pool_again.current == nm_add_static_vlan_pool_again.current == nm_add_static_vlan_pool.current + + +# CHANGE VLAN POOL +- name: Change description of static vlan pool (check_mode) + cisco.aci.aci_vlan_pool: + <<: *static_vlan_pool_present + description: Ansible test static vlan pool + check_mode: true + register: cm_add_static_vlan_pool_descr + +- name: Change description of static vlan pool (normal mode) + cisco.aci.aci_vlan_pool: + <<: *static_vlan_pool_present + description: Ansible test static vlan pool + register: nm_add_static_vlan_pool_descr + +- name: Verify add_static_vlan_pool_descr + assert: + that: + - cm_add_static_vlan_pool_descr is changed + - nm_add_static_vlan_pool_descr is changed + - cm_add_static_vlan_pool_descr.sent.fvnsVlanInstP.attributes.descr == nm_add_static_vlan_pool_descr.sent.fvnsVlanInstP.attributes.descr == 'Ansible test static vlan pool' + - cm_add_static_vlan_pool_descr.proposed.fvnsVlanInstP.attributes.allocMode == nm_add_static_vlan_pool_descr.proposed.fvnsVlanInstP.attributes.allocMode == 'static' + - cm_add_static_vlan_pool_descr.proposed.fvnsVlanInstP.attributes.descr == nm_add_static_vlan_pool_descr.proposed.fvnsVlanInstP.attributes.descr == 'Ansible test static vlan pool' + - cm_add_static_vlan_pool_descr.proposed.fvnsVlanInstP.attributes.name == nm_add_static_vlan_pool_descr.proposed.fvnsVlanInstP.attributes.name == 'anstest' + - cm_add_static_vlan_pool_descr.previous == nm_add_static_vlan_pool_descr.previous == cm_add_static_vlan_pool_descr.current == nm_add_static_vlan_pool.current + - nm_add_static_vlan_pool_descr.current.0.fvnsVlanInstP.attributes.allocMode == 'static' + - nm_add_static_vlan_pool_descr.current.0.fvnsVlanInstP.attributes.descr == 'Ansible test static vlan pool' + - nm_add_static_vlan_pool_descr.current.0.fvnsVlanInstP.attributes.dn == 'uni/infra/vlanns-[anstest]-static' + - nm_add_static_vlan_pool_descr.current.0.fvnsVlanInstP.attributes.name == 'anstest' + +- name: Change description of static vlan pool again (check_mode) + cisco.aci.aci_vlan_pool: + <<: *static_vlan_pool_present + description: Ansible test static vlan pool + check_mode: true + register: cm_add_static_vlan_pool_descr_again + +- name: Change description of static vlan pool again (normal mode) + cisco.aci.aci_vlan_pool: + <<: *static_vlan_pool_present + description: Ansible test static vlan pool + register: nm_add_static_vlan_pool_descr_again + +- name: Verify add_static_vlan_pool_descr_again + assert: + that: + - cm_add_static_vlan_pool_descr_again is not changed + - nm_add_static_vlan_pool_descr_again is not changed + - cm_add_static_vlan_pool_descr_again.current == nm_add_static_vlan_pool_descr_again.current == nm_add_static_vlan_pool_descr.current + + +# ADD VLAN POOL AGAIN +- name: Add static vlan pool again with no description (check_mode) + cisco.aci.aci_vlan_pool: *static_vlan_pool_present + check_mode: true + register: cm_add_static_vlan_pool_again_no_descr + +- name: Add static vlan pool again with no description (normal mode) + cisco.aci.aci_vlan_pool: *static_vlan_pool_present + register: nm_add_static_vlan_pool_again_no_descr + +- name: Verify add_static_vlan_pool_again_no_descr + assert: + that: + - cm_add_static_vlan_pool_again_no_descr is not changed + - nm_add_static_vlan_pool_again_no_descr is not changed + - cm_add_static_vlan_pool_again_no_descr.current == nm_add_static_vlan_pool_again_no_descr.current == nm_add_static_vlan_pool_descr.current + + +# QUERY ALL VLAN POOLS +- name: Query all static vlan pools (check_mode) + cisco.aci.aci_vlan_pool: &static_vlan_pool_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") }}' + state: query + check_mode: true + register: cm_query_all_static_vlan_pools + +- name: Query all static vlan pools (normal mode) + cisco.aci.aci_vlan_pool: *static_vlan_pool_query + register: nm_query_all_static_vlan_pools + +- name: Verify query_all_static_vlan_pools + assert: + that: + - cm_query_all_static_vlan_pools is not changed + - nm_query_all_static_vlan_pools is not changed + - cm_query_all_static_vlan_pools == nm_query_all_static_vlan_pools + - cm_query_all_static_vlan_pools.current|length >= 1 + + +# QUERY A VLAN POOL +- name: Query our static vlan pool + cisco.aci.aci_vlan_pool: + <<: *static_vlan_pool_query + pool: anstest + pool_allocation_mode: static + check_mode: true + register: cm_query_static_vlan_pool + +- name: Query our static vlan pool + cisco.aci.aci_vlan_pool: + <<: *static_vlan_pool_query + pool: anstest + pool_allocation_mode: static + register: nm_query_static_vlan_pool + +- name: Verify query_static_vlan_pool + assert: + that: + - cm_query_static_vlan_pool is not changed + - nm_query_static_vlan_pool is not changed + - cm_query_static_vlan_pool == nm_query_static_vlan_pool + - nm_query_static_vlan_pool.current.0.fvnsVlanInstP.attributes.allocMode == 'static' + - nm_query_static_vlan_pool.current.0.fvnsVlanInstP.attributes.descr == 'Ansible test static vlan pool' + - nm_query_static_vlan_pool.current.0.fvnsVlanInstP.attributes.dn == 'uni/infra/vlanns-[anstest]-static' + - nm_query_static_vlan_pool.current.0.fvnsVlanInstP.attributes.name == 'anstest' + + +# REMOVE VLAN POOL +- name: Remove static vlan pool (check_mode) + cisco.aci.aci_vlan_pool: *static_vlan_pool_absent + check_mode: true + register: cm_remove_static_vlan_pool + +- name: Remove static vlan pool (normal mode) + cisco.aci.aci_vlan_pool: *static_vlan_pool_absent + register: nm_remove_static_vlan_pool + +- name: Verify remove_static_vlan_pool + assert: + that: + - cm_remove_static_vlan_pool is changed + - nm_remove_static_vlan_pool is changed + - cm_remove_static_vlan_pool.current.0.fvnsVlanInstP.attributes.allocMode == cm_remove_static_vlan_pool.previous.0.fvnsVlanInstP.attributes.allocMode == nm_remove_static_vlan_pool.previous.0.fvnsVlanInstP.attributes.allocMode == 'static' + - cm_remove_static_vlan_pool.current.0.fvnsVlanInstP.attributes.descr == cm_remove_static_vlan_pool.previous.0.fvnsVlanInstP.attributes.descr == nm_remove_static_vlan_pool.previous.0.fvnsVlanInstP.attributes.descr == 'Ansible test static vlan pool' + - cm_remove_static_vlan_pool.current.0.fvnsVlanInstP.attributes.dn == cm_remove_static_vlan_pool.previous.0.fvnsVlanInstP.attributes.dn == nm_remove_static_vlan_pool.previous.0.fvnsVlanInstP.attributes.dn == 'uni/infra/vlanns-[anstest]-static' + - cm_remove_static_vlan_pool.current.0.fvnsVlanInstP.attributes.name == cm_remove_static_vlan_pool.previous.0.fvnsVlanInstP.attributes.name == nm_remove_static_vlan_pool.previous.0.fvnsVlanInstP.attributes.name == 'anstest' + - nm_remove_static_vlan_pool.current == [] + +- name: Remove static vlan pool again (check_mode) + cisco.aci.aci_vlan_pool: *static_vlan_pool_absent + check_mode: true + register: cm_remove_static_vlan_pool_again + +- name: Remove static vlan pool again (normal mode) + cisco.aci.aci_vlan_pool: *static_vlan_pool_absent + register: nm_remove_static_vlan_pool_again + +- name: Verify remove_static_vlan_pool_again + assert: + that: + - cm_remove_static_vlan_pool_again is not changed + - nm_remove_static_vlan_pool_again is not changed + - cm_remove_static_vlan_pool_again.proposed == nm_remove_static_vlan_pool_again.proposed == {} + - cm_remove_static_vlan_pool_again.sent == nm_remove_static_vlan_pool_again.sent == {} + - cm_remove_static_vlan_pool_again.previous == nm_remove_static_vlan_pool_again.previous == [] + - cm_remove_static_vlan_pool_again.current == nm_remove_static_vlan_pool_again.current == [] + + +# QUERY NON-EXISTING VLAN POOL +- name: Query non-existing static vlan pool (check_mode) + cisco.aci.aci_vlan_pool: + <<: *static_vlan_pool_query + pool: anstest + pool_allocation_mode: static + check_mode: true + register: cm_query_non_static_vlan_pool + +- name: Query non-existing static vlan pool (normal mode) + cisco.aci.aci_vlan_pool: + <<: *static_vlan_pool_query + pool: anstest + pool_allocation_mode: static + register: nm_query_non_static_vlan_pool + +# TODO: Implement more tests +- name: Verify query_non_static_vlan_pool + assert: + that: + - cm_query_non_static_vlan_pool is not changed + - nm_query_non_static_vlan_pool is not changed + - cm_remove_static_vlan_pool_again.previous == nm_remove_static_vlan_pool_again.previous == [] + - cm_remove_static_vlan_pool_again.current == nm_remove_static_vlan_pool_again.current == [] + + +# PROVOKE ERRORS +- name: Error when required parameter is missing + 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") }}' + state: present + ignore_errors: true + register: error_on_missing_required_param + +- name: Verify error_on_missing_required_param + assert: + that: + - error_on_missing_required_param is failed + - 'error_on_missing_required_param.msg == "state is present but all of the following are missing: pool"' + +- name: Error when together parameter is missing + 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") }}' + pool: anstest + state: present + ignore_errors: true + register: error_on_missing_together_param + +- name: Verify error_on_missing_together_param + assert: + that: + - error_on_missing_together_param is failed + - error_on_missing_together_param.msg == "ACI requires the 'pool_allocation_mode' when 'pool' is provided" diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool_encap_block/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool_encap_block/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool_encap_block/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..c39259593 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vlan_pool_encap_block/tasks/main.yml @@ -0,0 +1,378 @@ +# Test code for the ACI modules + +# Copyright: (c) 2017, Jacob McGill (jmcgill298) +# Copyright: (c) 2018, Dag Wieers (dagwieers) <dag@wieers.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: 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: Ensure vlan pool exists for tests to kick off + 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") }}' + state: absent + pool: anstest + pool_allocation_mode: static + description: Ansible Test + + - name: Ensure vlan pool exists for tests to kick off + cisco.aci.aci_vlan_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: debug + state: present + pool: anstest + pool_allocation_mode: static + description: Ansible Test + register: pool_present + + - name: Create vlan pool encap block - check mode works + cisco.aci.aci_vlan_pool_encap_block: &aci_encap_block_present + <<: *aci_pool_present + block_name: anstest + block_start: 20 + block_end: 40 + pool: anstest + pool_allocation_mode: static + allocation_mode: inherit + description: Ansible Test + check_mode: true + register: encap_block_present_check_mode + + - name: Present assertions + assert: + that: + - encap_block_present_check_mode is changed + - encap_block_present_check_mode.sent.fvnsEncapBlk.attributes.allocMode == 'inherit' + - encap_block_present_check_mode.sent.fvnsEncapBlk.attributes.descr == 'Ansible Test' + - encap_block_present_check_mode.sent.fvnsEncapBlk.attributes.from == 'vlan-20' + - encap_block_present_check_mode.sent.fvnsEncapBlk.attributes.to == 'vlan-40' + - encap_block_present_check_mode.sent.fvnsEncapBlk.attributes.name == 'anstest' + + - name: Create vlan pool encap_block - creation works + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_encap_block_present + register: encap_block_present + + - name: Present assertions + assert: + that: + - encap_block_present is changed + - encap_block_present.previous == [] + - encap_block_present.sent == encap_block_present_check_mode.sent + - encap_block_present.sent == encap_block_present.proposed + - encap_block_present.current.0.fvnsEncapBlk.attributes.annotation == 'orchestrator:ansible' + + - name: Create vlan pool range - idempotency works + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_encap_block_present + register: encap_block_present_idempotent + + - name: Present assertions + assert: + that: + - encap_block_present_idempotent is not changed + - encap_block_present_idempotent.previous.0.fvnsEncapBlk.attributes.name == "anstest" + + - name: Update vlan pool range - update works + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_encap_block_present + description: Ansible Test Update + allocation_mode: inherit + register: encap_block_present_update + + - name: Present assertions + assert: + that: + - encap_block_present_update is changed + - encap_block_present_update.previous != [] + - encap_block_present_update.sent != encap_block_present.sent + + - name: Create vlan pool range - used for query + cisco.aci.aci_vlan_pool_encap_block: &aci_encap_block_present_2 + <<: *aci_encap_block_present + block_name: anstest_2 + block_start: 50 + block_end: 55 + register: encap_block_present_2 + + - name: Present assertions + assert: + that: + - encap_block_present_2 is changed + - encap_block_present_2.previous == [] + + - name: Invalid encap_block_start - error message works + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_encap_block_present + block_start: 0 + ignore_errors: true + register: encap_block_start_low + + - name: Present assertions + assert: + that: + - encap_block_start_low is failed + - encap_block_start_low.msg == "vlan pools must have 'block_start' and 'block_end' values between 1 and 4094" + + - name: Invalid encap_block_start - error message works + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_encap_block_present + block_start: 4096 + ignore_errors: true + register: encap_block_start_high + + - name: Present assertions + assert: + that: + - encap_block_start_high is failed + - encap_block_start_high.msg == "vlan pools must have 'block_start' and 'block_end' values between 1 and 4094" + + - name: Invalid encap_block_end - error message works + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_encap_block_present + block_end: 0 + ignore_errors: true + register: encap_block_end_low + + - name: Present assertions + assert: + that: + - encap_block_end_low is failed + - encap_block_end_low.msg == "vlan pools must have 'block_start' and 'block_end' values between 1 and 4094" + + - name: Invalid encap_block_end - error message works + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_encap_block_present + block_end: 4096 + ignore_errors: true + register: encap_block_end_high + + - name: Present assertions + assert: + that: + - encap_block_end_high is failed + - encap_block_end_high.msg == "vlan pools must have 'block_start' and 'block_end' values between 1 and 4094" + + - name: Range start higher than range end - error message works + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_encap_block_present + block_start: 1000 + ignore_errors: true + register: encap_block_start_end + + - name: Present assertions + assert: + that: + - encap_block_start_end is failed + - encap_block_start_end.msg == "The 'block_start' must be less than or equal to the 'block_end'" + + - name: Missing required param - error message works + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_pool_present + ignore_errors: true + register: encap_block_present_missing_param + + - name: Present assertions + assert: + that: + - encap_block_present_missing_param is failed + - 'encap_block_present_missing_param.msg == "state is present but all of the following are missing: block_end, block_start"' + + - name: Query specific vlan pool range + cisco.aci.aci_vlan_pool_encap_block: &aci_encap_block_query + <<: *aci_encap_block_present + state: query + register: encap_block_query + + - name: Query assertions + assert: + that: + - encap_block_query is not changed + - encap_block_query.url.endswith("infra/vlanns-[anstest]-static/from-[vlan-20]-to-[vlan-40].json") + - encap_block_query.current | length == 1 + - encap_block_query.current.0.fvnsEncapBlk.attributes.name == "anstest" + + - name: Query vlan pool range - from, to, and name are filtered + cisco.aci.aci_vlan_pool_encap_block: &aci_encap_block_query_filter + <<: *aci_encap_block_query + pool: "{{ fake_var | default(omit) }}" + register: encap_block_query_from_to_name + + - name: Query assertions + assert: + that: + - encap_block_query_from_to_name is not changed + - encap_block_query_from_to_name.url.endswith("class/fvnsEncapBlk.json") + - '"eq(fvnsEncapBlk.from,\"vlan-20\")" in encap_block_query_from_to_name.filter_string' + - '"eq(fvnsEncapBlk.name,\"anstest\")" in encap_block_query_from_to_name.filter_string' + - '"eq(fvnsEncapBlk.to,\"vlan-40\")" in encap_block_query_from_to_name.filter_string' + - encap_block_query_from_to_name.current.0.fvnsEncapBlk.attributes.name == "anstest" + - encap_block_query_from_to_name.current.0.fvnsEncapBlk.attributes.from == "vlan-20" + - encap_block_query_from_to_name.current.0.fvnsEncapBlk.attributes.to == "vlan-40" + + - name: Query vlan pool range - from and name are filtered + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_encap_block_query_filter + block_end: "{{ fake_var | default(omit) }}" + register: encap_block_query_from_name + + - name: Query assertions + assert: + that: + - encap_block_query_from_name is not changed + - encap_block_query_from_name.url.endswith("class/fvnsEncapBlk.json") + - '"eq(fvnsEncapBlk.from,\"vlan-20\")" in encap_block_query_from_name.filter_string' + - '"eq(fvnsEncapBlk.name,\"anstest\")" in encap_block_query_from_name.filter_string' + - encap_block_query_from_name.current.0.fvnsEncapBlk.attributes.name == "anstest" + - encap_block_query_from_name.current.0.fvnsEncapBlk.attributes.from == "vlan-20" + + - name: Query vlan pool range - to and name are filtered + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_encap_block_query_filter + block_start: "{{ fake_var | default(omit) }}" + register: encap_block_query_to_name + + - name: Query assertions + assert: + that: + - encap_block_query_to_name is not changed + - encap_block_query_to_name.url.endswith("class/fvnsEncapBlk.json") + - '"eq(fvnsEncapBlk.name,\"anstest\")" in encap_block_query_to_name.filter_string' + - '"eq(fvnsEncapBlk.to,\"vlan-40\")" in encap_block_query_to_name.filter_string' + - encap_block_query_to_name.current.0.fvnsEncapBlk.attributes.name == "anstest" + - encap_block_query_to_name.current.0.fvnsEncapBlk.attributes.to == "vlan-40" + + - name: Query vlan pool range - name is filtered + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_encap_block_query_filter + block_start: "{{ fake_var | default(omit) }}" + block_end: "{{ fake_var | default(omit) }}" + register: encap_block_query_name + + - name: Query assertions + assert: + that: + - encap_block_query_name is not changed + - encap_block_query_name.url.endswith("class/fvnsEncapBlk.json") + - '"eq(fvnsEncapBlk.name,\"anstest\")" in encap_block_query_name.filter_string' + - encap_block_query_name.current.0.fvnsEncapBlk.attributes.name == "anstest" + + - name: Query vlan pool range - from and to are filtered + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_encap_block_query_filter + block_name: "{{ fake_var | default(omit) }}" + register: encap_block_query_from_to + + - name: Query assertions + assert: + that: + - encap_block_query_from_to is not changed + - encap_block_query_from_to.url.endswith("class/fvnsEncapBlk.json") + - '"eq(fvnsEncapBlk.from,\"vlan-20\")" in encap_block_query_from_to.filter_string' + - '"eq(fvnsEncapBlk.to,\"vlan-40\")" in encap_block_query_from_to.filter_string' + - encap_block_query_from_to.current.0.fvnsEncapBlk.attributes.from == "vlan-20" + - encap_block_query_from_to.current.0.fvnsEncapBlk.attributes.to == "vlan-40" + + - name: Query all ranges in a vlan pool + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_pool_present + state: query + pool_allocation_mode: static + register: encap_block_query_pool + + - name: Query assertions + assert: + that: + - encap_block_query_pool is not changed + - encap_block_query_pool.current | length == 1 + - encap_block_query_pool.current.0.fvnsVlanInstP.attributes.name == "anstest" + - encap_block_query_pool.current.0.fvnsVlanInstP.children | length > 1 + - encap_block_query_pool.url.endswith("infra/vlanns-[anstest]-static.json") + + - name: Query all ranges + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_pool_present + state: query + pool: "{{ fake_var | default(omit) }}" + register: encap_block_query_all + + - name: Query assertions + assert: + that: + - encap_block_query_all is not changed + - encap_block_query_all.current | length > 1 + - encap_block_query_all.current.0.fvnsEncapBlk is defined + - encap_block_query_all.url.endswith("class/fvnsEncapBlk.json") + + - name: Delete vlan pool range - deletion works + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_encap_block_present + state: absent + register: delete_range + + - name: Absent assertions + assert: + that: + - delete_range is changed + - delete_range.proposed == {} + - delete_range.previous.0.fvnsEncapBlk.attributes.name == "anstest" + + - name: Delete vlan pool range - check mode works + cisco.aci.aci_vlan_pool_encap_block: &aci_encap_block_absent + <<: *aci_encap_block_present_2 + state: absent + check_mode: true + register: delete_check_mode + + - name: Absent assertions + assert: + that: + - delete_check_mode is changed + - delete_check_mode.previous != [] + + - name: Delete vlan pool range - deletion works + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_encap_block_absent + register: delete_encap_block_2 + + - name: Absent assertions + assert: + that: + - delete_encap_block_2 is changed + - delete_encap_block_2.previous == delete_check_mode.previous + + - name: Delete vlan pool range again - idempotency works + cisco.aci.aci_vlan_pool_encap_block: + <<: *aci_encap_block_absent + register: delete_idempotent + + - name: Absent assertions + assert: + that: + - delete_idempotent is not changed + - delete_idempotent.previous == [] + + - name: Cleanup vlan pool + cisco.aci.aci_vlan_pool: + <<: *aci_pool_present + state: absent + when: pool_present is changed diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_controller/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_controller/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_controller/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_controller/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_controller/tasks/main.yml new file mode 100644 index 000000000..7a02169b0 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_controller/tasks/main.yml @@ -0,0 +1,164 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, Anvitha Jain (@anvitha-jain) <anvjain@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# CLEAN ENVIRONMENT +- 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") }}' + +# Remove VMM domain +- name: Remove VMM domain (normal mode) + cisco.aci.aci_domain: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + vm_provider: "{{ item }}" + state: absent + register: nm_remove_domain + loop: + - vmware + - redhat + - microsoft + - openstack + +- 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: + # ADD DOMAIN + - name: Add VMM domain + cisco.aci.aci_domain: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + vm_provider: "{{ item }}" + state: present + register: nm_add_domain + loop: + - vmware + - redhat + - microsoft + - openstack + + - name: Verify VMM add_domain + assert: + that: + - nm_add_domain is changed + + - name: Add controller to VMware VMM domain + aci_vmm_controller: &add_controller + <<: *aci_info + domain: vmm_dom + name: vCenter1 + controller_hostname: 10.1.1.1 + dvs_version: unmanaged + vm_provider: vmware + datacenter: DC1 + state: present + register: nm_add_controller + + - name: Verify VMM add_controller + assert: + that: + - nm_add_controller is changed + - nm_add_controller.sent.vmmCtrlrP.attributes.name == 'vCenter1' + - nm_add_controller.proposed.vmmCtrlrP.attributes.name == 'vCenter1' + - nm_add_controller.previous == [] + - nm_add_controller.current.0.vmmCtrlrP.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom/ctrlr-vCenter1' + - nm_add_controller.current.0.vmmCtrlrP.attributes.name == 'vCenter1' + - nm_add_controller.current.0.vmmCtrlrP.attributes.annotation == 'orchestrator:ansible' + + - name: Add another controller to all VMM domain + aci_vmm_controller: + <<: *add_controller + name: vCenter2 + credentials: vCenterCredentials1 + inband_management_epg: ib_epg + controller_hostname: 10.10.1.1 + vm_provider: "{{ item }}" + state: present + register: add_controller + loop: + - vmware + - redhat + - microsoft + - openstack + + - name: Verify another VMM add_controller + assert: + that: + - add_controller is changed + + - name: Add controller to VMware VMM domain again + aci_vmm_controller: + <<: *add_controller + name: vCenter2 + controller_hostname: 10.10.1.1 + state: present + register: add_controller_again + + - name: Verify another VMM add_controller again + assert: + that: + - add_controller_again is not changed + + - name: Query controller + aci_vmm_controller: + <<: *aci_info + domain: vmm_dom + name: vCenter1 + vm_provider: vmware + state: query + register: query_controller + + - name: Verify VMM query_controller + assert: + that: + - query_controller is not changed + - query_controller.current.0.vmmCtrlrP.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom/ctrlr-vCenter1' + - query_controller.current.0.vmmCtrlrP.attributes.name == 'vCenter1' + + - name: Query all controllers + aci_vmm_controller: + <<: *aci_info + domain: vmm_dom + vm_provider: vmware + state: query + register: query_controller + + - name: Verify VMM query_controller + assert: + that: + - query_controller is not changed + + - name: Delete controllers + aci_vmm_controller: + <<: *add_controller + name: vCenter1 + state: absent + register: remove_controller + + - name: Delete controllers + aci_vmm_controller: + <<: *add_controller + name: vCenter2 + state: absent + register: remove_controller_2 + + - name: Verify VMM remove_controller + assert: + that: + - remove_controller is changed + - remove_controller_2 is changed + - remove_controller_2.current == []
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_credential/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_credential/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_credential/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_credential/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_credential/tasks/main.yml new file mode 100644 index 000000000..b76c4563a --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_credential/tasks/main.yml @@ -0,0 +1,12 @@ +# Test code for the ACI modules +# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.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 + +- include_tasks: vmware.yml + when: vmware is not defined or vmware
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_credential/tasks/vmware.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_credential/tasks/vmware.yml new file mode 100644 index 000000000..262ecf33c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_credential/tasks/vmware.yml @@ -0,0 +1,221 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# CLEAN ENVIRONMENT +- 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") }}' + +# Remove VMM domain +- name: Remove VMM domain (normal mode) + cisco.aci.aci_domain: &domain_absent + <<: *aci_info + domain: vmm_dom + domain_type: vmm + vm_provider: vmware + state: absent + register: nm_remove_domain + +- 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: + # ADD VMM domain for testing + - name: Add VMM domain (normal mode) + cisco.aci.aci_domain: &domain_present + <<: *aci_info + domain: vmm_dom + domain_type: vmm + vm_provider: vmware + state: present + register: nm_add_domain + + - name: Verify add_domain + assert: + that: + - nm_add_domain is changed + + # REMOVE credential + - name: Remove credential (check mode) + cisco.aci.aci_vmm_credential: &credential_absent + <<: *aci_info + name: vmm_cred + description: my_new_cred + domain: vmm_dom + credential_username: myUsername + credential_password: mySecretPassword + vm_provider: vmware + state: absent + check_mode: true + register: cm_remove_credential + + - name: Remove vmware VMM credential (normal mode) + cisco.aci.aci_vmm_credential: *credential_absent + register: nm_remove_credential + + - name: Verify remove_credential + assert: + that: + - cm_remove_credential is not changed + - nm_remove_credential is not changed + + # ADD credential + - name: Add vmware VMM credential (check mode) + cisco.aci.aci_vmm_credential: &credential_present + <<: *aci_info + name: vmm_cred + description: my_new_cred + domain: vmm_dom + credential_username: myUsername + credential_password: mySecretPassword + vm_provider: vmware + state: present + check_mode: true + register: cm_add_credential + + # NOTE: Setting password is not idempotent + - name: Add vmware VMM credential (normal mode) + cisco.aci.aci_vmm_credential: *credential_present + register: nm_add_credential + + # NOTE: Setting password is not idempotent + - name: Add vmware VMM credential again (check mode) + cisco.aci.aci_vmm_credential: *credential_present + check_mode: true + register: cm_add_credential_again + + - name: Verify add_credential + assert: + that: + - cm_add_credential is changed + - nm_add_credential is changed + - cm_add_credential.sent.vmmUsrAccP.attributes.descr == nm_add_credential.sent.vmmUsrAccP.attributes.descr == 'my_new_cred' + - cm_add_credential.sent.vmmUsrAccP.attributes.name == nm_add_credential.sent.vmmUsrAccP.attributes.name == 'vmm_cred' + - cm_add_credential.sent.vmmUsrAccP.attributes.pwd == nm_add_credential.sent.vmmUsrAccP.attributes.pwd == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER' + - cm_add_credential.sent.vmmUsrAccP.attributes.usr == nm_add_credential.sent.vmmUsrAccP.attributes.usr == 'myUsername' + - cm_add_credential.proposed.vmmUsrAccP.attributes.descr == nm_add_credential.proposed.vmmUsrAccP.attributes.descr == 'my_new_cred' + - cm_add_credential.proposed.vmmUsrAccP.attributes.name == nm_add_credential.proposed.vmmUsrAccP.attributes.name == 'vmm_cred' + - cm_add_credential.proposed.vmmUsrAccP.attributes.pwd == nm_add_credential.proposed.vmmUsrAccP.attributes.pwd == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER' + - cm_add_credential.proposed.vmmUsrAccP.attributes.usr == nm_add_credential.proposed.vmmUsrAccP.attributes.usr == 'myUsername' + - cm_add_credential.current == cm_add_credential.previous == nm_add_credential.previous == [] + - nm_add_credential.current.0.vmmUsrAccP.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom/usracc-vmm_cred' + - nm_add_credential.current.0.vmmUsrAccP.attributes.name == 'vmm_cred' + - nm_add_credential.current.0.vmmUsrAccP.attributes.annotation == 'orchestrator:ansible' + + # MODIFY credential + - name: Modify vmware VMM credential (check mode) + cisco.aci.aci_vmm_credential: &credential_mod + <<: *aci_info + name: vmm_cred + description: my_updated_descr + domain: vmm_dom + credential_username: myNewUsername + credential_password: myNewSecretPassword + vm_provider: vmware + state: present + check_mode: true + register: cm_mod_credential + + - name: Modify vmware VMM credential (normal mode) + cisco.aci.aci_vmm_credential: *credential_mod + register: nm_mod_credential + + - name: Verify mod_credential + assert: + that: + - cm_mod_credential is changed + - nm_mod_credential is changed + - cm_mod_credential.sent.vmmUsrAccP.attributes.descr == nm_mod_credential.sent.vmmUsrAccP.attributes.descr == 'my_updated_descr' + - cm_mod_credential.sent.vmmUsrAccP.attributes.pwd == nm_mod_credential.sent.vmmUsrAccP.attributes.pwd == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER' + - cm_mod_credential.sent.vmmUsrAccP.attributes.usr == nm_mod_credential.sent.vmmUsrAccP.attributes.usr == 'myNewUsername' + - cm_mod_credential.proposed.vmmUsrAccP.attributes.descr == nm_mod_credential.proposed.vmmUsrAccP.attributes.descr == 'my_updated_descr' + - cm_mod_credential.proposed.vmmUsrAccP.attributes.name == nm_mod_credential.proposed.vmmUsrAccP.attributes.name == 'vmm_cred' + - cm_mod_credential.proposed.vmmUsrAccP.attributes.pwd == nm_mod_credential.proposed.vmmUsrAccP.attributes.pwd == 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER' + - cm_mod_credential.proposed.vmmUsrAccP.attributes.usr == nm_mod_credential.proposed.vmmUsrAccP.attributes.usr == 'myNewUsername' + - nm_mod_credential.current.0.vmmUsrAccP.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom/usracc-vmm_cred' + - nm_mod_credential.current.0.vmmUsrAccP.attributes.name == 'vmm_cred' + + - name: Query existing vmware VMM credential (check mode) + cisco.aci.aci_vmm_credential: &query_existing_cred + <<: *aci_info + name: vmm_cred + domain: vmm_dom + vm_provider: vmware + state: query + check_mode: true + register: cm_query_credential + + - name: Query existing vmware VMM credential (normal mode) + cisco.aci.aci_vmm_credential: *query_existing_cred + register: nm_query_credential + + - name: Query non-existent vmware VMM credential + cisco.aci.aci_vmm_credential: + <<: *aci_info + name: vmm_fake_cred + domain: vmm_dom + vm_provider: vmware + state: query + register: nm_query_fake_credential + + - name: Query all vmware VMM credentials (check mode) + cisco.aci.aci_vmm_credential: &query_all_creds + <<: *aci_info + vm_provider: vmware + state: query + check_mode: true + register: cm_query_all_credential + + - name: Query all vmware VMM credentials (normal mode) + cisco.aci.aci_vmm_credential: *query_all_creds + register: nm_query_all_credential + + - name: Verify query_credential + assert: + that: + - cm_query_credential is not changed + - nm_query_credential is not changed + - nm_query_fake_credential is not changed + - cm_query_all_credential is not changed + - nm_query_all_credential is not changed + - cm_query_credential.current.0.vmmUsrAccP.attributes.name == 'vmm_cred' + - nm_query_credential.current.0.vmmUsrAccP.attributes.name == 'vmm_cred' + - nm_query_fake_credential.current == [] + - cm_query_all_credential.current.0.vmmUsrAccP.attributes.name == 'vmm_cred' + - nm_query_all_credential.current.0.vmmUsrAccP.attributes.name == 'vmm_cred' + + - name: Remove credential (check_mode) + cisco.aci.aci_vmm_credential: *credential_absent + check_mode: true + register: cm_remove_credential_again + + - name: Remove credential (normal_mode) + cisco.aci.aci_vmm_credential: *credential_absent + register: nm_remove_credential_again + + - name: Remove credential (normal_mode) + cisco.aci.aci_vmm_credential: *credential_absent + register: nm_remove_credential_final + + - name: Verify remove_credential + assert: + that: + - cm_remove_credential_again is changed + - nm_remove_credential_again is changed + - nm_remove_credential_final is not changed + + # Remove VMM domain after testing + - name: Remove VMM domain (normal_mode) + cisco.aci.aci_domain: *domain_absent + register: nm_remove_domain_again diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_uplink/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_uplink/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_uplink/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_uplink/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_uplink/tasks/main.yml new file mode 100644 index 000000000..1e7b6a6cf --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_uplink/tasks/main.yml @@ -0,0 +1,175 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# PERFORM TESTS ONLY ON SUPPORTED APICS +- 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: Execute tasks only for non-cloud sites + when: + - query_cloud.current == [] # This condition will skip execution for cloud sites + - version.current.0.topSystem.attributes.version is version('4.2', '>=') # Make sure we execute it for APIC version above or equal to 4.2 + block: + # CLEAN ENVIRONMENT + - name: Remove ansible_domain if it already exists + aci_domain: + <<: *aci_info + domain: ansible_domain + domain_type: vmm + vm_provider: vmware + state: absent + + # CREATE VMWARE DOMAIN + - name: Create ansible_domain + aci_domain: + <<: *aci_info + domain: ansible_domain + domain_type: vmm + vm_provider: vmware + state: present + + # CREATE VMWARE UPLINK CONTAINER + - name: Create VMWare Uplink Container + aci_vmm_uplink_container: + <<: *aci_info + domain: ansible_domain + num_of_uplinks: 1 + state: present + + # CREATE VMWARE UPLINK + - name: Create VMWare Uplink + cisco.aci.aci_vmm_uplink: + <<: *aci_info + domain: ansible_domain + uplink_id: 1 + uplink_name: uplink1 + state: present + register: create_uplink + + - name: Verify Uplink Creation + assert: + that: + - create_uplink.current.0.vmmUplinkP.attributes.dn == "uni/vmmp-VMware/dom-ansible_domain/uplinkpcont/uplinkp-1" + - create_uplink.current.0.vmmUplinkP.attributes.uplinkId == "1" + - create_uplink.current.0.vmmUplinkP.attributes.uplinkName == "uplink1" + - create_uplink.current.0.vmmUplinkP.attributes.annotation == 'orchestrator:ansible' + + # CREATE VMWARE UPLINK AGAIN TO TEST IDEMPOTENCE + - name: Create VMWare Uplink again + cisco.aci.aci_vmm_uplink: + <<: *aci_info + domain: ansible_domain + uplink_id: 1 + uplink_name: uplink1 + state: present + register: create_uplink_again + + - name: Verify Uplink Creation idempotence + assert: + that: + - create_uplink_again is not changed + - create_uplink_again.current.0.vmmUplinkP.attributes.dn == "uni/vmmp-VMware/dom-ansible_domain/uplinkpcont/uplinkp-1" + - create_uplink_again.current.0.vmmUplinkP.attributes.uplinkId == "1" + - create_uplink_again.current.0.vmmUplinkP.attributes.uplinkName == "uplink1" + + # MODIFY VMWARE UPLINK + - name: Create VMWare Uplink again + cisco.aci.aci_vmm_uplink: + <<: *aci_info + domain: ansible_domain + uplink_id: 1 + uplink_name: updated_uplink + state: present + register: update_uplink + + - name: Verify Uplink update + assert: + that: + - update_uplink is changed + - update_uplink.current.0.vmmUplinkP.attributes.dn == "uni/vmmp-VMware/dom-ansible_domain/uplinkpcont/uplinkp-1" + - update_uplink.current.0.vmmUplinkP.attributes.uplinkId == "1" + - update_uplink.current.0.vmmUplinkP.attributes.uplinkName == "updated_uplink" + + # QUERY VMWARE UPLINK + - name: Query VMWare Uplink + cisco.aci.aci_vmm_uplink: + <<: *aci_info + domain: ansible_domain + uplink_id: 1 + state: query + register: query_uplink + + - name: Verify Uplink query + assert: + that: + - query_uplink is not changed + - query_uplink.current.0.vmmUplinkP.attributes.dn == "uni/vmmp-VMware/dom-ansible_domain/uplinkpcont/uplinkp-1" + - query_uplink.current.0.vmmUplinkP.attributes.uplinkId == "1" + - query_uplink.current.0.vmmUplinkP.attributes.uplinkName == "updated_uplink" + + # DELETE VMWARE UPLINK + - name: Delete VMWare Uplink + cisco.aci.aci_vmm_uplink: + <<: *aci_info + domain: ansible_domain + uplink_id: 1 + state: absent + register: remove_uplink + + - name: Verify VMWare Uplink deletion + assert: + that: + - remove_uplink is changed + - remove_uplink.current == [] + - remove_uplink.previous.0.vmmUplinkP.attributes.dn == "uni/vmmp-VMware/dom-ansible_domain/uplinkpcont/uplinkp-1" + - remove_uplink.previous.0.vmmUplinkP.attributes.uplinkId == "1" + - remove_uplink.previous.0.vmmUplinkP.attributes.uplinkName == "updated_uplink" + + # DELETE VMWARE UPLINK AGAIN TO TEST IDEMPOTENCE + - name: Delete VMWare Uplink again + cisco.aci.aci_vmm_uplink: + <<: *aci_info + domain: ansible_domain + uplink_id: 1 + state: absent + register: remove_uplink_again + + - name: Verify VMWare Uplink deletion idempotence + assert: + that: + - remove_uplink_again is not changed + + # CLEAN UP + - name: Remove ansible_domain + aci_domain: + <<: *aci_info + domain: ansible_domain + domain_type: vmm + vm_provider: vmware + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_uplink_container/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_uplink_container/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_uplink_container/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_uplink_container/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_uplink_container/tasks/main.yml new file mode 100644 index 000000000..0ddbe2174 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_uplink_container/tasks/main.yml @@ -0,0 +1,156 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, 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 + +# 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 + +# PERFORM TESTS ONLY ON SUPPORTED APICS +- 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: Execute tasks only for non-cloud sites + when: + - query_cloud.current == [] # This condition will skip execution for cloud sites + - version.current.0.topSystem.attributes.version is version('4.2', '>=') # Make sure we execute it for APIC version above or equal to 4.2 + block: + # CLEAN ENVIRONMENT + - name: Remove ansible_domain if it already exists + aci_domain: + <<: *aci_info + domain: ansible_domain + domain_type: vmm + vm_provider: vmware + state: absent + + # CREATE VMWARE DOMAIN + - name: Create ansible_domain + aci_domain: + <<: *aci_info + domain: ansible_domain + domain_type: vmm + vm_provider: vmware + state: present + + # CREATE VMWARE UPLINK CONTAINER + - name: Create VMWare Uplink Container + aci_vmm_uplink_container: + <<: *aci_info + domain: ansible_domain + num_of_uplinks: 2 + state: present + register: create_container + + - name: Verify Uplink Container Creation + assert: + that: + - create_container.current.0.vmmUplinkPCont.attributes.dn == "uni/vmmp-VMware/dom-ansible_domain/uplinkpcont" + - create_container.current.0.vmmUplinkPCont.attributes.numOfUplinks == "2" + - create_container.current.0.vmmUplinkPCont.attributes.annotation == 'orchestrator:ansible' + + # CREATE VMWARE UPLINK CONTAINER AGAIN TO CHECK IDEMPOTENCE + - name: Create VMWare Uplink Container again + aci_vmm_uplink_container: + <<: *aci_info + domain: ansible_domain + num_of_uplinks: 2 + state: present + register: create_container_again + + - name: Verify Uplink Container Creation Idempotence + assert: + that: + - create_container_again is not changed + - create_container_again.current.0.vmmUplinkPCont.attributes.dn == "uni/vmmp-VMware/dom-ansible_domain/uplinkpcont" + - create_container_again.current.0.vmmUplinkPCont.attributes.numOfUplinks == "2" + + # MODIFY VMWARE UPLINK CONTAINER + - name: Update VMWare Uplink Container + aci_vmm_uplink_container: + <<: *aci_info + domain: ansible_domain + num_of_uplinks: 3 + state: present + register: update_container + + - name: Verify Uplink Container is updated + assert: + that: + - update_container is changed + - update_container.current.0.vmmUplinkPCont.attributes.dn == "uni/vmmp-VMware/dom-ansible_domain/uplinkpcont" + - update_container.current.0.vmmUplinkPCont.attributes.numOfUplinks == "3" + + # QUERY VMWARE UPLINK CONTAINER + - name: Update VMWare Uplink Container + aci_vmm_uplink_container: + <<: *aci_info + domain: ansible_domain + state: query + register: query_container + + - name: Verify Uplink Container Query + assert: + that: + - query_container is not changed + - query_container.current.0.vmmUplinkPCont.attributes.dn == "uni/vmmp-VMware/dom-ansible_domain/uplinkpcont" + - query_container.current.0.vmmUplinkPCont.attributes.numOfUplinks == "3" + + # DELETE VMWARE UPLINK CONTAINER + - name: Remove Uplink Container + aci_vmm_uplink_container: + <<: *aci_info + domain: ansible_domain + state: absent + register: delete_container + + - name: Verify Uplink Container removal + assert: + that: + - delete_container is changed + - delete_container.current == [] + - delete_container.previous.0.vmmUplinkPCont.attributes.dn == "uni/vmmp-VMware/dom-ansible_domain/uplinkpcont" + - delete_container.previous.0.vmmUplinkPCont.attributes.numOfUplinks == "3" + + # DELETE VMWARE UPLINK CONTAINER AGAIN TO TEST IDEMPOTENCE + - name: Remove Uplink Container again + aci_vmm_uplink_container: + <<: *aci_info + domain: ansible_domain + state: absent + register: delete_container_again + + - name: Verify Uplink Container removal idempotence + assert: + that: + - delete_container_again is not changed + + # CLEAN UP + - name: Remove ansible_domain + aci_domain: + <<: *aci_info + domain: ansible_domain + domain_type: vmm + vm_provider: vmware + state: absent diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_vswitch_policy/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_vswitch_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_vswitch_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_vmm_vswitch_policy/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_vswitch_policy/tasks/main.yml new file mode 100644 index 000000000..371137af4 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vmm_vswitch_policy/tasks/main.yml @@ -0,0 +1,205 @@ +# Test code for the ACI modules +# Copyright: (c) 2021, Anvitha Jain (@anvitha-jain) <anvjain@cisco.com> + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# CLEAN ENVIRONMENT +- 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: Query system information + aci_system: + <<: *aci_info + id: 1 + state: query + register: version + +# Remove VMM domain +- name: Remove VMM domain (normal mode) + cisco.aci.aci_domain: + <<: *aci_info + domain: '{{ item.domain }}' + domain_type: vmm + vm_provider: '{{ item.provider }}' + state: absent + register: nm_remove_domain + loop: + - { domain: 'vmm_dom', provider: 'vmware' } + - { domain: 'vmm_dom', provider: 'microsoft' } + - { domain: 'microsoft_dom', provider: 'microsoft' } + +- 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: + # ADD DOMAIN + - name: Add VMM domain + cisco.aci.aci_domain: + <<: *aci_info + domain: '{{ item.domain }}' + domain_type: vmm + vm_provider: '{{ item.provider }}' + state: present + register: nm_add_domain + loop: + - { domain: 'vmm_dom', provider: 'vmware' } + - { domain: 'vmm_dom', provider: 'microsoft' } + - { domain: 'microsoft_dom', provider: 'microsoft' } + + - name: Verify VMM add_domain + assert: + that: + - nm_add_domain is changed + + - name: Add a vSwitch policy to vmware domain + aci_vmm_vswitch_policy: &add_vmware_policies + <<: *aci_info + domain: vmm_dom + vm_provider: vmware + lldp_policy: LLDP_policy + cdp_policy: CDP_policy + port_channel_policy: PORT_Channel_policy + state: present + register: add_vmware_policy + + - name: Verify VMM add_vmware_policy + assert: + that: + - add_vmware_policy is changed + - add_vmware_policy.previous == [] + - add_vmware_policy.current.0.vmmVSwitchPolicyCont.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom/vswitchpolcont' + - add_vmware_policy.current.0.vmmVSwitchPolicyCont.children.0.vmmRsVswitchOverrideLacpPol.attributes.tDn == 'uni/infra/lacplagp-PORT_Channel_policy' + - add_vmware_policy.current.0.vmmVSwitchPolicyCont.children.1.vmmRsVswitchOverrideCdpIfPol.attributes.tDn == 'uni/infra/cdpIfP-CDP_policy' + - add_vmware_policy.current.0.vmmVSwitchPolicyCont.children.2.vmmRsVswitchOverrideLldpIfPol.attributes.tDn == 'uni/infra/lldpIfP-LLDP_policy' + - add_vmware_policy.current.0.vmmVSwitchPolicyCont.attributes.annotation == 'orchestrator:ansible' + + - name: Add a vSwitch policy to vmware domain + aci_vmm_vswitch_policy: + <<: *add_vmware_policies + netflow_exporter: + name: Netflow_Exporter_policy + enhanced_lag: + - name: Enhanced_Lag_pol + state: present + register: add_vmware_policy_2 + + - name: Verify VMM add_vmware_policy_2 + assert: + that: + - add_vmware_policy_2 is changed + - add_vmware_policy_2.current.0.vmmVSwitchPolicyCont.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom/vswitchpolcont' + - add_vmware_policy_2.current.0.vmmVSwitchPolicyCont.children.0.lacpEnhancedLagPol.attributes.name == 'Enhanced_Lag_pol' + - add_vmware_policy_2.current.0.vmmVSwitchPolicyCont.children.1.vmmRsVswitchExporterPol.attributes.tDn == 'uni/infra/vmmexporterpol-Netflow_Exporter_policy' + - add_vmware_policy_2.current.0.vmmVSwitchPolicyCont.children.2.vmmRsVswitchOverrideLacpPol.attributes.tDn == 'uni/infra/lacplagp-PORT_Channel_policy' + - add_vmware_policy_2.current.0.vmmVSwitchPolicyCont.children.3.vmmRsVswitchOverrideCdpIfPol.attributes.tDn == 'uni/infra/cdpIfP-CDP_policy' + - add_vmware_policy_2.current.0.vmmVSwitchPolicyCont.children.4.vmmRsVswitchOverrideLldpIfPol.attributes.tDn == 'uni/infra/lldpIfP-LLDP_policy' + + - name: Add MTU policy to vmware domain when version is >= 4.2 + aci_vmm_vswitch_policy: + <<: *add_vmware_policies + mtu_policy: MTU_policy + state: present + register: add_vmware_mtu_policy + when: version.current.0.topSystem.attributes.version is version('4.2', '>=') + + - name: Verify VMM add_vmware_mtu_policy + assert: + that: + - add_vmware_mtu_policy is changed + - add_vmware_mtu_policy.current.0.vmmVSwitchPolicyCont.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom/vswitchpolcont' + - add_vmware_mtu_policy.current.0.vmmVSwitchPolicyCont.children.0.vmmRsVswitchOverrideMtuPol.attributes.tDn == 'uni/fabric/l2pol-MTU_policy' + when: version.current.0.topSystem.attributes.version is version('4.2', '>=') + + - name: Add a vSwitch policy to microsoft domain + aci_vmm_vswitch_policy: + <<: *aci_info + domain: vmm_dom + vm_provider: microsoft + lldp_policy: ms_LLDP_policy + cdp_policy: ms_CDP_policy + port_channel_policy: ms_PORT_Channel_policy + state: present + register: add_microsoft_policy + + - name: Verify VMM add_microsoft_policy + assert: + that: + - add_microsoft_policy is changed + - add_microsoft_policy.previous == [] + - add_microsoft_policy.current.0.vmmVSwitchPolicyCont.attributes.dn == 'uni/vmmp-Microsoft/dom-vmm_dom/vswitchpolcont' + - add_microsoft_policy.current.0.vmmVSwitchPolicyCont.children.0.vmmRsVswitchOverrideLacpPol.attributes.tDn == 'uni/infra/lacplagp-ms_PORT_Channel_policy' + - add_microsoft_policy.current.0.vmmVSwitchPolicyCont.children.1.vmmRsVswitchOverrideCdpIfPol.attributes.tDn == 'uni/infra/cdpIfP-ms_CDP_policy' + - add_microsoft_policy.current.0.vmmVSwitchPolicyCont.children.2.vmmRsVswitchOverrideLldpIfPol.attributes.tDn == 'uni/infra/lldpIfP-ms_LLDP_policy' + + - name: Add STP vSwitch policy to another microsoft domain + aci_vmm_vswitch_policy: + <<: *aci_info + domain: microsoft_dom + vm_provider: microsoft + stp_policy: ms_STP_policy + state: present + register: add_microsoft_stp_policy + + - name: Verify VMM add_microsoft_stp_policy + assert: + that: + - add_microsoft_stp_policy is changed + - add_microsoft_stp_policy.previous == [] + - add_microsoft_stp_policy.current.0.vmmVSwitchPolicyCont.attributes.dn == 'uni/vmmp-Microsoft/dom-microsoft_dom/vswitchpolcont' + - add_microsoft_stp_policy.current.0.vmmVSwitchPolicyCont.children.0.vmmRsVswitchOverrideStpPol.attributes.tDn == 'uni/infra/ifPol-ms_STP_policy' + + - name: Query all the vSwitch policy + aci_vmm_vswitch_policy: + <<: *aci_info + state: query + register: query_all_vmware + + - name: Query all the vSwitch policy of the VMWare domain + aci_vmm_vswitch_policy: + <<: *aci_info + state: query + register: query_all_microsoft + + - name: Verify Query all tasks for vmware and microsoft domain + assert: + that: + - query_all_vmware is not changed + - query_all_microsoft is not changed + + - name: Query vSwitch policies of VMWare domain + aci_vmm_vswitch_policy: + <<: *aci_info + domain: vmm_dom + vm_provider: vmware + state: query + register: query_vmware + + - name: Verify Query vSwitch policy of the VMWare domain + assert: + that: + - query_vmware is not changed + - query_vmware.current.0.vmmVSwitchPolicyCont.attributes.dn == 'uni/vmmp-VMware/dom-vmm_dom/vswitchpolcont' + + - name: Remove vSwitch Policy from VMware VMM domain + aci_vmm_vswitch_policy: + <<: *aci_info + domain: vmm_dom + vm_provider: vmware + state: absent + register: remove_vmware_vSwitch_policy + + - name: Verify remove_vmware_vSwitch_policy + assert: + that: + - remove_vmware_vSwitch_policy is changed + - remove_vmware_vSwitch_policy.current == []
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vrf/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_vrf/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vrf/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..fa3f1057c --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vrf/tasks/main.yml @@ -0,0 +1,192 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) + +# 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: 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 + tenant: ansible_test + register: tenant_present + +- name: ensure vrf does not exist yet for tests to kick off + cisco.aci.aci_vrf: + <<: *aci_tenant_present + vrf: "{{ item }}" + state: absent + with_items: + - anstest + - anstest2 + +- name: create vrf - check mode works + cisco.aci.aci_vrf: &aci_vrf_present + <<: *aci_tenant_present + vrf: anstest + description: Ansible Test + check_mode: true + register: vrf_present_check_mode + +- name: create vrf - creation works + cisco.aci.aci_vrf: + <<: *aci_vrf_present + register: vrf_present + +- name: create vrf again - idempotency works + cisco.aci.aci_vrf: + <<: *aci_vrf_present + register: vrf_present_idempotent + +- name: update vrf - update works + cisco.aci.aci_vrf: + <<: *aci_vrf_present + description: Ansible Test Update + policy_control_preference: unenforced + register: vrf_update + +- name: create another vrf - check more params + cisco.aci.aci_vrf: + <<: *aci_vrf_present + vrf: anstest2 + policy_control_direction: egress + preferred_group: enabled + match_type: all + register: vrf_present_2 + +- name: create vrf without all necessary params - failure message works + cisco.aci.aci_vrf: + <<: *aci_vrf_present + tenant: "{{ fake_var | default(omit) }}" + ignore_errors: true + register: vrf_present_missing_param + +- name: present asserts + assert: + that: + - vrf_present_check_mode is changed + - vrf_present_check_mode.sent.fvCtx.attributes.descr == 'Ansible Test' + - vrf_present_check_mode.sent.fvCtx.attributes.name == 'anstest' + - vrf_present is changed + - vrf_present.sent == vrf_present_check_mode.sent + - vrf_present.current.0.fvCtx.attributes.annotation == 'orchestrator:ansible' + - vrf_present.previous == [] + - vrf_present_idempotent is not changed + - vrf_present_idempotent.previous != [] + - vrf_update is changed + - vrf_update.previous != [] + - vrf_update.sent != vrf_update.proposed + - vrf_update.sent.fvCtx.attributes.descr == 'Ansible Test Update' + - vrf_update.sent.fvCtx.attributes.pcEnfPref == 'unenforced' + - 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.children.0.vzAny.attributes.matchT == 'All' + - vrf_present_2.current.0.fvCtx.children.0.vzAny.attributes.prefGrMemb == 'enabled' + - vrf_present_missing_param is failed + - vrf_present_missing_param.msg == 'state is present but all of the following are missing{{":"}} tenant' + +- name: get all vrf + cisco.aci.aci_vrf: &aci_query + <<: *aci_tenant_present + state: query + tenant: "{{ fake_var | default(omit) }}" + register: query_all + +- name: get all in tenant + cisco.aci.aci_vrf: + <<: *aci_query + tenant: ansible_test + register: query_tenant + +- name: get all with name + cisco.aci.aci_vrf: + <<: *aci_query + vrf: anstest + register: query_vrf_vrf + +- name: get vrf + cisco.aci.aci_vrf: + <<: *aci_vrf_present + state: query + register: query_vrf + +- name: query asserts + assert: + that: + - query_all is not changed + - query_all.current | length > 1 + - query_all.current.0.fvCtx is defined + - '"class/fvCtx.json" in query_all.url' + - query_tenant is not changed + - query_tenant.current | length == 1 + - query_tenant.current.0.fvTenant.children | length == 2 + - query_tenant.current.0.fvTenant.attributes.name == "ansible_test" + - '"rsp-subtree-class=fvCtx" in query_tenant.filter_string' + - '"tn-ansible_test.json" in query_tenant.url' + - query_vrf_vrf is not changed + - query_vrf_vrf.current != [] + - query_vrf_vrf.current.0.fvCtx.attributes.name == "anstest" + - '"query-target-filter=eq(fvCtx.name,\"anstest\")" in query_vrf_vrf.filter_string' + - '"class/fvCtx.json" in query_vrf_vrf.url' + - query_vrf is not changed + - query_vrf.current | length == 1 + - '"tn-ansible_test/ctx-anstest.json" in query_vrf.url' + +- name: delete vrf - check mode works + cisco.aci.aci_vrf: &aci_vrf_absent + <<: *aci_vrf_present + state: absent + check_mode: true + register: vrf_absent_check_mode + +- name: delete vrf - delete works + cisco.aci.aci_vrf: + <<: *aci_vrf_absent + register: vrf_absent + +- name: delete vrf again - idempotency works + cisco.aci.aci_vrf: + <<: *aci_vrf_absent + register: vrf_absent_idempotent + +- name: delete vrf - cleanup + cisco.aci.aci_vrf: + <<: *aci_vrf_absent + name: anstest2 + +- name: delete vrf missing param - fails properly + cisco.aci.aci_vrf: + <<: *aci_vrf_absent + vrf: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: vrf_absent_missing_param + +- name: asserts for deletion task + assert: + that: + - vrf_absent_check_mode is changed + - vrf_absent_check_mode.previous != [] + - vrf_absent_check_mode.proposed == {} + - vrf_absent is changed + - vrf_absent.previous == vrf_absent_check_mode.previous + - vrf_absent_idempotent is not changed + - vrf_absent_idempotent.previous == [] + - vrf_absent_missing_param is failed + - 'vrf_absent_missing_param.msg == "state is absent but all of the following are missing: vrf"' + +- name: delete tenant - cleanup before ending tests + cisco.aci.aci_tenant: + <<: *aci_tenant_present + state: absent + when: tenant_present is changed
\ No newline at end of file diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vzany_to_contract/aliases b/ansible_collections/cisco/aci/tests/integration/targets/aci_vzany_to_contract/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vzany_to_contract/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/ansible_collections/cisco/aci/tests/integration/targets/aci_vzany_to_contract/tasks/main.yml b/ansible_collections/cisco/aci/tests/integration/targets/aci_vzany_to_contract/tasks/main.yml new file mode 100644 index 000000000..65e6f1278 --- /dev/null +++ b/ansible_collections/cisco/aci/tests/integration/targets/aci_vzany_to_contract/tasks/main.yml @@ -0,0 +1,170 @@ +# Author: Marcel Zehnder (@maercu) +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# 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") }}' + +# CLEAN ENVIRONMENT +- name: Remove test tenant1 before we kickoff + cisco.aci.aci_tenant: &tenant1_absent + <<: *aci_info + tenant: ansible_test + state: absent + +- name: Remove test tenant2 before we kickoff + cisco.aci.aci_tenant: &tenant2_absent + <<: *aci_info + tenant: ansible_test_2 + state: absent + +# SETUP ENVIRONMENT +- name: Create tenant1 + cisco.aci.aci_tenant: &tenant1_present + <<: *tenant1_absent + state: present + +- name: Configure source contract for cif + cisco.aci.aci_contract: + <<: *tenant1_present + contract: cifsrc + +- name: Create tenant2 + cisco.aci.aci_tenant: &tenant2_present + <<: *tenant2_absent + state: present + +- name: Create VRF + cisco.aci.aci_vrf: &vrf_present + <<: *tenant2_present + vrf: vzanyvrf + +- name: Configure contract + cisco.aci.aci_contract: + <<: *tenant2_present + contract: '{{ item }}' + loop: + - testcp + - testcp2 + +- name: Create contract interface in test tenant + cisco.aci.aci_contract_export: + <<: *tenant1_present + contract: cifsrc + destination_tenant: ansible_test_2 + name: testcif + +# BEGIN WITH TESTS +- name: Attach contract as provider to vzAny (check_mode) + cisco.aci.aci_vzany_to_contract: &prov_present + <<: *vrf_present + contract: testcp + contract_type: provider + check_mode: true + register: cm_vzany_prov + +- name: Attach contract as provider to vzAny (normal_mode) + cisco.aci.aci_vzany_to_contract: + <<: *prov_present + register: nm_vzany_prov + +- name: Verify vzany_prov + assert: + that: + - cm_vzany_prov is changed + - nm_vzany_prov is changed + - cm_vzany_prov.previous == nm_vzany_prov.previous == [] + - cm_vzany_prov.sent.vzRsAnyToProv.attributes.tnVzBrCPName == nm_vzany_prov.sent.vzRsAnyToProv.attributes.tnVzBrCPName == 'testcp' + - nm_vzany_prov.current.0.vzRsAnyToProv.attributes.annotation == 'orchestrator:ansible' + +- name: Attach contract again, check if idempotency works + cisco.aci.aci_vzany_to_contract: + <<: *prov_present + register: add_prov_again + +- name: Verify add_prov_again + assert: + that: + - add_prov_again is not changed + +# ATTACH ANOTHER PROVIDER +- name: Attach another contract as provider to vzAny + cisco.aci.aci_vzany_to_contract: &prov2_present + <<: *prov_present + contract: testcp2 + +# ATTACH CONTRACT AS CONSUMER +- name: Attach contract as consumer to vzAny + cisco.aci.aci_vzany_to_contract: &cons_present + <<: *prov_present + contract_type: consumer + +# ATTACH CONTRACT INTERFACE (AS CONSUMER) +- name: Attach contract interface to vzAny + cisco.aci.aci_vzany_to_contract: &cif_present + <<: *prov_present + contract: testcif + contract_type: interface + +# QUERY ALL PROVIDERS +- name: Query all providers + cisco.aci.aci_vzany_to_contract: + <<: *aci_info + state: query + contract_type: provider + register: query_all_provs + +- name: Verify query_all_provs + assert: + that: + - query_all_provs is not changed + - query_all_provs.current|length >= 2 + +# QUERY A SPECIFIC CONTRACT BINDING +- name: Query a specific binding + cisco.aci.aci_vzany_to_contract: + <<: *cons_present + state: query + register: query_spec_bind + +- name: Verify query_spec_bind + assert: + that: + - query_spec_bind is not changed + - query_spec_bind.current|length == 1 + +# REMOVE ALL BINDINGS +- name: Remove provider + cisco.aci.aci_vzany_to_contract: + <<: *prov_present + state: absent + register: del_prov + +- name: Remove consumer + cisco.aci.aci_vzany_to_contract: + <<: *cons_present + state: absent + register: del_cons + +- name: Remove interface + cisco.aci.aci_vzany_to_contract: + <<: *cif_present + state: absent + register: del_cif + +- name: Verify remove_intf + assert: + that: + - del_prov is changed + - del_cons is changed + - del_cif is changed + - del_prov.current == del_cons.current == del_cif.current ==[] +
\ No newline at end of file |