From 6ee8a5b3cad4dc90c3d70f95a8610891ea504fc8 Mon Sep 17 00:00:00 2001 From: Gaspard Micol Date: Wed, 13 Sep 2023 12:54:41 -0400 Subject: [PATCH 01/11] [minor_change] Add loopback interface profile as a child class for aci_l3out_logical_node. --- plugins/modules/aci_l3out_logical_node.py | 23 +++++++- .../aci_l3out_logical_node/tasks/main.yml | 54 +++++++++++++------ 2 files changed, 59 insertions(+), 18 deletions(-) diff --git a/plugins/modules/aci_l3out_logical_node.py b/plugins/modules/aci_l3out_logical_node.py index 2bfc876ad..dea5ace4d 100644 --- a/plugins/modules/aci_l3out_logical_node.py +++ b/plugins/modules/aci_l3out_logical_node.py @@ -49,6 +49,9 @@ type: str choices: [ 'yes', 'no' ] default: 'yes' + loopback_address: + description: + - loopback IP of the loopback interface profile. state: description: - Use C(present) or C(absent) for adding or removing. @@ -243,6 +246,7 @@ def main(): node_id=dict(type="int"), router_id=dict(type="str"), router_id_as_loopback=dict(type="str", default="yes", choices=["yes", "no"]), + loopback_address = dict(type="str"), state=dict(type="str", default="present", choices=["absent", "present", "query"]), ) @@ -262,6 +266,7 @@ def main(): node_id = module.params.get("node_id") router_id = module.params.get("router_id") router_id_as_loopback = module.params.get("router_id_as_loopback") + loopback_address = module.params.get("loopback_address") state = module.params.get("state") tdn = None @@ -270,6 +275,13 @@ def main(): aci = ACIModule(module) + if loopback_address is not None: + child_classes = ["l3extLoopBackIfP"] + child_configs = [dict(l3extLoopBackIfP=dict(attributes=dict(name="", descr="", addr=loopback_address)))] + else: + child_classes = [] + child_configs = [] + aci.construct_url( root_class=dict( aci_class="fvTenant", @@ -295,12 +307,21 @@ def main(): module_object=tdn, target_filter={"name": tdn}, ), + child_classes=child_classes, ) aci.get_existing() if state == "present": - aci.payload(aci_class="l3extRsNodeL3OutAtt", class_config=dict(rtrId=router_id, rtrIdLoopBack=router_id_as_loopback, tDn=tdn)) + aci.payload( + aci_class="l3extRsNodeL3OutAtt", + class_config=dict( + rtrId=router_id, + rtrIdLoopBack=router_id_as_loopback, + tDn=tdn + ), + child_configs=child_configs, + ) aci.get_diff(aci_class="l3extRsNodeL3OutAtt") diff --git a/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml b/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml index 68bc64b20..e1bbe439d 100644 --- a/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml +++ b/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml @@ -1,6 +1,11 @@ # Author: Marcel Zehnder (@maercu) # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +- name: Test that we have an ACI APIC host, ACI username and ACI password + fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + # SET VARS - name: Set vars set_fact: @@ -11,11 +16,11 @@ 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") }}' + output_level: debug # CLEAN ENVIRONMENT - name: Remove test tenant before we kickoff - cisco.aci.aci_tenant: &tenant_absent + aci_tenant: &tenant_absent <<: *aci_info tenant: ansible_test state: absent @@ -28,38 +33,38 @@ block: # block specifies execution of tasks within, based on conditions # SETUP ENVIRONMENT - name: Create domain - cisco.aci.aci_domain: &domain_present + aci_domain: &domain_present <<: *aci_info domain: l3outtest domain_type: l3dom state: present - name: Create tenant - cisco.aci.aci_tenant: &tenant_present + aci_tenant: &tenant_present <<: *tenant_absent state: present - name: Configure VRF - cisco.aci.aci_vrf: &vrf_present + aci_vrf: &vrf_present <<: *tenant_present vrf: l3outtest - name: Create L3Out - cisco.aci.aci_l3out: + aci_l3out: <<: *vrf_present l3out: l3outtest domain: l3outtest route_control: export - name: Crete node profile - cisco.aci.aci_l3out_logical_node_profile: &np_present + 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 + aci_l3out_logical_node: &node_present <<: *np_present pod_id: 1 node_id: 111 @@ -69,7 +74,7 @@ register: cm_add_node - name: Add node (normal mode) - cisco.aci.aci_l3out_logical_node: + aci_l3out_logical_node: <<: *node_present register: nm_add_node @@ -85,7 +90,7 @@ - nm_add_node.current.0.l3extRsNodeL3OutAtt.attributes.annotation == 'orchestrator:ansible' - name: Add node again, check if idempotency works - cisco.aci.aci_l3out_logical_node: + aci_l3out_logical_node: <<: *node_present register: add_node_again @@ -96,28 +101,37 @@ # UPDATE NODE - name: Change roouter id - cisco.aci.aci_l3out_logical_node: &node_update + aci_l3out_logical_node: &node_update <<: *node_present router_id: 11.11.11.11 register: update_node + - name: Add loopback address + aci_l3out_logical_node: &node_add_loopback + <<: *node_update + loopback_address: 11.11.11.12 + register: add_loopback_ip + - name: Verify update_node assert: that: - update_node is changed - update_node.previous != [] - update_node.sent.l3extRsNodeL3OutAtt.attributes.rtrId == '11.11.11.11' + - add_loopback_ip is changed + - add_loopback_ip.previous != [] + - add_loopback_ip.current.0.l3extRsNodeL3OutAtt.children.0.l3extLoopBackIfP.attributes.addr == "11.11.11.12" # ADD ANOTHER NODE - name: Add another node - cisco.aci.aci_l3out_logical_node: + 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_l3out_logical_node: <<: *aci_info state: query register: query_all_nodes @@ -130,8 +144,8 @@ # QUERY A SPECIFIC NODE - name: Query a specific node - cisco.aci.aci_l3out_logical_node: - <<: *node_update + aci_l3out_logical_node: + <<: *node_add_loopback state: query register: query_spec_node @@ -143,8 +157,8 @@ # REMOVE NODE - name: Remove node - cisco.aci.aci_l3out_logical_node: - <<: *node_update + aci_l3out_logical_node: + <<: *node_add_loopback state: absent register: remove_node @@ -153,3 +167,9 @@ that: - remove_node is changed - remove_node.current == [] + + - name: Remove test tenant - clean-up the environment + aci_tenant: + <<: *aci_info + tenant: ansible_test + state: absent \ No newline at end of file From f460ecc85be5d0beb00e9f8b17d50b97b5800160 Mon Sep 17 00:00:00 2001 From: Gaspard Micol Date: Wed, 13 Sep 2023 13:00:08 -0400 Subject: [PATCH 02/11] [ignore] Apply Black for formating python files. --- plugins/modules/aci_l3out_logical_node.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/plugins/modules/aci_l3out_logical_node.py b/plugins/modules/aci_l3out_logical_node.py index dea5ace4d..d1d4970f1 100644 --- a/plugins/modules/aci_l3out_logical_node.py +++ b/plugins/modules/aci_l3out_logical_node.py @@ -276,8 +276,8 @@ def main(): aci = ACIModule(module) if loopback_address is not None: - child_classes = ["l3extLoopBackIfP"] - child_configs = [dict(l3extLoopBackIfP=dict(attributes=dict(name="", descr="", addr=loopback_address)))] + child_classes = ["l3extLoopBackIfP"] + child_configs = [dict(l3extLoopBackIfP=dict(attributes=dict(name="", descr="", addr=loopback_address)))] else: child_classes = [] child_configs = [] @@ -315,11 +315,7 @@ def main(): if state == "present": aci.payload( aci_class="l3extRsNodeL3OutAtt", - class_config=dict( - rtrId=router_id, - rtrIdLoopBack=router_id_as_loopback, - tDn=tdn - ), + class_config=dict(rtrId=router_id, rtrIdLoopBack=router_id_as_loopback, tDn=tdn), child_configs=child_configs, ) From 4c75301719c37301388a842a46bc328918efa361 Mon Sep 17 00:00:00 2001 From: Gaspard Micol Date: Wed, 13 Sep 2023 18:37:49 -0400 Subject: [PATCH 03/11] [ignore] modify conditions for loopback interface profile in aci_l3out_logical_node. --- plugins/modules/aci_l3out_logical_node.py | 18 +++++++++++------- .../aci_l3out_logical_node/tasks/main.yml | 14 +++++++++++--- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/plugins/modules/aci_l3out_logical_node.py b/plugins/modules/aci_l3out_logical_node.py index d1d4970f1..61114890b 100644 --- a/plugins/modules/aci_l3out_logical_node.py +++ b/plugins/modules/aci_l3out_logical_node.py @@ -51,7 +51,8 @@ default: 'yes' loopback_address: description: - - loopback IP of the loopback interface profile. + - Loopback IP. + - to delete the existing loopback IP, pass an empty string. state: description: - Use C(present) or C(absent) for adding or removing. @@ -246,7 +247,7 @@ def main(): node_id=dict(type="int"), router_id=dict(type="str"), router_id_as_loopback=dict(type="str", default="yes", choices=["yes", "no"]), - loopback_address = dict(type="str"), + loopback_address=dict(type="str"), state=dict(type="str", default="present", choices=["absent", "present", "query"]), ) @@ -275,12 +276,15 @@ def main(): aci = ACIModule(module) + child_classes = ["l3extLoopBackIfP"] + + child_configs = [] + if loopback_address is not None: - child_classes = ["l3extLoopBackIfP"] - child_configs = [dict(l3extLoopBackIfP=dict(attributes=dict(name="", descr="", addr=loopback_address)))] - else: - child_classes = [] - child_configs = [] + if loopback_address == "": + child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr="", status="deleted")))]) + else: + child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address)))]) aci.construct_url( root_class=dict( diff --git a/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml b/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml index e1bbe439d..cf32758d7 100644 --- a/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml +++ b/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml @@ -112,6 +112,12 @@ loopback_address: 11.11.11.12 register: add_loopback_ip + - name: Remove loopback address + aci_l3out_logical_node: &node_remove_loopback + <<: *node_add_loopback + loopback_address: '' + register: remove_loopback_ip + - name: Verify update_node assert: that: @@ -120,7 +126,9 @@ - update_node.sent.l3extRsNodeL3OutAtt.attributes.rtrId == '11.11.11.11' - add_loopback_ip is changed - add_loopback_ip.previous != [] - - add_loopback_ip.current.0.l3extRsNodeL3OutAtt.children.0.l3extLoopBackIfP.attributes.addr == "11.11.11.12" + - add_loopback_ip.current.0.l3extRsNodeL3OutAtt.children.0.l3extLoopBackIfP.attributes.addr == '11.11.11.12' + - remove_loopback_ip is changed + - remove_loopback_ip.previous != [] # ADD ANOTHER NODE - name: Add another node @@ -145,7 +153,7 @@ # QUERY A SPECIFIC NODE - name: Query a specific node aci_l3out_logical_node: - <<: *node_add_loopback + <<: *node_remove_loopback state: query register: query_spec_node @@ -158,7 +166,7 @@ # REMOVE NODE - name: Remove node aci_l3out_logical_node: - <<: *node_add_loopback + <<: *node_remove_loopback state: absent register: remove_node From d448b526b0910ee2c836add7be7eeff97bc6aac3 Mon Sep 17 00:00:00 2001 From: Gaspard Micol Date: Thu, 14 Sep 2023 00:43:45 -0400 Subject: [PATCH 04/11] [ignore] Add option to delete loopback interface profile in aci_l3out_logical_node. --- plugins/modules/aci_l3out_logical_node.py | 15 ++++++++++++--- .../targets/aci_l3out_logical_node/tasks/main.yml | 3 ++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/plugins/modules/aci_l3out_logical_node.py b/plugins/modules/aci_l3out_logical_node.py index 61114890b..4b31f3ce8 100644 --- a/plugins/modules/aci_l3out_logical_node.py +++ b/plugins/modules/aci_l3out_logical_node.py @@ -52,7 +52,14 @@ loopback_address: description: - Loopback IP. - - to delete the existing loopback IP, pass an empty string. + type: str + delete_loopback_address: + description: + - Option to delete the current loopback interface profile. + - the current loopback address needs to be provided in order to be deleted. + type: str + choices: [ 'yes', 'no' ] + default: 'no' state: description: - Use C(present) or C(absent) for adding or removing. @@ -248,6 +255,7 @@ def main(): router_id=dict(type="str"), router_id_as_loopback=dict(type="str", default="yes", choices=["yes", "no"]), loopback_address=dict(type="str"), + delete_loopback_address=dict(type="str", default="no", choices=["yes", "no"]), state=dict(type="str", default="present", choices=["absent", "present", "query"]), ) @@ -268,6 +276,7 @@ def main(): router_id = module.params.get("router_id") router_id_as_loopback = module.params.get("router_id_as_loopback") loopback_address = module.params.get("loopback_address") + delete_loopback_address = module.params.get("delete_loopback_address") state = module.params.get("state") tdn = None @@ -281,8 +290,8 @@ def main(): child_configs = [] if loopback_address is not None: - if loopback_address == "": - child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr="", status="deleted")))]) + if delete_loopback_address == "yes": + child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address, status="deleted")))]) else: child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address)))]) diff --git a/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml b/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml index cf32758d7..ddb2a0712 100644 --- a/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml +++ b/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml @@ -115,7 +115,8 @@ - name: Remove loopback address aci_l3out_logical_node: &node_remove_loopback <<: *node_add_loopback - loopback_address: '' + loopback_address: 11.11.11.12 + delete_loopback_address: "yes" register: remove_loopback_ip - name: Verify update_node From 704ab60cd8fff226c483c1d6109b5401463b52a3 Mon Sep 17 00:00:00 2001 From: Gaspard Micol Date: Thu, 14 Sep 2023 00:47:12 -0400 Subject: [PATCH 05/11] [ignore] Used Black to format python file (2nd iterration). --- plugins/modules/aci_l3out_logical_node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/aci_l3out_logical_node.py b/plugins/modules/aci_l3out_logical_node.py index 4b31f3ce8..8e6c0a45b 100644 --- a/plugins/modules/aci_l3out_logical_node.py +++ b/plugins/modules/aci_l3out_logical_node.py @@ -290,7 +290,7 @@ def main(): child_configs = [] if loopback_address is not None: - if delete_loopback_address == "yes": + if delete_loopback_address == "yes": child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address, status="deleted")))]) else: child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address)))]) From 416e3e20a3ddab00c0d32a7fdbb4ce6f0ec8c118 Mon Sep 17 00:00:00 2001 From: Gaspard Micol Date: Thu, 14 Sep 2023 16:13:53 -0400 Subject: [PATCH 06/11] [ignore] Modify conditions to delete loopback_address for aci_l3out_logical_node. --- plugins/modules/aci_l3out_logical_node.py | 25 ++++++++----------- .../aci_l3out_logical_node/tasks/main.yml | 3 +-- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/plugins/modules/aci_l3out_logical_node.py b/plugins/modules/aci_l3out_logical_node.py index 8e6c0a45b..01b07a557 100644 --- a/plugins/modules/aci_l3out_logical_node.py +++ b/plugins/modules/aci_l3out_logical_node.py @@ -52,14 +52,8 @@ loopback_address: description: - Loopback IP. + - to delete an existing loopback address, pass an empty string. type: str - delete_loopback_address: - description: - - Option to delete the current loopback interface profile. - - the current loopback address needs to be provided in order to be deleted. - type: str - choices: [ 'yes', 'no' ] - default: 'no' state: description: - Use C(present) or C(absent) for adding or removing. @@ -255,7 +249,6 @@ def main(): router_id=dict(type="str"), router_id_as_loopback=dict(type="str", default="yes", choices=["yes", "no"]), loopback_address=dict(type="str"), - delete_loopback_address=dict(type="str", default="no", choices=["yes", "no"]), state=dict(type="str", default="present", choices=["absent", "present", "query"]), ) @@ -276,7 +269,6 @@ def main(): router_id = module.params.get("router_id") router_id_as_loopback = module.params.get("router_id_as_loopback") loopback_address = module.params.get("loopback_address") - delete_loopback_address = module.params.get("delete_loopback_address") state = module.params.get("state") tdn = None @@ -289,12 +281,6 @@ def main(): child_configs = [] - if loopback_address is not None: - if delete_loopback_address == "yes": - child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address, status="deleted")))]) - else: - child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address)))]) - aci.construct_url( root_class=dict( aci_class="fvTenant", @@ -325,6 +311,15 @@ def main(): aci.get_existing() + if loopback_address is not None: + if loopback_address == "" and isinstance(aci.existing, list) and len(aci.existing) > 0: + for child in aci.existing[0].get("l3extRsNodeL3OutAtt", {}).get("children", {}): + if child.get("l3extLoopBackIfP"): + previous_loopback_address = child.get("l3extLoopBackIfP").get("attributes").get("addr") + child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=previous_loopback_address,status="deleted")))]) + elif loopback_address: + child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address)))]) + if state == "present": aci.payload( aci_class="l3extRsNodeL3OutAtt", diff --git a/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml b/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml index ddb2a0712..07279b617 100644 --- a/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml +++ b/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml @@ -115,8 +115,7 @@ - name: Remove loopback address aci_l3out_logical_node: &node_remove_loopback <<: *node_add_loopback - loopback_address: 11.11.11.12 - delete_loopback_address: "yes" + loopback_address: "" register: remove_loopback_ip - name: Verify update_node From 8ff48266d3127637c8b0a15afccdc7cbcb52c57a Mon Sep 17 00:00:00 2001 From: Gaspard Micol Date: Fri, 15 Sep 2023 14:24:58 -0400 Subject: [PATCH 07/11] [ignore] Small changes in deleting and creating conditions for loopback interface profile. --- plugins/modules/aci_l3out_logical_node.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/modules/aci_l3out_logical_node.py b/plugins/modules/aci_l3out_logical_node.py index 01b07a557..0115cbbd1 100644 --- a/plugins/modules/aci_l3out_logical_node.py +++ b/plugins/modules/aci_l3out_logical_node.py @@ -313,9 +313,10 @@ def main(): if loopback_address is not None: if loopback_address == "" and isinstance(aci.existing, list) and len(aci.existing) > 0: - for child in aci.existing[0].get("l3extRsNodeL3OutAtt", {}).get("children", {}): - if child.get("l3extLoopBackIfP"): - previous_loopback_address = child.get("l3extLoopBackIfP").get("attributes").get("addr") + for child in aci.existing[0].get("l3extRsNodeL3OutAtt", {}).get("children", []): + existing_loopback_interface_profile = child.get("l3extLoopBackIfP") + if existing_loopback_interface_profile: + previous_loopback_address = existing_loopback_interface_profile.get("attributes",{}).get("addr") child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=previous_loopback_address,status="deleted")))]) elif loopback_address: child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address)))]) From e4600919e84d37932498c8a8ec62c9b6749adead Mon Sep 17 00:00:00 2001 From: Gaspard Micol Date: Wed, 20 Sep 2023 09:45:40 -0400 Subject: [PATCH 08/11] [ignore] Modify remove condition for loopback address and test case for aci_l3out_logical_node. --- plugins/modules/aci_l3out_logical_node.py | 13 ++++++------- .../aci_l3out_logical_node/tasks/main.yml | 17 ++++++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/plugins/modules/aci_l3out_logical_node.py b/plugins/modules/aci_l3out_logical_node.py index 0115cbbd1..c95b9c94d 100644 --- a/plugins/modules/aci_l3out_logical_node.py +++ b/plugins/modules/aci_l3out_logical_node.py @@ -51,9 +51,10 @@ default: 'yes' loopback_address: description: - - Loopback IP. - - to delete an existing loopback address, pass an empty string. + - The loopback IP address. + - an empty string removes a configured loopback. type: str + aliases: [ loopback ] state: description: - Use C(present) or C(absent) for adding or removing. @@ -248,7 +249,7 @@ def main(): node_id=dict(type="int"), router_id=dict(type="str"), router_id_as_loopback=dict(type="str", default="yes", choices=["yes", "no"]), - loopback_address=dict(type="str"), + loopback_address=dict(type="str", aliases=["loopback"]), state=dict(type="str", default="present", choices=["absent", "present", "query"]), ) @@ -314,10 +315,8 @@ def main(): if loopback_address is not None: if loopback_address == "" and isinstance(aci.existing, list) and len(aci.existing) > 0: for child in aci.existing[0].get("l3extRsNodeL3OutAtt", {}).get("children", []): - existing_loopback_interface_profile = child.get("l3extLoopBackIfP") - if existing_loopback_interface_profile: - previous_loopback_address = existing_loopback_interface_profile.get("attributes",{}).get("addr") - child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=previous_loopback_address,status="deleted")))]) + previous_loopback_address = child.get("l3extLoopBackIfP", {}).get("attributes", {}).get("addr") + child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=previous_loopback_address,status="deleted")))]) elif loopback_address: child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address)))]) diff --git a/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml b/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml index 07279b617..35206a27b 100644 --- a/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml +++ b/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml @@ -16,7 +16,7 @@ validate_certs: '{{ aci_validate_certs | default(false) }}' use_ssl: '{{ aci_use_ssl | default(true) }}' use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: debug + output_level: '{{ aci_output_level | default("info") }}' # CLEAN ENVIRONMENT - name: Remove test tenant before we kickoff @@ -84,9 +84,9 @@ - cm_add_node is changed - nm_add_node is changed - cm_add_node.previous == nm_add_node.previous == [] - - cm_add_node.sent.l3extRsNodeL3OutAtt.attributes.rtrId == nm_add_node.sent.l3extRsNodeL3OutAtt.attributes.rtrId == '111.111.111.111' - - cm_add_node.sent.l3extRsNodeL3OutAtt.attributes.rtrIdLoopBack == nm_add_node.sent.l3extRsNodeL3OutAtt.attributes.rtrIdLoopBack == 'no' - - cm_add_node.sent.l3extRsNodeL3OutAtt.attributes.tDn == nm_add_node.sent.l3extRsNodeL3OutAtt.attributes.tDn == 'topology/pod-1/node-111' + - cm_add_node.sent.l3extRsNodeL3OutAtt.attributes.rtrId == nm_add_node.current.0.l3extRsNodeL3OutAtt.attributes.rtrId == '111.111.111.111' + - cm_add_node.sent.l3extRsNodeL3OutAtt.attributes.rtrIdLoopBack == nm_add_node.current.0.l3extRsNodeL3OutAtt.attributes.rtrIdLoopBack == 'no' + - cm_add_node.sent.l3extRsNodeL3OutAtt.attributes.tDn == nm_add_node.current.0.l3extRsNodeL3OutAtt.attributes.tDn == 'topology/pod-1/node-111' - nm_add_node.current.0.l3extRsNodeL3OutAtt.attributes.annotation == 'orchestrator:ansible' - name: Add node again, check if idempotency works @@ -123,7 +123,7 @@ that: - update_node is changed - update_node.previous != [] - - update_node.sent.l3extRsNodeL3OutAtt.attributes.rtrId == '11.11.11.11' + - update_node.current.0.l3extRsNodeL3OutAtt.attributes.rtrId == '11.11.11.11' - add_loopback_ip is changed - add_loopback_ip.previous != [] - add_loopback_ip.current.0.l3extRsNodeL3OutAtt.children.0.l3extLoopBackIfP.attributes.addr == '11.11.11.12' @@ -132,10 +132,11 @@ # ADD ANOTHER NODE - name: Add another node - aci_l3out_logical_node: + aci_l3out_logical_node: &second_node_present <<: *node_present node_id: 112 router_id: 12.12.12.12 + loopback_address: 12.12.12.13 # QUERY ALL NODES - name: Query all nodes @@ -153,7 +154,7 @@ # QUERY A SPECIFIC NODE - name: Query a specific node aci_l3out_logical_node: - <<: *node_remove_loopback + <<: *second_node_present state: query register: query_spec_node @@ -162,6 +163,8 @@ that: - query_spec_node is not changed - query_spec_node.current|length == 1 + - query_spec_node.current.0.l3extRsNodeL3OutAtt.attributes.rtrId == '12.12.12.12' + - query_spec_node.current.0.l3extRsNodeL3OutAtt.children.0.l3extLoopBackIfP.attributes.addr == '12.12.12.13' # REMOVE NODE - name: Remove node From d0bd4855d321ae847b48ce0eab0a28f5eb26400c Mon Sep 17 00:00:00 2001 From: Gaspard Micol Date: Wed, 20 Sep 2023 10:04:10 -0400 Subject: [PATCH 09/11] [ignore] Used Black to format python file (3rd iterration). --- plugins/modules/aci_l3out_logical_node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/aci_l3out_logical_node.py b/plugins/modules/aci_l3out_logical_node.py index c95b9c94d..5df33362f 100644 --- a/plugins/modules/aci_l3out_logical_node.py +++ b/plugins/modules/aci_l3out_logical_node.py @@ -316,7 +316,7 @@ def main(): if loopback_address == "" and isinstance(aci.existing, list) and len(aci.existing) > 0: for child in aci.existing[0].get("l3extRsNodeL3OutAtt", {}).get("children", []): previous_loopback_address = child.get("l3extLoopBackIfP", {}).get("attributes", {}).get("addr") - child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=previous_loopback_address,status="deleted")))]) + child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=previous_loopback_address, status="deleted")))]) elif loopback_address: child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address)))]) From cc180ef94a856a01e20e4c1710dd59c936cf0550 Mon Sep 17 00:00:00 2001 From: Gaspard Micol Date: Wed, 20 Sep 2023 13:14:17 -0400 Subject: [PATCH 10/11] [ignore] Modify documentations and deletion condition for loopback interface profile. --- plugins/modules/aci_l3out_logical_node.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/modules/aci_l3out_logical_node.py b/plugins/modules/aci_l3out_logical_node.py index 5df33362f..6b0ff14af 100644 --- a/plugins/modules/aci_l3out_logical_node.py +++ b/plugins/modules/aci_l3out_logical_node.py @@ -52,7 +52,7 @@ loopback_address: description: - The loopback IP address. - - an empty string removes a configured loopback. + - An empty string removes a configured loopback address. type: str aliases: [ loopback ] state: @@ -316,9 +316,9 @@ def main(): if loopback_address == "" and isinstance(aci.existing, list) and len(aci.existing) > 0: for child in aci.existing[0].get("l3extRsNodeL3OutAtt", {}).get("children", []): previous_loopback_address = child.get("l3extLoopBackIfP", {}).get("attributes", {}).get("addr") - child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=previous_loopback_address, status="deleted")))]) + child_configs.append(dict(l3extLoopBackIfP=dict(attributes=dict(addr=previous_loopback_address, status="deleted")))) elif loopback_address: - child_configs.extend([dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address)))]) + child_configs.append(dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address)))) if state == "present": aci.payload( From 5301ceccca93f005372b3283a71eeeb3385f27b7 Mon Sep 17 00:00:00 2001 From: Gaspard Micol Date: Thu, 21 Sep 2023 14:01:03 -0400 Subject: [PATCH 11/11] [ignore] add example to documentation for aci_l3out_logical_node. --- plugins/modules/aci_l3out_logical_node.py | 32 ++++++++++++----- .../aci_l3out_logical_node/tasks/main.yml | 34 +++++++++---------- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/plugins/modules/aci_l3out_logical_node.py b/plugins/modules/aci_l3out_logical_node.py index 6b0ff14af..33c8a22a5 100644 --- a/plugins/modules/aci_l3out_logical_node.py +++ b/plugins/modules/aci_l3out_logical_node.py @@ -52,7 +52,7 @@ loopback_address: description: - The loopback IP address. - - An empty string removes a configured loopback address. + - A configured loopback address can be removed by passing an empty string (see Examples). type: str aliases: [ loopback ] state: @@ -88,9 +88,23 @@ pod_id: 1 node_id: 111 router_id: 111.111.111.111 + loopback_address: 111.111.111.112 state: present delegate_to: localhost +- name: Remove a loopback address from a node in node profile + cisco.aci.aci_l3out_logical_node: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + pod_id: 1 + node_id: 111 + loopback_address: "" + delegate_to: localhost + - name: Delete a node from a node profile cisco.aci.aci_l3out_logical_node: host: apic @@ -312,15 +326,15 @@ def main(): aci.get_existing() - if loopback_address is not None: - if loopback_address == "" and isinstance(aci.existing, list) and len(aci.existing) > 0: - for child in aci.existing[0].get("l3extRsNodeL3OutAtt", {}).get("children", []): - previous_loopback_address = child.get("l3extLoopBackIfP", {}).get("attributes", {}).get("addr") - child_configs.append(dict(l3extLoopBackIfP=dict(attributes=dict(addr=previous_loopback_address, status="deleted")))) - elif loopback_address: - child_configs.append(dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address)))) - if state == "present": + if loopback_address is not None: + if loopback_address == "" and isinstance(aci.existing, list) and len(aci.existing) > 0: + for child in aci.existing[0].get("l3extRsNodeL3OutAtt", {}).get("children", []): + previous_loopback_address = child.get("l3extLoopBackIfP", {}).get("attributes", {}).get("addr") + child_configs.append(dict(l3extLoopBackIfP=dict(attributes=dict(addr=previous_loopback_address, status="deleted")))) + elif loopback_address: + child_configs.append(dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address)))) + aci.payload( aci_class="l3extRsNodeL3OutAtt", class_config=dict(rtrId=router_id, rtrIdLoopBack=router_id_as_loopback, tDn=tdn), diff --git a/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml b/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml index 35206a27b..1d61ee3e3 100644 --- a/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml +++ b/tests/integration/targets/aci_l3out_logical_node/tasks/main.yml @@ -20,7 +20,7 @@ # CLEAN ENVIRONMENT - name: Remove test tenant before we kickoff - aci_tenant: &tenant_absent + cisco.aci.aci_tenant: &tenant_absent <<: *aci_info tenant: ansible_test state: absent @@ -33,38 +33,38 @@ block: # block specifies execution of tasks within, based on conditions # SETUP ENVIRONMENT - name: Create domain - aci_domain: &domain_present + cisco.aci.aci_domain: &domain_present <<: *aci_info domain: l3outtest domain_type: l3dom state: present - name: Create tenant - aci_tenant: &tenant_present + cisco.aci.aci_tenant: &tenant_present <<: *tenant_absent state: present - name: Configure VRF - aci_vrf: &vrf_present + cisco.aci.aci_vrf: &vrf_present <<: *tenant_present vrf: l3outtest - name: Create L3Out - aci_l3out: + cisco.aci.aci_l3out: <<: *vrf_present l3out: l3outtest domain: l3outtest route_control: export - name: Crete node profile - aci_l3out_logical_node_profile: &np_present + cisco.aci.aci_l3out_logical_node_profile: &np_present <<: *tenant_present l3out: l3outtest node_profile: NODES # BEGIN WITH TESTS - name: Add node (check_mode) - aci_l3out_logical_node: &node_present + cisco.aci.aci_l3out_logical_node: &node_present <<: *np_present pod_id: 1 node_id: 111 @@ -74,7 +74,7 @@ register: cm_add_node - name: Add node (normal mode) - aci_l3out_logical_node: + cisco.aci.aci_l3out_logical_node: <<: *node_present register: nm_add_node @@ -90,7 +90,7 @@ - nm_add_node.current.0.l3extRsNodeL3OutAtt.attributes.annotation == 'orchestrator:ansible' - name: Add node again, check if idempotency works - aci_l3out_logical_node: + cisco.aci.aci_l3out_logical_node: <<: *node_present register: add_node_again @@ -101,19 +101,19 @@ # UPDATE NODE - name: Change roouter id - aci_l3out_logical_node: &node_update + cisco.aci.aci_l3out_logical_node: &node_update <<: *node_present router_id: 11.11.11.11 register: update_node - name: Add loopback address - aci_l3out_logical_node: &node_add_loopback + cisco.aci.aci_l3out_logical_node: &node_add_loopback <<: *node_update loopback_address: 11.11.11.12 register: add_loopback_ip - name: Remove loopback address - aci_l3out_logical_node: &node_remove_loopback + cisco.aci.aci_l3out_logical_node: &node_remove_loopback <<: *node_add_loopback loopback_address: "" register: remove_loopback_ip @@ -132,7 +132,7 @@ # ADD ANOTHER NODE - name: Add another node - aci_l3out_logical_node: &second_node_present + cisco.aci.aci_l3out_logical_node: &second_node_present <<: *node_present node_id: 112 router_id: 12.12.12.12 @@ -140,7 +140,7 @@ # QUERY ALL NODES - name: Query all nodes - aci_l3out_logical_node: + cisco.aci.aci_l3out_logical_node: <<: *aci_info state: query register: query_all_nodes @@ -153,7 +153,7 @@ # QUERY A SPECIFIC NODE - name: Query a specific node - aci_l3out_logical_node: + cisco.aci.aci_l3out_logical_node: <<: *second_node_present state: query register: query_spec_node @@ -168,7 +168,7 @@ # REMOVE NODE - name: Remove node - aci_l3out_logical_node: + cisco.aci.aci_l3out_logical_node: <<: *node_remove_loopback state: absent register: remove_node @@ -180,7 +180,7 @@ - remove_node.current == [] - name: Remove test tenant - clean-up the environment - aci_tenant: + cisco.aci.aci_tenant: <<: *aci_info tenant: ansible_test state: absent \ No newline at end of file