Skip to content

L3out module#276

Draft
skaszlik wants to merge 4 commits into
CiscoDevNet:developfrom
skaszlik:l3out_module
Draft

L3out module#276
skaszlik wants to merge 4 commits into
CiscoDevNet:developfrom
skaszlik:l3out_module

Conversation

@skaszlik
Copy link
Copy Markdown

@skaszlik skaszlik commented May 12, 2026

Related Issue(s)

#235

Proposed Changes

Example playbooks:

  - name: nd_l3out module examples
  hosts: nd
  gather_facts: false
  vars:
    fabric_name: "{{ fabric_name | default('my-fabric') }}"
  tasks:
    ##############################################
    ##  Example 1: Create L3Out (merged)        ##
    ##############################################
    - name: "Create L3Out with BGP routing (subInterface)"
      cisco.nd.nd_l3out:
        fabric: "{{ fabric_name }}"
        state: merged
        config:
          - name: example-l3out-bgp
            fabric1_name: DC1-Fabric
            fabric2_name: External-Fabric
            vrf1_name: production
            vrf2_name: external
            configured_fabrics: both
            ip_version: ipv4
            connectivity_details:
              routing_interface_type: subInterface
              links:
                - mtu: 9216
                  ipv4_mask_length: 30
                  dot1q_id: 100
                  switch1_details:
                    switch_id: FDO12345678
                    interface_name: Ethernet1/2.100
                    ipv4_address: 192.168.100.1
                    interface_description: "Link to external - fabric1"
                  switch2_details:
                    switch_id: FDO87654321
                    interface_name: Ethernet1/2.100
                    ipv4_address: 192.168.100.2
                    interface_description: "Link from DC1 - fabric2"
            routing_details:
              routing_protocol: bgp
              bfd: true
              fabric1_details:
                local_asn: "65001"
                advertise_default_route: true
                ipv4_peering_details:
                  ipv4_route_map_in: RM-BGP-IN
                  ipv4_route_map_out: RM-BGP-OUT
              fabric2_details:
                local_asn: "65002"
                ipv4_peering_details:
                  ipv4_route_map_in: RM-EXT-IN
      register: create_result
    - name: "Verify L3Out creation"
      ansible.builtin.assert:
        that:
          - create_result is changed
          - create_result.after | selectattr('name', 'equalto', 'example-l3out-bgp') | list | length == 1
    - name: "Display created L3Out"
      ansible.builtin.debug:
        msg: "Created L3Out: {{ create_result.after | selectattr('name', 'equalto', 'example-l3out-bgp') | first }}"
    ##############################################
    ##  Example 2: Create with static routing   ##
    ##############################################
    - name: "Create L3Out with static routing"
      cisco.nd.nd_l3out:
        fabric: "{{ fabric_name }}"
        state: merged
        config:
          - name: example-l3out-static
            fabric1_name: DC1-Fabric
            fabric2_name: External-Fabric
            vrf1_name: production
            vrf2_name: external
            configured_fabrics: fabric1
            ip_version: ipv4
            connectivity_details:
              routing_interface_type: subInterface
              links:
                - mtu: 1500
                  ipv4_mask_length: 24
                  dot1q_id: 200
                  switch1_details:
                    switch_id: FDO12345678
                    interface_name: Ethernet1/3.200
                    ipv4_address: 10.0.0.1
                  switch2_details:
                    switch_id: FDO87654321
                    interface_name: Ethernet1/3.200
                    ipv4_address: 10.0.0.2
            routing_details:
              routing_protocol: static
              fabric1_static_routes:
                - ip_version: ipv4
                  ip_prefix: 0.0.0.0/0
                  next_hop: 10.0.0.254
                  switch_ids:
                    - FDO12345678
                  route_preference: 1
                  tag: 12345
      register: static_result
    ##############################################
    ##  Example 3: Idempotency check            ##
    ##############################################
    - name: "Re-apply same config (idempotent - no change expected)"
      cisco.nd.nd_l3out:
        fabric: "{{ fabric_name }}"
        state: merged
        config:
          - name: example-l3out-static
            fabric1_name: DC1-Fabric
            fabric2_name: External-Fabric
            vrf1_name: production
            vrf2_name: external
            configured_fabrics: fabric1
            ip_version: ipv4
            connectivity_details:
              routing_interface_type: subInterface
              links:
                - mtu: 1500
                  ipv4_mask_length: 24
                  dot1q_id: 200
                  switch1_details:
                    switch_id: FDO12345678
                    interface_name: Ethernet1/3.200
                    ipv4_address: 10.0.0.1
                  switch2_details:
                    switch_id: FDO87654321
                    interface_name: Ethernet1/3.200
                    ipv4_address: 10.0.0.2
            routing_details:
              routing_protocol: static
              fabric1_static_routes:
                - ip_version: ipv4
                  ip_prefix: 0.0.0.0/0
                  next_hop: 10.0.0.254
                  switch_ids:
                    - FDO12345678
                  route_preference: 1
                  tag: 12345
      register: idem_result
    - name: "Verify idempotency"
      ansible.builtin.assert:
        that:
          - idem_result is not changed
    ##############################################
    ##  Example 4: Replace L3Out completely     ##
    ##############################################
    - name: "Replace L3Out with new configuration"
      cisco.nd.nd_l3out:
        fabric: "{{ fabric_name }}"
        state: replaced
        config:
          - name: example-l3out-static
            fabric1_name: DC1-Fabric
            fabric2_name: External-Fabric
            vrf1_name: new-vrf
            vrf2_name: external
            configured_fabrics: fabric1
            ip_version: both
            connectivity_details:
              routing_interface_type: subInterface
              links:
                - mtu: 9216
                  ipv4_mask_length: 30
                  ipv6_prefix_length: 64
                  dot1q_id: 201
                  switch1_details:
                    switch_id: FDO12345678
                    interface_name: Ethernet1/3.201
                    ipv4_address: 172.16.0.1
                    ipv6_address: "2001:db8::1"
                  switch2_details:
                    switch_id: FDO87654321
                    interface_name: Ethernet1/3.201
                    ipv4_address: 172.16.0.2
                    ipv6_address: "2001:db8::2"
            routing_details:
              routing_protocol: bgp
              fabric1_details:
                local_asn: "65001"
                ipv4_peering_details:
                  ipv4_route_map_in: RM-NEW-IN
                ipv6_peering_details:
                  ipv6_route_map_in: RM-V6-IN
      register: replace_result
    - name: "Verify replacement"
      vars:
        l3out: "{{ replace_result.after | selectattr('name', 'equalto', 'example-l3out-static') | first }}"
      ansible.builtin.assert:
        that:
          - replace_result is changed
          - l3out.ip_version == "both"
          - l3out.routing_details.routing_protocol == "bgp"
    ##############################################
    ##  Example 5: Create and attach (deploy)   ##
    ##############################################
    - name: "Create L3Out and attach to fabrics"
      cisco.nd.nd_l3out:
        fabric: "{{ fabric_name }}"
        state: merged
        config:
          - name: example-l3out-attached
            attach: true
            fabric1_name: DC1-Fabric
            fabric2_name: External-Fabric
            vrf1_name: production
            vrf2_name: external
            configured_fabrics: both
            ip_version: ipv4
            connectivity_details:
              routing_interface_type: subInterface
              links:
                - mtu: 9216
                  ipv4_mask_length: 30
                  dot1q_id: 300
                  switch1_details:
                    switch_id: FDO12345678
                    interface_name: Ethernet1/4.300
                    ipv4_address: 10.1.0.1
                  switch2_details:
                    switch_id: FDO87654321
                    interface_name: Ethernet1/4.300
                    ipv4_address: 10.1.0.2
            routing_details:
              routing_protocol: bgp
              fabric1_details:
                local_asn: "65001"
                ipv4_peering_details:
                  ipv4_route_map_in: RM-PROD-IN
      register: attach_result
    - name: "Verify creation and attachment"
      ansible.builtin.assert:
        that:
          - attach_result is changed
          - attach_result.after | selectattr('name', 'equalto', 'example-l3out-attached') | list | length == 1
    ##############################################
    ##  Example 6: Delete specific L3Outs       ##
    ##############################################
    - name: "Delete specific L3Outs by name"
      cisco.nd.nd_l3out:
        fabric: "{{ fabric_name }}"
        state: deleted
        config:
          - name: example-l3out-bgp
          - name: example-l3out-static
          - name: example-l3out-attached
      register: delete_result
    - name: "Verify deletion"
      ansible.builtin.assert:
        that:
          - delete_result is changed
          - delete_result.after | selectattr('name', 'match', '^example-l3out-') | list | length == 0
    - name: "Display final state"
      ansible.builtin.debug:
        msg: "All example L3Outs removed. {{ delete_result.after | length }} L3Outs remaining in fabric."

