Skip to content

Addition of a new module for enhanced_lag_policy (DCNE-422) #768

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions plugins/module_utils/aci.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,9 @@ def aci_owner_spec():
)


def enhanced_lag_spec():
def enhanced_lag_spec(name_is_required=True):
return dict(
name=dict(type="str", required=True),
name=dict(type="str", required=name_is_required),
lacp_mode=dict(type="str", choices=["active", "passive"]),
load_balancing_mode=dict(
type="str",
Expand Down
340 changes: 340 additions & 0 deletions plugins/modules/aci_vmm_enhanced_lag_policy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,340 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright: (c) 2025, Dev Sinha (@DevSinha13) <devsinh@cisco.com>
# 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": "community"}

DOCUMENTATION = r"""
---
module: aci_vmm_enhanced_lag_policy
short_description: Manage Enhanced LACP Policy for Virtual Machine Manager (VMM) in Cisco ACI
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other modules I think we include the classname to the short description (lacp:EnhancedLagPol) at the end. If not mistaken this was done for search-ability of classes in documentation

description:
- Manage Enhanced LACP Policy (lacpEnhancedLagPol) for VMM domains on Cisco ACI fabrics.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't think we put class names in the descriptions

- The Enhanced LACP Policy allows you to configure advanced Link Aggregation Control Protocol (LACP) settings for virtual switches in VMM domains.
- This policy is a child of the C(vmmVSwitchPolicyCont) class.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is children something we decided to add to the descriptions?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand the thumbs up here? Has this been decided?


options:
name:
description:
- The name of the Enhanced LACP Policy.
type: str
domain:
description:
- The name of the virtual domain profile where the Enhanced LACP Policy is applied.
type: str
aliases: [ domain_name, domain_profile ]
vm_provider:
description:
- The virtualization platform provider for the VMM domain.
type: str
choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ]
lacp_mode:
description:
- The LACP mode for the policy.
- Determines whether the policy initiates or responds to LACP negotiations.
type: str
choices: [ active, passive ]
load_balancing_mode:
description:
- The load balancing algorithm for distributing traffic across links in the port channel.
- See the APIC Management Information Model reference for more details.
type: str
choices:
- dst-ip
- dst-ip-l4port
- dst-ip-vlan
- dst-ip-l4port-vlan
- dst-mac
- dst-l4port
- src-ip
- src-ip-l4port
- src-ip-vlan
- src-ip-l4port-vlan
- src-mac
- src-l4port
- src-dst-ip
- src-dst-ip-l4port
- src-dst-ip-vlan
- src-dst-ip-l4port-vlan
- src-dst-mac
- src-dst-l4port
- src-port-id
- vlan
number_uplinks:
description:
- The minimum number of uplinks required for the port channel.
- Must be a value between 2 and 8.
type: int
state:
description:
- The desired state of the Enhanced LACP Policy.
- Use C(present) to create or update the policy.
- Use C(absent) to delete the policy.
- Use C(query) to retrieve information about the policy.
type: str
choices: [ absent, present, query ]
default: present
extends_documentation_fragment:
- cisco.aci.aci
- cisco.aci.annotation
- cisco.aci.owner

seealso:
- module: cisco.aci.aci_domain
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- module: cisco.aci.aci_domain
- module: cisco.aci.aci_domain
- module: cisco.aci. aci_vmm_vswitch_policy

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about that, I have made the fix

- name: APIC Management Information Model reference
description: More information about the internal APIC classes B(lacp:EnhancedLagPol).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dev Sinha (@DevSinha13)
"""

EXAMPLES = r"""
- name: Create an Enhanced LACP Policy
cisco.aci.aci_vmm_enhanced_lag_policy:
host: apic.example.com
username: admin
password: SomeSecretPassword
name: my_enhanced_lag_policy
domain: my_vmm_domain
vm_provider: vmware
lacp_mode: active
load_balancing_mode: src-dst-ip
number_uplinks: 4
state: present

- name: Simulate creation of an Enhanced LACP Policy (Check Mode)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont think we include this type of example in other modules

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand the thumbs up here? Has this been decided to include?

cisco.aci.aci_vmm_enhanced_lag_policy:
host: apic.example.com
username: admin
password: SomeSecretPassword
name: my_enhanced_lag_policy
domain: my_vmm_domain
vm_provider: vmware
lacp_mode: active
load_balancing_mode: src-dst-ip
number_uplinks: 4
state: present
check_mode: true

- name: Update an existing Enhanced LACP Policy
cisco.aci.aci_vmm_enhanced_lag_policy:
host: apic.example.com
username: admin
password: SomeSecretPassword
name: my_enhanced_lag_policy
domain: my_vmm_domain
vm_provider: vmware
lacp_mode: passive
load_balancing_mode: src-dst-ip-l4port
number_uplinks: 6
state: present

- name: Query a specific Enhanced LACP Policy
cisco.aci.aci_vmm_enhanced_lag_policy:
host: apic.example.com
username: admin
password: SomeSecretPassword
name: my_enhanced_lag_policy
domain: my_vmm_domain
vm_provider: vmware
state: query
register: query_result

- name: Query all Enhanced LACP Policies in a VMM domain
cisco.aci.aci_vmm_enhanced_lag_policy:
host: apic.example.com
username: admin
password: SomeSecretPassword
domain: my_vmm_domain
vm_provider: vmware
state: query
register: query_all_result

- name: Ensure idempotency when creating an Enhanced LACP Policy
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont think we include this type of example in other modules

cisco.aci.aci_vmm_enhanced_lag_policy:
host: apic.example.com
username: admin
password: SomeSecretPassword
name: my_enhanced_lag_policy
domain: my_vmm_domain
vm_provider: vmware
lacp_mode: active
load_balancing_mode: src-dst-ip
number_uplinks: 4
state: present

- name: Delete an Enhanced LACP Policy
cisco.aci.aci_vmm_enhanced_lag_policy:
host: apic.example.com
username: admin
password: SomeSecretPassword
name: my_enhanced_lag_policy
domain: my_vmm_domain
vm_provider: vmware
state: absent

- name: Simulate deletion of an Enhanced LACP Policy (Check Mode)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont think we include this type of example in other modules

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted, I have deleted that example. Thank you for the clarification.

cisco.aci.aci_vmm_enhanced_lag_policy:
host: apic.example.com
username: admin
password: SomeSecretPassword
name: my_enhanced_lag_policy
domain: my_vmm_domain
vm_provider: vmware
state: absent
check_mode: true
"""
RETURN = r"""
current:
description: The existing configuration of the Enhanced LACP Policy from the APIC after the module has finished.
returned: success
type: list
sample:
[
{
"lacpEnhancedLagPol": {
"attributes": {
"name": "test_enhanced_lag_policy",
"mode": "active",
"lbmode": "src-dst-ip",
"numLinks": "4",
"dn": "uni/vmmp-VMware/dom-test_vmm_dom/vswitchpolcont/enlacplagp-test_enhanced_lag_policy"
}
}
}
]
error:
description: The error information as returned from the APIC.
returned: failure
type: dict
sample:
{
"code": "801",
"text": "property name of enlacplagp-test_enhanced_lag_policy failed validation"
}
proposed:
description: The configuration sent to the APIC.
returned: info
type: dict
sample:
{
"lacpEnhancedLagPol": {
"attributes": {
"name": "test_enhanced_lag_policy",
"mode": "active",
"lbmode": "src-dst-ip",
"numLinks": "4"
}
}
}
"""

from ansible.module_utils.basic import AnsibleModule
from ansible_collections.cisco.aci.plugins.module_utils.aci import (
ACIModule,
aci_argument_spec,
enhanced_lag_spec,
)
from ansible_collections.cisco.aci.plugins.module_utils.aci import (
aci_annotation_spec,
aci_owner_spec,
)

VM_PROVIDER_MAPPING = dict(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can import and use the VM_PROVIDER_MAPPING defined in module_utils/constants.py

cloudfoundry="CloudFoundry",
kubernetes="Kubernetes",
microsoft="Microsoft",
openshift="OpenShift",
openstack="OpenStack",
redhat="Redhat",
vmware="VMware",
)


def main():
argument_spec = aci_argument_spec()
argument_spec.update(aci_annotation_spec())
argument_spec.update(aci_owner_spec())
argument_spec.update(enhanced_lag_spec(name_is_required=False))
argument_spec.update(
domain=dict(type="str", aliases=["domain_name", "domain_profile"]),
state=dict(type="str", default="present", choices=["absent", "present", "query"]),
vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING.keys())),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't think the keys() is needed and list function can be called directly on the MAP

Suggested change
vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING.keys())),
vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING)),

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, removed the .keys() function and maintained functionality across all tests. Thanks for the feedback.

)

module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
["state", "absent", ["name", "domain", "vm_provider"]],
["state", "present", ["name", "domain", "vm_provider"]],
],
)

name = module.params.get("name")
lacp_mode = module.params.get("lacp_mode")
load_balancing_mode = module.params.get("load_balancing_mode")
number_uplinks = module.params.get("number_uplinks")
domain = module.params.get("domain")
state = module.params.get("state")
vm_provider = module.params.get("vm_provider")

aci = ACIModule(module)

aci.construct_url(
root_class=dict(
aci_class="vmmProvP",
aci_rn="vmmp-{0}".format(VM_PROVIDER_MAPPING.get(vm_provider)),
module_object=vm_provider,
target_filter={"name": vm_provider},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think vmmProvP idtenifier isvendor

Suggested change
target_filter={"name": vm_provider},
target_filter={"vendor": vm_provider},

),
subclass_1=dict(
aci_class="vmmDomP",
aci_rn="dom-{0}".format(domain),
module_object=domain,
target_filter={"name": domain},
),
subclass_2=dict(
aci_class="vmmVSwitchPolicyCont",
aci_rn="vswitchpolcont",
module_object="vswitchpolcont",
target_filter={"name": "vswitchpolcont"},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to define an target_filter? this class has no identifiers, so would not be able to filter on it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite know how I should identify if this is required or not, would love to discuss it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would start by testing the behaviour with and without for both module_object and target_filter.

The target_filter is referencing a property now that exist but is not configurable according to the model, so is it always vswitchpolcont?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

had a quick look and from what I read in code if module_object is defined that should be enough, target_filter is not used at all in the logic as far as I can tell so can be excluded, since it only uses the filter of the object defined in subclass_3. See _construct_url_4) function in aci.py

),
subclass_3=dict(
aci_class="lacpEnhancedLagPol",
aci_rn="enlacplagp-{0}".format(name),
module_object=name,
target_filter={"name": name},
),
)

aci.get_existing()

if state == "present":
aci.payload(
aci_class="lacpEnhancedLagPol",
class_config=dict(
name=name,
mode=lacp_mode,
lbmode=load_balancing_mode,
numLinks=number_uplinks,
),
)

aci.get_diff(aci_class="lacpEnhancedLagPol")

aci.post_config()

elif state == "absent":
aci.delete_config()

aci.exit_json()


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# No ACI simulator yet, so not enabled
# unsupported
Loading