diff --git a/plugins/modules/aci_context_policy.py b/plugins/modules/aci_context_policy.py index 78231212c..aa35081b8 100644 --- a/plugins/modules/aci_context_policy.py +++ b/plugins/modules/aci_context_policy.py @@ -69,8 +69,8 @@ - cisco.aci.owner notes: -- The C(tenant) used must exist before using this module in your playbook. - The M(cisco.aci.aci_tenant) module can be used for this. +- The C(tenant) and the C(route_control_profile) used must exist before using this module in your playbook. + The M(cisco.aci.aci_tenant) and the M(cisco.aci.aci_route_control_profile) modules can be used for this. seealso: - module: cisco.aci.aci_tenant - name: APIC Management Information Model reference @@ -201,6 +201,8 @@ def main(): l3out=dict(type="str", aliases=["l3out_name"]), # Not required for querying all objects route_control_profile=dict(type="str", aliases=["rtctrl_profile_name"]), # Not required for querying all objects context_policy=dict(type="str", aliases=["name", "context_name"]), # Not required for querying all objects + subject_profile=dict(type="str", aliases=["subject_name"]), + action_rule=dict(type="str", aliases=["action_rule_name"]), action = dict(type="str", choices=["deny", "permit"]), order=dict(type="int"), description=dict(type="str", aliases=["descr"]), @@ -225,10 +227,14 @@ def main(): tenant = module.params.get("tenant") l3out = module.params.get("l3out") route_control_profile = module.params.get("route_control_profile") + subject_profile = module.params.get("subject_profile") + action_rule = module.params.get("action_rule") name_alias = module.params.get("name_alias") aci = ACIModule(module) + child_classes = ["rtctrlRsCtxPToSubjP", "rtctrlScope"] + tenant_url_config = dict( aci_class="fvTenant", aci_rn="tn-{0}".format(tenant), @@ -261,26 +267,40 @@ def main(): ), subclass_2=route_control_profile_url_config, subclass_3=context_policy_url_config, + child_classes=child_classes, ) else: aci.construct_url( root_class=tenant_url_config, subclass_1=route_control_profile_url_config, subclass_2=context_policy_url_config, + child_classes=child_classes, ) aci.get_existing() if state == "present": + child_configs = [] + if subject_profile is not None: + child_configs.append({"rtctrlRsCtxPToSubjP": {"attributes": {"tnRtctrlSubjPName": subject_profile}}}) + if action_rule is not None: + child_configs.append( + {"rtctrlScope": {"attributes": {"descr": ""}, + "children": [{"rtctrlRsScopeToAttrP": {"attributes": {"tnRtctrlAttrPName": action_rule}}}], + } + } + ) + aci.payload( aci_class="rtctrlCtxP", class_config=dict( - name=route_control_profile, + name=context_policy, descr=description, action=action, order=order, nameAlias=name_alias, ), + child_configs=child_configs, ) aci.get_diff(aci_class="rtctrlCtxP") diff --git a/plugins/modules/aci _match_as_path_regex_term.py b/plugins/modules/aci_match_as_path_regex_term.py similarity index 97% rename from plugins/modules/aci _match_as_path_regex_term.py rename to plugins/modules/aci_match_as_path_regex_term.py index 67fa766a3..05ce7b25a 100644 --- a/plugins/modules/aci _match_as_path_regex_term.py +++ b/plugins/modules/aci_match_as_path_regex_term.py @@ -58,8 +58,8 @@ - cisco.aci.owner notes: -- The C(tenant) used must exist before using this module in your playbook. - The M(cisco.aci.aci_tenant) module can be used for this. +- The C(tenant) and the C(subject_profile) used must exist before using this module in your playbook. + The M(cisco.aci.aci_tenant) and the M(cisco.aci.subject_profile) modules can be used for this. seealso: - module: cisco.aci.aci_tenant - name: APIC Management Information Model reference @@ -187,7 +187,6 @@ def main(): argument_spec.update(aci_owner_spec()) argument_spec.update( tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects - l3out=dict(type="str", aliases=["l3out_name"]), # Not required for querying all objects subject_profile=dict(type="str", aliases=["subject_name"]), # Not required for querying all objects match_as_path_regex_term=dict(type="str", aliases=["name", "match_rule_name"]), regex=dict(type="str"), diff --git a/plugins/modules/aci_match_community_factor.py b/plugins/modules/aci_match_community_factor.py new file mode 100644 index 000000000..c8da456df --- /dev/null +++ b/plugins/modules/aci_match_community_factor.py @@ -0,0 +1,277 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2023, Gaspard Micol (@gmicol) +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported_by": "certified"} + +DOCUMENTATION = r""" +--- +module: aci_subject_profile +short_description: Manage Match Community Factor (rtctrl:MatchCommFactor) +description: +- Manage Match Community Factors for Match Rules Based on Community on Cisco ACI fabrics. +options: + tenant: + description: + - The name of an existing tenant. + type: str + aliases: [ tenant_name ] + subject_profile: + description: + - Name of an exising subject profile. + type: str + aliases: [ subject_name ] + match_community_term: + description: + - Name of an existing match community term. + type: str + aliases: [ match_rule_name ] + community: + description: + - The match community value. + type: str + scope: + description: + - The item scope. + - if the scope is transitive, this community may be passed between ASs. + - if the scope is Non transitive, this community should be carried only within the local AS. + type: str + choices: [ transitive, non-transitive ] + description: + description: + - The description for the Match Community Term. + type: str + aliases: [ descr ] + state: + description: + - Use C(present) or C(absent) for adding or removing. + - Use C(query) for listing an object or multiple objects. + type: str + choices: [ absent, present, query ] + default: present + name_alias: + description: + - The alias for the current object. This relates to the nameAlias field in ACI. + type: str +extends_documentation_fragment: +- cisco.aci.aci +- cisco.aci.annotation +- cisco.aci.owner + +notes: +- The C(tenant), the C(subject_profile) and the C(match_community_term) used must exist before using this module in your playbook. + The M(cisco.aci.aci_tenant), the M(cisco.aci.subject_profile) and M(cisco.aci.match_community_term) modules can be used for this. +seealso: +- module: cisco.aci.aci_tenant +- name: APIC Management Information Model reference + description: More information about the internal APIC class B(rtctrl:MatchCommFactor). + link: https://developer.cisco.com/docs/apic-mim-ref/ +author: +- Gaspard Micol (@gmicol) +""" + +EXAMPLES = r""" +""" + +RETURN = r""" +current: + description: The existing configuration from the APIC after the module has finished + returned: success + type: list + sample: + [ + { + "fvTenant": { + "attributes": { + "descr": "Production environment", + "dn": "uni/tn-production", + "name": "production", + "nameAlias": "", + "ownerKey": "", + "ownerauto_continue": "" + } + } + } + ] +error: + description: The error information as returned from the APIC + returned: failure + type: dict + sample: + { + "code": "122", + "text": "unknown managed object class foo" + } +raw: + description: The raw output returned by the APIC REST API (xml or json) + returned: parse error + type: str + sample: '' +sent: + description: The actual/minimal configuration pushed to the APIC + returned: info + type: list + sample: + { + "fvTenant": { + "attributes": { + "descr": "Production environment" + } + } + } +previous: + description: The original configuration from the APIC before the module has started + returned: info + type: list + sample: + [ + { + "fvTenant": { + "attributes": { + "descr": "Production", + "dn": "uni/tn-production", + "name": "production", + "nameAlias": "", + "ownerKey": "", + "ownerauto_continue": "" + } + } + } + ] +proposed: + description: The assembled configuration from the user-provided parameters + returned: info + type: dict + sample: + { + "fvTenant": { + "attributes": { + "descr": "Production environment", + "name": "production" + } + } + } +filter_string: + description: The filter string used for the request + returned: failure or debug + type: str + sample: ?rsp-prop-include=config-only +method: + description: The HTTP method used for the request to the APIC + returned: failure or debug + type: str + sample: POST +response: + description: The HTTP response from the APIC + returned: failure or debug + type: str + sample: OK (30 bytes) +status: + description: The HTTP status from the APIC + returned: failure or debug + type: int + sample: 200 +url: + description: The HTTP url used for the request to the APIC + returned: failure or debug + type: str + sample: https://10.11.12.13/api/mo/uni/tn-production.json +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec, aci_owner_spec + + +def main(): + argument_spec = aci_argument_spec() + argument_spec.update(aci_annotation_spec()) + argument_spec.update(aci_owner_spec()) + argument_spec.update( + tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects + subject_profile=dict(type="str", aliases=["subject_name"]), # Not required for querying all objects + match_community_term=dict(type="str", aliases=["match_rule_name"]), # Not required for querying all objects + community=dict(type="str"), + scope=dict(type="str", choices=["transitive", "non-transitive"]), + description=dict(type="str", aliases=["descr"]), + name_alias=dict(type="str"), + state=dict(type="str", default="present", choices=["present", "absent", "query"]), + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[ + ["state", "absent", ["community", "tenant", "subject_profile", "match_community_term"]], + ["state", "present", ["community", "tenant", "subject_profile", "match_community_term"]], + ], + ) + + community = module.params.get("community") + scope = module.params.get("scope") + description = module.params.get("description") + state = module.params.get("state") + tenant = module.params.get("tenant") + subject_profile = module.params.get("subject_profile") + match_community_term = module.params.get("match_community_term") + name_alias = module.params.get("name_alias") + + aci = ACIModule(module) + + aci.construct_url( + root_class=dict( + aci_class="fvTenant", + aci_rn="tn-{0}".format(tenant), + module_object=tenant, + target_filter={"name": tenant}, + ), + subclass_1=dict( + aci_class="rtctrlSubjP", + aci_rn="subj-{0}".format(subject_profile), + module_object=subject_profile, + target_filter={"name": subject_profile}, + ), + subclass_2=dict( + aci_class="rtctrlMatchCommTerm", + aci_rn="commtrm-{0}".format(match_community_term), + module_object=match_community_term, + target_filter={"name": match_community_term}, + ), + subclass_3=dict( + aci_class="rtctrlMatchCommFactor", + aci_rn="commfct-{0}".format(community), + module_object=community, + target_filter={"community": community}, + ), + ) + + aci.get_existing() + + if state == "present": + aci.payload( + aci_class="rtctrlMatchCommFactor", + class_config=dict( + community=community, + scope=scope, + descr=description, + nameAlias=name_alias, + ), + ) + + aci.get_diff(aci_class="rtctrlMatchCommFactor") + + aci.post_config() + + elif state == "absent": + aci.delete_config() + + aci.exit_json() + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/plugins/modules/aci_match_comm_regex_term.py b/plugins/modules/aci_match_community_regex_term.py similarity index 89% rename from plugins/modules/aci_match_comm_regex_term.py rename to plugins/modules/aci_match_community_regex_term.py index 8295aa5cf..34bc52094 100644 --- a/plugins/modules/aci_match_comm_regex_term.py +++ b/plugins/modules/aci_match_community_regex_term.py @@ -63,8 +63,9 @@ - cisco.aci.owner notes: -- The C(tenant) used must exist before using this module in your playbook. - The M(cisco.aci.aci_tenant) module can be used for this. +- The C(tenant) and the C(subject_profile) used must exist before using this module in your playbook. + The M(cisco.aci.aci_tenant) and the M(cisco.aci.subject_profile) modules can be used for this. +- Only two match community regex terms can exist at the same two, one of each C(community_type). seealso: - module: cisco.aci.aci_tenant - name: APIC Management Information Model reference @@ -191,11 +192,10 @@ def main(): argument_spec.update(aci_annotation_spec()) argument_spec.update(aci_owner_spec()) argument_spec.update( - tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects - l3out=dict(type="str", aliases=["l3out_name"]), # Not required for querying all objects + tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects subject_profile=dict(type="str", aliases=["subject_name"]), # Not required for querying all objects match_community_regex_term=dict(type="str", aliases=["name", "match_rule_name"]), - community_type=dict(type="str", choices=["extended", "regular"]), + community_type=dict(type="str", default="regular", choices=["extended", "regular"]), regex=dict(type="str"), description=dict(type="str", aliases=["descr"]), name_alias=dict(type="str"), @@ -206,8 +206,8 @@ def main(): argument_spec=argument_spec, supports_check_mode=True, required_if=[ - ["state", "absent", ["match_community_regex_term", "tenant"]], - ["state", "present", ["match_community_regex_term", "tenant"]], + ["state", "absent", ["community_type", "tenant", "subject_profile"]], + ["state", "present", ["community_type", "tenant", "subject_profile"]], ], ) @@ -237,9 +237,9 @@ def main(): ), subclass_2=dict( aci_class="rtctrlMatchCommRegexTerm", - aci_rn="commrxtrm-{0}".format(match_community_regex_term), - module_object=match_community_regex_term, - target_filter={"name": match_community_regex_term}, + aci_rn="commrxtrm-{0}".format(community_type), + module_object=community_type, + target_filter={"commType": community_type}, ), ) diff --git a/plugins/modules/aci_match_community_term.py b/plugins/modules/aci_match_community_term.py index dc46ddba1..83fc50837 100644 --- a/plugins/modules/aci_match_community_term.py +++ b/plugins/modules/aci_match_community_term.py @@ -54,8 +54,8 @@ - cisco.aci.owner notes: -- The C(tenant) used must exist before using this module in your playbook. - The M(cisco.aci.aci_tenant) module can be used for this. +- The C(tenant) and the C(subject_profile) used must exist before using this module in your playbook. + The M(cisco.aci.aci_tenant) and the M(cisco.aci.subject_profile) modules can be used for this. seealso: - module: cisco.aci.aci_tenant - name: APIC Management Information Model reference @@ -183,7 +183,6 @@ def main(): argument_spec.update(aci_owner_spec()) argument_spec.update( tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects - l3out=dict(type="str", aliases=["l3out_name"]), # Not required for querying all objects subject_profile=dict(type="str", aliases=["subject_name"]), # Not required for querying all objects match_community_term=dict(type="str", aliases=["name", "match_rule_name"]), description=dict(type="str", aliases=["descr"]), @@ -195,8 +194,8 @@ def main(): argument_spec=argument_spec, supports_check_mode=True, required_if=[ - ["state", "absent", ["match_community_term", "tenant"]], - ["state", "present", ["match_community_term", "tenant"]], + ["state", "absent", ["match_community_term", "tenant", "subject_profile"]], + ["state", "present", ["match_community_term", "tenant", "subject_profile"]], ], ) @@ -224,7 +223,7 @@ def main(): ), subclass_2=dict( aci_class="rtctrlMatchCommTerm", - aci_rn="commrxtrm-{0}".format(match_community_term), + aci_rn="commtrm-{0}".format(match_community_term), module_object=match_community_term, target_filter={"name": match_community_term}, ), diff --git a/plugins/modules/aci_match_route_destination.py b/plugins/modules/aci_match_route_destination.py index b72e8c40c..2c3faf7d4 100644 --- a/plugins/modules/aci_match_route_destination.py +++ b/plugins/modules/aci_match_route_destination.py @@ -39,10 +39,12 @@ from_prefix_lenght: description: - Start of the prefix lenght. + - It corresponds to the less equal Mask if the route is aggregated. type: str to_prefix_lenght: description: - End of the prefix lenght. + - It corresponds to greater equal Mask if the route is aggregated. description: description: - The description for the Match Action Rule. @@ -65,8 +67,8 @@ - cisco.aci.owner notes: -- The C(tenant) used must exist before using this module in your playbook. - The M(cisco.aci.aci_tenant) module can be used for this. +- The C(tenant) and the C(subject_profile) used must exist before using this module in your playbook. + The M(cisco.aci.aci_tenant) and the M(cisco.aci.subject_profile) modules can be used for this. seealso: - module: cisco.aci.aci_tenant - name: APIC Management Information Model reference @@ -194,12 +196,11 @@ def main(): argument_spec.update(aci_owner_spec()) argument_spec.update( tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects - l3out=dict(type="str", aliases=["l3out_name"]), # Not required for querying all objects subject_profile=dict(type="str", aliases=["subject_name"]), # Not required for querying all objects - ip=dict(type="str", aliases=["name", "match_rule_name"]), - aggregate=dict(type="str", choices=["extended", "regular"]), - from_prefix_lenght=dict(type="str"), - to_prefix_lenght=dict(type="str"), + ip=dict(type="str"), + aggregate=dict(type="str", choices=["no", "yes"]), + from_prefix_lenght=dict(type="int"), + to_prefix_lenght=dict(type="int"), description=dict(type="str", aliases=["descr"]), name_alias=dict(type="str"), state=dict(type="str", default="present", choices=["present", "absent", "query"]), @@ -209,8 +210,8 @@ def main(): argument_spec=argument_spec, supports_check_mode=True, required_if=[ - ["state", "absent", ["ip", "tenant"]], - ["state", "present", ["ip", "tenant"]], + ["state", "absent", ["ip", "tenant", "subject_profile"]], + ["state", "present", ["ip", "tenant", "subject_profile"]], ], ) diff --git a/plugins/modules/aci_subject_profile.py b/plugins/modules/aci_subject_profile.py index 9139f6119..4ee7f9d7f 100644 --- a/plugins/modules/aci_subject_profile.py +++ b/plugins/modules/aci_subject_profile.py @@ -178,7 +178,6 @@ def main(): argument_spec.update(aci_owner_spec()) argument_spec.update( tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects - l3out=dict(type="str", aliases=["l3out_name"]), # Not required for querying all objects subject_profile=dict(type="str", aliases=["name", "subject_name"]), # Not required for querying all objects description=dict(type="str", aliases=["descr"]), name_alias=dict(type="str"), diff --git a/tests/integration/targets/aci_context_policy/aliases b/tests/integration/targets/aci_context_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/tests/integration/targets/aci_context_policy/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/tests/integration/targets/aci_context_policy/tasks/main.yml b/tests/integration/targets/aci_context_policy/tasks/main.yml new file mode 100644 index 000000000..fb06a562b --- /dev/null +++ b/tests/integration/targets/aci_context_policy/tasks/main.yml @@ -0,0 +1,196 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a new action rule profile + aci_tenant_action_rule_profile: &aci_action_rule_present + <<: *aci_info + tenant: ansible_tenant + action_rule: ansible_action_rule + description: Ansible action rule profile for ansible_tenant tenant + state: present + + - name: Add a new L3Out + aci_l3out: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + description: Ansible l3Out for ansible_tenant tenant + domain: ansible_dom + vrf: ansible_vrf + state: present + + - name: Add route control profile for l3out + aci_route_control_profile: + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + route_control_profile: ansible_rtctrl_profile_l3out + description: Ansible Route Control Profile for ansible_l3out l3Out + state: present + + - name: Add subject profile + aci_subject_profile: &aci_subject_profile_present + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + description: Ansible Subject Profile for ansible_tenant tenant + state: present + + - name: Add context policy for l3out (check_mode) + aci_context_policy: &aci_context_policy_present + <<: *aci_info + tenant: ansible_tenant + l3out: ansible_l3out + route_control_profile: ansible_rtctrl_profile_l3out + context_policy: ansible_context_policy_l3out + description: Ansible Context Policy for ansible_rtctrl_profile_l3out route control profile + subject_profile: ansible_subject_profile + action_rule: ansible_action_rule + action: deny + order: 5 + state: present + check_mode: true + register: cm_add_context_policy_l3out + + - name: Add context policy again (normal_mode) + aci_context_policy: + <<: *aci_context_policy_present + register: nm_add_context_policy_l3out + + - name: Add context policy again - testing idempotency + aci_context_policy: + <<: *aci_context_policy_present + register: nm_add_context_policy_l3out_idempotency + + - name: Add route control profile for tenant + aci_route_control_profile: + <<: *aci_info + tenant: ansible_tenant + route_control_profile: ansible_rtctrl_profile_tenant + description: Route Control Profile for ansible_tenant tenant + state: present + + - name: Add context policy for tenant + aci_context_policy: + <<: *aci_info + tenant: ansible_tenant + route_control_profile: ansible_rtctrl_profile_tenant + context_policy: ansible_context_policy_tenant + description: Ansible Context Policy for ansible_rtctrl_profile_tenant route control profile + state: present + register: nm_add_context_policy_tenant + + - name: Asserts for route control profiles creation tasks + assert: + that: + - cm_add_context_policy_l3out is changed + - cm_add_context_policy_l3out.previous == [] + - cm_add_context_policy_l3out.current == [] + - nm_add_context_policy_l3out is changed + - nm_add_context_policy_l3out.current.0.rtctrlCtxP.attributes.name == "ansible_context_policy_l3out" + - nm_add_context_policy_l3out.current.0.rtctrlCtxP.attributes.action == "deny" + - nm_add_context_policy_l3out.current.0.rtctrlCtxP.attributes.order == "5" + - nm_add_context_policy_l3out.current.0.rtctrlCtxP.children.0.rtctrlScope.children.0.rtctrlRsScopeToAttrP.attributes.tnRtctrlAttrPName == "ansible_action_rule" + - nm_add_context_policy_l3out.current.0.rtctrlCtxP.children.1.rtctrlRsCtxPToSubjP.attributes.tnRtctrlSubjPName == "ansible_subject_profile" + - nm_add_context_policy_l3out_idempotency is not changed + - nm_add_context_policy_tenant is changed + - nm_add_context_policy_tenant.previous == [] + - nm_add_context_policy_tenant.current.0.rtctrlCtxP.attributes.name == "ansible_context_policy_tenant" + - nm_add_context_policy_tenant.current.0.rtctrlCtxP.attributes.action == "permit" + - nm_add_context_policy_tenant.current.0.rtctrlCtxP.attributes.order == "0" + + - name: Query all context policy + aci_context_policy: + <<: *aci_info + state: query + register: query_all_context_policy + + - name: Query ansible_context_policy_l3out context policy + aci_context_policy: + <<: *aci_info + context_policy: ansible_context_policy_l3out + state: query + register: query_context_policy_l3out + + - name: Asserts query tasks + assert: + that: + - query_all_context_policy is not changed + - query_all_context_policy.current|length >= 2 + - query_context_policy_l3out is not changed + - query_context_policy_l3out.current.0.rtctrlCtxP.attributes.name == "ansible_context_policy_l3out" + - query_context_policy_l3out.current.0.rtctrlCtxP.attributes.action == "deny" + - query_context_policy_l3out.current.0.rtctrlCtxP.attributes.order == "5" + - query_context_policy_l3out.current.0.rtctrlCtxP.children.0.rtctrlScope.children.0.rtctrlRsScopeToAttrP.attributes.tDn == "uni/tn-ansible_tenant/attr-ansible_action_rule" + - query_context_policy_l3out.current.0.rtctrlCtxP.children.1.rtctrlRsCtxPToSubjP.attributes.tDn == "uni/tn-ansible_tenant/subj-ansible_subject_profile" + + - name: Remove context policy for l3out (check_mode) + aci_context_policy: &aci_context_policy_absent + <<: *aci_context_policy_present + state: absent + check_mode: true + register: cm_remove_context_policy + + - name: Remove context policy for l3out (normal_mode) + aci_context_policy: + <<: *aci_context_policy_absent + register: nm_remove_remove_context_policy + + - name: Remove route control profile for l3out - testing idempotency + aci_context_policy: + <<: *aci_context_policy_absent + register: nm_remove_context_policy_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_context_policy is changed + - cm_remove_context_policy.proposed == {} + - nm_remove_remove_context_policy is changed + - nm_remove_remove_context_policy.previous != [] + - nm_remove_remove_context_policy.method == "DELETE" + - nm_remove_context_policy_idempotency is not changed + - nm_remove_context_policy_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent diff --git a/tests/integration/targets/aci_match_as_path_regex_term/aliases b/tests/integration/targets/aci_match_as_path_regex_term/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/tests/integration/targets/aci_match_as_path_regex_term/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/tests/integration/targets/aci_match_as_path_regex_term/tasks/main.yml b/tests/integration/targets/aci_match_as_path_regex_term/tasks/main.yml new file mode 100644 index 000000000..466fcd405 --- /dev/null +++ b/tests/integration/targets/aci_match_as_path_regex_term/tasks/main.yml @@ -0,0 +1,150 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a subject profile + aci_subject_profile: + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + description: subject profile for ansible_tenant tenant + state: present + register: cm_add_subject_profile + + - name: Add a match regex AS-Path term (check_mode) + aci_match_as_path_regex_term: &aci_match_as_path_regex_term_present + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + match_as_path_regex_term: ansible_match_as_path_regex_term_1 + description: match regex AS-Path term 1 for ansible_subject_profile subject profile + regex: .* + state: present + check_mode: true + register: cm_add_match_as_path_regex_term + + - name: Add a match regex AS-Path term (normal_mode) + aci_match_as_path_regex_term: + <<: *aci_match_as_path_regex_term_present + register: nm_add_match_as_path_regex_term + + - name: Add the first match regex AS-Path term again - testing idempotency + aci_match_as_path_regex_term: + <<: *aci_match_as_path_regex_term_present + register: nm_add_match_as_path_regex_term_idempotency + + - name: Add a second match regex AS-Path term (normal_mode) + aci_match_as_path_regex_term: + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + match_as_path_regex_term: ansible_match_as_path_regex_term_2 + description: match regex AS-Path term 2 for ansible_subject_profile subject profile + state: present + register: nm_add_match_as_path_regex_term_2 + + - name: Asserts for match regex AS-Path terms creation tasks + assert: + that: + - cm_add_match_as_path_regex_term is changed + - cm_add_match_as_path_regex_term.previous == [] + - cm_add_match_as_path_regex_term.current == [] + - nm_add_match_as_path_regex_term is changed + - nm_add_match_as_path_regex_term.current.0.rtctrlMatchAsPathRegexTerm.attributes.name == "ansible_match_as_path_regex_term_1" + - nm_add_match_as_path_regex_term.current.0.rtctrlMatchAsPathRegexTerm.attributes.regex == ".*" + - nm_add_match_as_path_regex_term_idempotency is not changed + - nm_add_match_as_path_regex_term_2 is changed + - nm_add_match_as_path_regex_term_2.previous == [] + - nm_add_match_as_path_regex_term_2.current.0.rtctrlMatchAsPathRegexTerm.attributes.name == "ansible_match_as_path_regex_term_2" + - nm_add_match_as_path_regex_term_2.current.0.rtctrlMatchAsPathRegexTerm.attributes.regex == "" + + - name: Query all match regex AS-Path terms + aci_match_as_path_regex_term: + <<: *aci_info + state: query + register: query_all_match_as_path_regex_term + + - name: Query ansible_match_as_path_regex_term_1 + aci_match_as_path_regex_term: + <<: *aci_match_as_path_regex_term_present + state: query + register: query_ansible_match_as_path_regex_term_1 + + - name: Asserts query tasks + assert: + that: + - query_all_match_as_path_regex_term is not changed + - query_all_match_as_path_regex_term.current|length >= 2 + - query_ansible_match_as_path_regex_term_1 is not changed + - query_ansible_match_as_path_regex_term_1.current.0.rtctrlMatchAsPathRegexTerm.attributes.name == "ansible_match_as_path_regex_term_1" + - query_ansible_match_as_path_regex_term_1.current.0.rtctrlMatchAsPathRegexTerm.attributes.regex == ".*" + + - name: Remove match regex AS-Path term for l3out (check_mode) + aci_match_as_path_regex_term: &match_as_path_regex_term_absent + <<: *aci_match_as_path_regex_term_present + state: absent + check_mode: true + register: cm_remove_match_as_path_regex_term + + - name: Remove match regex AS-Path term for l3out (normal_mode) + aci_match_as_path_regex_term: + <<: *match_as_path_regex_term_absent + register: nm_remove_match_as_path_regex_term + + - name: Remove match regex AS-Path term for l3out - testing idempotency + aci_match_as_path_regex_term: + <<: *match_as_path_regex_term_absent + register: nm_remove_match_as_path_regex_term_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_match_as_path_regex_term is changed + - cm_remove_match_as_path_regex_term.proposed == {} + - nm_remove_match_as_path_regex_term is changed + - nm_remove_match_as_path_regex_term.previous != [] + - nm_remove_match_as_path_regex_term.method == "DELETE" + - nm_remove_match_as_path_regex_term_idempotency is not changed + - nm_remove_match_as_path_regex_term_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent diff --git a/tests/integration/targets/aci_match_community_factor/aliases b/tests/integration/targets/aci_match_community_factor/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/tests/integration/targets/aci_match_community_factor/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/tests/integration/targets/aci_match_community_factor/tasks/main.yml b/tests/integration/targets/aci_match_community_factor/tasks/main.yml new file mode 100644 index 000000000..28f2c68aa --- /dev/null +++ b/tests/integration/targets/aci_match_community_factor/tasks/main.yml @@ -0,0 +1,157 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a subject profile + aci_subject_profile: + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + description: subject profile for ansible_tenant tenant + state: present + + - name: Add a match community term + aci_match_community_term: + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + match_community_term: ansible_match_community_term + description: match community term for ansible_subject_profile subject profile + state: present + + - name: Add a match community factor (check_mode) + aci_match_community_factor: &aci_match_community_factor_present + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + match_community_term: ansible_match_community_term + community: regular:as2-nn2:4:15 + scope: non-transitive + description: match community factor 1 for ansible_match_community_term + state: present + check_mode: true + register: cm_add_match_community_factor + + - name: Add a match community factor (normal_mode) + aci_match_community_factor: + <<: *aci_match_community_factor_present + register: nm_add_match_community_factor + + - name: Add the first match community factor again - testing idempotency + aci_match_community_factor: + <<: *aci_match_community_factor_present + register: nm_add_match_community_factor_idempotency + + - name: Add a second match community factor (normal_mode) + aci_match_community_factor: + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + match_community_term: ansible_match_community_term + community: regular:as2-nn2:4:16 + description: match community factor 2 for ansible_match_community_term + state: present + register: nm_add_match_community_factor_2 + + - name: Asserts for match community factors creation tasks + assert: + that: + - cm_add_match_community_factor is changed + - cm_add_match_community_factor.previous == [] + - cm_add_match_community_factor.current == [] + - nm_add_match_community_factor is changed + - nm_add_match_community_factor.current.0.rtctrlMatchCommFactor.attributes.community == "regular:as2-nn2:4:15" + - nm_add_match_community_factor_idempotency is not changed + - nm_add_match_community_factor_2 is changed + - nm_add_match_community_factor_2.previous == [] + - nm_add_match_community_factor_2.current.0.rtctrlMatchCommFactor.attributes.community == "regular:as2-nn2:4:16" + + - name: Query all match community factors + aci_match_community_factor: + <<: *aci_info + state: query + register: query_all_match_community_factor + + - name: Query a specific match community factor + aci_match_community_factor: + <<: *aci_match_community_factor_present + state: query + register: query_ansible_match_community_factor_1 + + - name: Asserts query tasks + assert: + that: + - query_all_match_community_factor is not changed + - query_all_match_community_factor.current|length >= 2 + - query_ansible_match_community_factor_1 is not changed + - query_ansible_match_community_factor_1.current.0.rtctrlMatchCommFactor.attributes.community == "regular:as2-nn2:4:15" + + - name: Remove match community factor (check_mode) + aci_match_community_factor: &match_community_term_absent + <<: *aci_match_community_factor_present + state: absent + check_mode: true + register: cm_remove_match_community_factor + + - name: Remove match community factor (normal_mode) + aci_match_community_factor: + <<: *match_community_term_absent + register: nm_remove_match_community_factor + + - name: Remove match community factor - testing idempotency + aci_match_community_factor: + <<: *match_community_term_absent + register: nm_remove_match_community_factor_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_match_community_factor is changed + - cm_remove_match_community_factor.proposed == {} + - nm_remove_match_community_factor is changed + - nm_remove_match_community_factor.previous != [] + - nm_remove_match_community_factor.method == "DELETE" + - nm_remove_match_community_factor_idempotency is not changed + - nm_remove_match_community_factor_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent diff --git a/tests/integration/targets/aci_match_community_regex_term/aliases b/tests/integration/targets/aci_match_community_regex_term/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/tests/integration/targets/aci_match_community_regex_term/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/tests/integration/targets/aci_match_community_regex_term/tasks/main.yml b/tests/integration/targets/aci_match_community_regex_term/tasks/main.yml new file mode 100644 index 000000000..9e9bf654f --- /dev/null +++ b/tests/integration/targets/aci_match_community_regex_term/tasks/main.yml @@ -0,0 +1,152 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a subject profile + aci_subject_profile: + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + description: subject profile for ansible_tenant tenant + state: present + register: cm_add_subject_profile + + - name: Add a match community regex term (check_mode) + aci_match_community_regex_term: &aci_match_community_regex_term_present + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + name: ansible_community_regex_extended + description: match extended community regex term for ansible_subject_profile subject profile + community_type: extended + regex: .* + state: present + check_mode: true + register: cm_add_match_community_regex_term + + - name: Add a match community regex term (normal_mode) + aci_match_community_regex_term: + <<: *aci_match_community_regex_term_present + register: nm_add_match_community_regex_term + + - name: Add the first match community regex term again - testing idempotency + aci_match_community_regex_term: + <<: *aci_match_community_regex_term_present + register: nm_add_match_community_regex_term_idempotency + + - name: Add a second match community regex term (normal_mode) + aci_match_community_regex_term: &aci_match_community_regex_term_2_present + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + description: match regular community regex term for ansible_subject_profile subject profile + state: present + register: nm_add_match_community_regex_term_2 + + - name: Asserts for match community regex terms creation tasks + assert: + that: + - cm_add_match_community_regex_term is changed + - cm_add_match_community_regex_term.previous == [] + - cm_add_match_community_regex_term.current == [] + - nm_add_match_community_regex_term is changed + - nm_add_match_community_regex_term.current.0.rtctrlMatchCommRegexTerm.attributes.regex == ".*" + - nm_add_match_community_regex_term.current.0.rtctrlMatchCommRegexTerm.attributes.name == "ansible_community_regex_extended" + - nm_add_match_community_regex_term.current.0.rtctrlMatchCommRegexTerm.attributes.commType == "extended" + - nm_add_match_community_regex_term_idempotency is not changed + - nm_add_match_community_regex_term_2 is changed + - nm_add_match_community_regex_term_2.previous == [] + - nm_add_match_community_regex_term_2.current.0.rtctrlMatchCommRegexTerm.attributes.regex == "" + - nm_add_match_community_regex_term_2.current.0.rtctrlMatchCommRegexTerm.attributes.commType == "regular" + + - name: Query all match community regex terms + aci_match_community_regex_term: + <<: *aci_info + state: query + community_type: extended + register: query_all_match_community_regex_term + + - name: Query ansible_match_community_regex_term_regular + aci_match_community_regex_term: + <<: *aci_match_community_regex_term_2_present + state: query + register: query_ansible_match_community_regex_term_regular + + - name: Asserts query tasks + assert: + that: + - query_all_match_community_regex_term is not changed + - query_all_match_community_regex_term.current.0.rtctrlMatchCommRegexTerm.attributes.commType == "extended" + - query_ansible_match_community_regex_term_regular is not changed + - query_ansible_match_community_regex_term_regular.current.0.rtctrlMatchCommRegexTerm.attributes.regex == "" + - query_ansible_match_community_regex_term_regular.current.0.rtctrlMatchCommRegexTerm.attributes.commType == "regular" + + - name: Remove match community regex term (check_mode) + aci_match_community_regex_term: &match_community_regex_term_absent + <<: *aci_match_community_regex_term_present + state: absent + check_mode: true + register: cm_remove_match_community_regex_term + + - name: Remove match community regex term (normal_mode) + aci_match_community_regex_term: + <<: *match_community_regex_term_absent + register: nm_remove_match_community_regex_term + + - name: Remove match community regex term - testing idempotency + aci_match_community_regex_term: + <<: *match_community_regex_term_absent + register: nm_remove_match_community_regex_term_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_match_community_regex_term is changed + - cm_remove_match_community_regex_term.proposed == {} + - nm_remove_match_community_regex_term is changed + - nm_remove_match_community_regex_term.previous != [] + - nm_remove_match_community_regex_term.method == "DELETE" + - nm_remove_match_community_regex_term_idempotency is not changed + - nm_remove_match_community_regex_term_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent \ No newline at end of file diff --git a/tests/integration/targets/aci_match_community_term/aliases b/tests/integration/targets/aci_match_community_term/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/tests/integration/targets/aci_match_community_term/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/tests/integration/targets/aci_match_community_term/tasks/main.yml b/tests/integration/targets/aci_match_community_term/tasks/main.yml new file mode 100644 index 000000000..7e619206e --- /dev/null +++ b/tests/integration/targets/aci_match_community_term/tasks/main.yml @@ -0,0 +1,146 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a subject profile + aci_subject_profile: + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + description: subject profile for ansible_tenant tenant + state: present + register: cm_add_subject_profile + + - name: Add a match community term (check_mode) + aci_match_community_term: &aci_match_community_term_present + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + match_community_term: ansible_match_community_term_1 + description: match community term 1 for ansible_subject_profile subject profile + state: present + check_mode: true + register: cm_add_match_community_term + + - name: Add a match community term (normal_mode) + aci_match_community_term: + <<: *aci_match_community_term_present + register: nm_add_match_community_term + + - name: Add the first match community term again - testing idempotency + aci_match_community_term: + <<: *aci_match_community_term_present + register: nm_add_match_community_term_idempotency + + - name: Add a second match community term (normal_mode) + aci_match_community_term: + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + match_community_term: ansible_match_community_term_2 + description: match community term 2 for ansible_subject_profile subject profile + state: present + register: nm_add_match_community_term_2 + + - name: Asserts for match community terms creation tasks + assert: + that: + - cm_add_match_community_term is changed + - cm_add_match_community_term.previous == [] + - cm_add_match_community_term.current == [] + - nm_add_match_community_term is changed + - nm_add_match_community_term.current.0.rtctrlMatchCommTerm.attributes.name == "ansible_match_community_term_1" + - nm_add_match_community_term_idempotency is not changed + - nm_add_match_community_term_2 is changed + - nm_add_match_community_term_2.previous == [] + - nm_add_match_community_term_2.current.0.rtctrlMatchCommTerm.attributes.name == "ansible_match_community_term_2" + + - name: Query all match community terms + aci_match_community_term: + <<: *aci_info + state: query + register: query_all_match_community_term + + - name: Query ansible_match_community_term_1 + aci_match_community_term: + <<: *aci_match_community_term_present + state: query + register: query_ansible_match_community_term_1 + + - name: Asserts query tasks + assert: + that: + - query_all_match_community_term is not changed + - query_all_match_community_term.current|length >= 2 + - query_ansible_match_community_term_1 is not changed + - query_ansible_match_community_term_1.current.0.rtctrlMatchCommTerm.attributes.name == "ansible_match_community_term_1" + + - name: Remove match community term (check_mode) + aci_match_community_term: &match_community_term_absent + <<: *aci_match_community_term_present + state: absent + check_mode: true + register: cm_remove_match_community_term + + - name: Remove match community term (normal_mode) + aci_match_community_term: + <<: *match_community_term_absent + register: nm_remove_match_community_term + + - name: Remove match community term - testing idempotency + aci_match_community_term: + <<: *match_community_term_absent + register: nm_remove_match_community_term_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_match_community_term is changed + - cm_remove_match_community_term.proposed == {} + - nm_remove_match_community_term is changed + - nm_remove_match_community_term.previous != [] + - nm_remove_match_community_term.method == "DELETE" + - nm_remove_match_community_term_idempotency is not changed + - nm_remove_match_community_term_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent diff --git a/tests/integration/targets/aci_match_route_destination/aliases b/tests/integration/targets/aci_match_route_destination/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/tests/integration/targets/aci_match_route_destination/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/tests/integration/targets/aci_match_route_destination/tasks/main.yml b/tests/integration/targets/aci_match_route_destination/tasks/main.yml new file mode 100644 index 000000000..3a57570a8 --- /dev/null +++ b/tests/integration/targets/aci_match_route_destination/tasks/main.yml @@ -0,0 +1,158 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a subject profile + aci_subject_profile: + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + description: subject profile for ansible_tenant tenant + state: present + register: cm_add_subject_profile + + - name: Add a match route destination rule (check_mode) + aci_match_route_destination: &aci_match_route_destination_present + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + description: match route destination rule 1 for ansible_subject_profile subject profile + ip: 11.11.11.11/24 + aggregate: yes + from_prefix_lenght: 0 + to_prefix_lenght: 32 + state: present + check_mode: true + register: cm_add_match_route_destination + + - name: Add a match route destination rule (normal_mode) + aci_match_route_destination: + <<: *aci_match_route_destination_present + register: nm_add_match_route_destination + + - name: Add the first match route destination rule again - testing idempotency + aci_match_route_destination: + <<: *aci_match_route_destination_present + register: nm_add_match_route_destination_idempotency + + - name: Add a second match route destination rule (normal_mode) + aci_match_route_destination: + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile + description: match route destination rule 2 for ansible_subject_profile subject profile + ip: 11.11.11.12/24 + state: present + register: nm_add_match_route_destination_2 + + - name: Asserts for match route destination rule creation tasks + assert: + that: + - cm_add_match_route_destination is changed + - cm_add_match_route_destination.previous == [] + - cm_add_match_route_destination.current == [] + - nm_add_match_route_destination is changed + - nm_add_match_route_destination.current.0.rtctrlMatchRtDest.attributes.ip == "11.11.11.11/24" + - nm_add_match_route_destination.current.0.rtctrlMatchRtDest.attributes.aggregate == "yes" + - nm_add_match_route_destination.current.0.rtctrlMatchRtDest.attributes.fromPfxLen == "0" + - nm_add_match_route_destination.current.0.rtctrlMatchRtDest.attributes.toPfxLen == "32" + - nm_add_match_route_destination_idempotency is not changed + - nm_add_match_route_destination_2 is changed + - nm_add_match_route_destination_2.previous == [] + - nm_add_match_route_destination_2.current.0.rtctrlMatchRtDest.attributes.ip == "11.11.11.12/24" + - nm_add_match_route_destination_2.current.0.rtctrlMatchRtDest.attributes.aggregate == "no" + - nm_add_match_route_destination_2.current.0.rtctrlMatchRtDest.attributes.fromPfxLen == "0" + - nm_add_match_route_destination_2.current.0.rtctrlMatchRtDest.attributes.toPfxLen == "0" + + - name: Query all match regex AS-Path terms + aci_match_route_destination: + <<: *aci_info + state: query + register: query_all_match_route_destination + + - name: Query ansible_match_route_destination_1 + aci_match_route_destination: + <<: *aci_match_route_destination_present + state: query + register: query_ansible_match_route_destination_1 + + - name: Asserts query tasks + assert: + that: + - query_all_match_route_destination is not changed + - query_all_match_route_destination.current|length >= 2 + - query_ansible_match_route_destination_1 is not changed + - query_ansible_match_route_destination_1.current.0.rtctrlMatchRtDest.attributes.ip == "11.11.11.11/24" + - query_ansible_match_route_destination_1.current.0.rtctrlMatchRtDest.attributes.aggregate == "yes" + - query_ansible_match_route_destination_1.current.0.rtctrlMatchRtDest.attributes.fromPfxLen == "0" + - query_ansible_match_route_destination_1.current.0.rtctrlMatchRtDest.attributes.toPfxLen == "32" + + - name: Remove match route destination rule (check_mode) + aci_match_route_destination: &match_route_destination_absent + <<: *aci_match_route_destination_present + state: absent + check_mode: true + register: cm_remove_match_route_destination + + - name: Remove match route destination rule (normal_mode) + aci_match_route_destination: + <<: *match_route_destination_absent + register: nm_remove_match_route_destination + + - name: Remove match route destination rule - testing idempotency + aci_match_route_destination: + <<: *match_route_destination_absent + register: nm_remove_match_route_destination_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_match_route_destination is changed + - cm_remove_match_route_destination.proposed == {} + - nm_remove_match_route_destination is changed + - nm_remove_match_route_destination.previous != [] + - nm_remove_match_route_destination.method == "DELETE" + - nm_remove_match_route_destination_idempotency is not changed + - nm_remove_match_route_destination_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent \ No newline at end of file diff --git a/tests/integration/targets/aci_subject_profile/aliases b/tests/integration/targets/aci_subject_profile/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/tests/integration/targets/aci_subject_profile/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/tests/integration/targets/aci_subject_profile/tasks/main.yml b/tests/integration/targets/aci_subject_profile/tasks/main.yml new file mode 100644 index 000000000..51c1f423b --- /dev/null +++ b/tests/integration/targets/aci_subject_profile/tasks/main.yml @@ -0,0 +1,135 @@ +# Test code for the ACI modules +# Copyright: (c) 2023, Gaspard Micol (@gmicol) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + set_fact: + aci_info: &aci_info + host: "{{ aci_hostname }}" + username: "{{ aci_username }}" + password: "{{ aci_password }}" + validate_certs: '{{ aci_validate_certs | default(false) }}' + use_ssl: '{{ aci_use_ssl | default(true) }}' + use_proxy: '{{ aci_use_proxy | default(true) }}' + output_level: debug + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + aci_tenant: &aci_tenant_absent + <<: *aci_info + tenant: ansible_tenant + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + - name: Add a new tenant + aci_tenant: &aci_tenant_present + <<: *aci_info + tenant: ansible_tenant + description: Ansible tenant + state: present + + - name: Add a subject profile (check_mode) + aci_subject_profile: &aci_subject_profile_present + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile_1 + description: subject profile 1 for ansible_tenant tenant + state: present + check_mode: true + register: cm_add_subject_profile + + - name: Add a subject profile (normal_mode) + aci_subject_profile: + <<: *aci_subject_profile_present + register: nm_add_subject_profile + + - name: Add the first subject profile again - testing idempotency + aci_subject_profile: + <<: *aci_subject_profile_present + register: nm_add_subject_profile_idempotency + + - name: Add a second subject profile (normal_mode) + aci_subject_profile: + <<: *aci_info + tenant: ansible_tenant + subject_profile: ansible_subject_profile_2 + description: subject profile 2 for ansible_tenant tenant + state: present + register: nm_add_subject_profile_2 + + - name: Asserts for subject profiles creation tasks + assert: + that: + - cm_add_subject_profile is changed + - cm_add_subject_profile.previous == [] + - cm_add_subject_profile.current == [] + - nm_add_subject_profile is changed + - nm_add_subject_profile.current.0.rtctrlSubjP.attributes.name == "ansible_subject_profile_1" + - nm_add_subject_profile_idempotency is not changed + - nm_add_subject_profile_2 is changed + - nm_add_subject_profile_2.previous == [] + - nm_add_subject_profile_2.current.0.rtctrlSubjP.attributes.name == "ansible_subject_profile_2" + + - name: Query all subject profiles + aci_subject_profile: + <<: *aci_info + state: query + register: query_all_subject_profile + + - name: Query ansible_subject_profile_1 + aci_subject_profile: + <<: *aci_subject_profile_present + state: query + register: query_ansible_subject_profile_1 + + - name: Asserts query tasks + assert: + that: + - query_all_subject_profile is not changed + - query_all_subject_profile.current|length >= 2 + - query_ansible_subject_profile_1 is not changed + - query_ansible_subject_profile_1.current.0.rtctrlSubjP.attributes.name == "ansible_subject_profile_1" + + - name: Remove subject profile for l3out (check_mode) + aci_subject_profile: &subject_profile_absent + <<: *aci_subject_profile_present + state: absent + check_mode: true + register: cm_remove_subject_profile + + - name: Remove subject profile for l3out (normal_mode) + aci_subject_profile: + <<: *subject_profile_absent + register: nm_remove_subject_profile + + - name: Remove subject profile for l3out - testing idempotency + aci_subject_profile: + <<: *subject_profile_absent + register: nm_remove_subject_profile_idempotency + + - name: Asserts deletion tasks + assert: + that: + - cm_remove_subject_profile is changed + - cm_remove_subject_profile.proposed == {} + - nm_remove_subject_profile is changed + - nm_remove_subject_profile.previous != [] + - nm_remove_subject_profile.method == "DELETE" + - nm_remove_subject_profile_idempotency is not changed + - nm_remove_subject_profile_idempotency.previous == [] + + - name: Remove the ansible_tenant - cleanup before ending tests + aci_tenant: + <<: *aci_tenant_present + state: absent