Test Notes

Cisco Nexus Dashboard Version

Related ND API Resource Category

  • analyze
  • infa
  • manage
  • onemanage
  • other

Checklist

  • Latest commit is rebased from develop with merge conflicts resolved
  • New or updates to documentation has been made accordingly
  • Assigned the proper reviewers

@mtarking
Copy link
Copy Markdown
Collaborator

This contains both ACL and L3Out. Please limit to one module and its subsequent imports.

- Implement comprehensive test cases for L3Out creation, update, replace, and deletion.
- Ensure compatibility with ND version 4.1 or later.
- Validate idempotency for L3Out operations.
- Include assertions to verify expected outcomes after each operation.
- Clean up test L3Outs after execution to maintain a clean test environment.
@skaszlik
Copy link
Copy Markdown
Author

This contains both ACL and L3Out. Please limit to one module and its subsequent imports.

Done. The PR contains now the L3Out only

@skaszlik
Copy link
Copy Markdown
Author

To be able to create L3Out, links have to be ready, otherwise the ND will return:

{
    "results": [
        {
            "message": "No Links exist between the given fabrics for this type. Please create links with ext_l3_dci_link template between the fabrics.",
            "name": "test-l3out-routed-bgp",
            "status": "failed"
        }
    ]
}

skaszlik added 3 commits May 19, 2026 19:51
…ptions

- Introduced 'overridden' state to enforce configuration as the single source of truth, deleting any existing L3Outs not in the configuration.
- Removed 'gathered' state option and updated documentation accordingly.
- Improved descriptions for various parameters to enhance clarity.
- Added support for static routes for both fabric1 and fabric2 under routing_details.
- Updated example playbooks to reflect new configurations and best practices.
- Refactored code for better readability and maintainability, including error handling improvements.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants